forked from OctaForge/libostd
move directory range structural details into implementation
This commit is contained in:
parent
466b80b96b
commit
256a35697a
90
ostd/path.hh
90
ostd/path.hh
|
@ -1759,54 +1759,6 @@ private:
|
|||
file_mode p_type{};
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct OSTD_EXPORT dir_range_impl {
|
||||
void open(path const &p);
|
||||
void close() noexcept;
|
||||
void read_next();
|
||||
|
||||
bool empty() const noexcept {
|
||||
return p_current.path().empty();
|
||||
}
|
||||
|
||||
directory_entry const &front() const noexcept {
|
||||
return p_current;
|
||||
}
|
||||
|
||||
~dir_range_impl() {
|
||||
close();
|
||||
}
|
||||
|
||||
directory_entry p_current{};
|
||||
path p_dir{};
|
||||
void *p_handle = nullptr;
|
||||
};
|
||||
|
||||
struct OSTD_EXPORT rdir_range_impl {
|
||||
using hstack = std::stack<void *, std::list<void *>>;
|
||||
|
||||
void open(path const &p);
|
||||
void close() noexcept;
|
||||
void read_next();
|
||||
|
||||
bool empty() const noexcept {
|
||||
return p_current.path().empty();
|
||||
}
|
||||
|
||||
directory_entry const &front() const noexcept {
|
||||
return p_current;
|
||||
}
|
||||
|
||||
~rdir_range_impl() {
|
||||
close();
|
||||
}
|
||||
|
||||
directory_entry p_current{};
|
||||
path p_dir{};
|
||||
hstack p_handles{};
|
||||
};
|
||||
}
|
||||
|
||||
/** @brief A simple range for traversal of a directory.
|
||||
*
|
||||
* The range is an ostd::input_range_path, so it is only suitable for
|
||||
|
@ -1821,7 +1773,7 @@ namespace detail {
|
|||
* also not defined whether entries added to the directory during
|
||||
* iteration will be represented in the range.
|
||||
**/
|
||||
struct directory_range: input_range<directory_range> {
|
||||
struct OSTD_EXPORT directory_range: input_range<directory_range> {
|
||||
using range_category = input_range_tag;
|
||||
using value_type = directory_entry;
|
||||
using reference = directory_entry const &;
|
||||
|
@ -1835,16 +1787,10 @@ struct directory_range: input_range<directory_range> {
|
|||
*
|
||||
* @throws fs::fs_error
|
||||
*/
|
||||
directory_range(path const &p):
|
||||
p_impl{std::make_shared<detail::dir_range_impl>()}
|
||||
{
|
||||
p_impl->open(p);
|
||||
}
|
||||
directory_range(path const &p);
|
||||
|
||||
/** @brief Checks if there are any entries in the range. */
|
||||
bool empty() const noexcept {
|
||||
return p_impl->empty();
|
||||
}
|
||||
bool empty() const noexcept;
|
||||
|
||||
/** @brief Pops out the current entry and retrieves the next one.
|
||||
*
|
||||
|
@ -1852,14 +1798,10 @@ struct directory_range: input_range<directory_range> {
|
|||
*
|
||||
* @throws fs::fs_error
|
||||
*/
|
||||
void pop_front() {
|
||||
p_impl->read_next();
|
||||
}
|
||||
void pop_front();
|
||||
|
||||
/** @brief Retrieves the current entry. */
|
||||
reference front() const noexcept {
|
||||
return p_impl->front();
|
||||
}
|
||||
reference front() const noexcept;
|
||||
|
||||
private:
|
||||
std::shared_ptr<detail::dir_range_impl> p_impl;
|
||||
|
@ -1872,7 +1814,9 @@ private:
|
|||
* a directory is still undefined, but the range does guarantee that if
|
||||
* th entry is a directory, it will be listed before its contents.
|
||||
*/
|
||||
struct recursive_directory_range: input_range<recursive_directory_range> {
|
||||
struct OSTD_EXPORT recursive_directory_range:
|
||||
input_range<recursive_directory_range>
|
||||
{
|
||||
using range_category = input_range_tag;
|
||||
using value_type = directory_entry;
|
||||
using reference = directory_entry const &;
|
||||
|
@ -1886,16 +1830,10 @@ struct recursive_directory_range: input_range<recursive_directory_range> {
|
|||
*
|
||||
* @throws fs::fs_error
|
||||
*/
|
||||
recursive_directory_range(path const &p):
|
||||
p_impl{std::make_shared<detail::rdir_range_impl>()}
|
||||
{
|
||||
p_impl->open(p);
|
||||
}
|
||||
recursive_directory_range(path const &p);
|
||||
|
||||
/** @brief Checks if there are any entries in the range. */
|
||||
bool empty() const noexcept {
|
||||
return p_impl->empty();
|
||||
}
|
||||
bool empty() const noexcept;
|
||||
|
||||
/** @brief Pops out the current entry and retrieves the next one.
|
||||
*
|
||||
|
@ -1903,14 +1841,10 @@ struct recursive_directory_range: input_range<recursive_directory_range> {
|
|||
*
|
||||
* @throws fs::fs_error
|
||||
*/
|
||||
void pop_front() {
|
||||
p_impl->read_next();
|
||||
}
|
||||
void pop_front();
|
||||
|
||||
/** @brief Retrieves the current entry. */
|
||||
reference front() const noexcept {
|
||||
return p_impl->front();
|
||||
}
|
||||
reference front() const noexcept;
|
||||
|
||||
private:
|
||||
std::shared_ptr<detail::rdir_range_impl> p_impl;
|
||||
|
|
10
src/path.cc
10
src/path.cc
|
@ -7,12 +7,14 @@
|
|||
|
||||
#include "ostd/platform.hh"
|
||||
|
||||
#if defined(OSTD_PLATFORM_WIN32)
|
||||
# include "src/win32/path.cc"
|
||||
#elif defined(OSTD_PLATFORM_POSIX)
|
||||
/* we don't have a native implementation for Windows right now, but a
|
||||
* platform independent generic fallback is available, depending on the
|
||||
* native C++ std::filesystem module
|
||||
*/
|
||||
#if defined(OSTD_PLATFORM_POSIX)
|
||||
# include "src/posix/path.cc"
|
||||
#else
|
||||
# error "Unsupported platform"
|
||||
# include "src/any/path.cc"
|
||||
#endif
|
||||
|
||||
namespace ostd {
|
||||
|
|
|
@ -200,87 +200,121 @@ static void dir_read_next(
|
|||
}
|
||||
}
|
||||
|
||||
/* dir range */
|
||||
|
||||
OSTD_EXPORT void dir_range_impl::open(path const &p) {
|
||||
DIR *d = opendir(p.string().data());
|
||||
if (!d) {
|
||||
throw fs_error{"opendir failure", p, errno_ec()};
|
||||
}
|
||||
p_dir = p;
|
||||
p_handle = d;
|
||||
read_next();
|
||||
}
|
||||
|
||||
OSTD_EXPORT void dir_range_impl::close() noexcept {
|
||||
closedir(static_cast<DIR *>(p_handle));
|
||||
}
|
||||
|
||||
OSTD_EXPORT void dir_range_impl::read_next() {
|
||||
path cur;
|
||||
file_mode tp;
|
||||
dir_read_next(static_cast<DIR *>(p_handle), cur, tp, p_dir);
|
||||
p_current = directory_entry{std::move(cur), tp};
|
||||
}
|
||||
|
||||
/* recursive dir range */
|
||||
|
||||
OSTD_EXPORT void rdir_range_impl::open(path const &p) {
|
||||
DIR *d = opendir(p.string().data());
|
||||
if (!d) {
|
||||
throw fs_error{"opendir failure", p, errno_ec()};
|
||||
}
|
||||
p_dir = p;
|
||||
p_handles.push(d);
|
||||
read_next();
|
||||
}
|
||||
|
||||
OSTD_EXPORT void rdir_range_impl::close() noexcept {
|
||||
while (!p_handles.empty()) {
|
||||
closedir(static_cast<DIR *>(p_handles.top()));
|
||||
p_handles.pop();
|
||||
}
|
||||
}
|
||||
|
||||
OSTD_EXPORT void rdir_range_impl::read_next() {
|
||||
if (p_handles.empty()) {
|
||||
return;
|
||||
}
|
||||
path curd;
|
||||
file_mode tp;
|
||||
/* can't reuse info from dirent because we need to expand symlinks */
|
||||
if (p_current.is_directory()) {
|
||||
/* directory, recurse into it and if it contains stuff, return */
|
||||
DIR *nd = opendir(p_current.path().string().data());
|
||||
if (!nd) {
|
||||
throw fs_error{"opendir failure", p_current, errno_ec()};
|
||||
struct dir_range_impl {
|
||||
void open(path const &p) {
|
||||
DIR *d = opendir(p.string().data());
|
||||
if (!d) {
|
||||
throw fs_error{"opendir failure", p, errno_ec()};
|
||||
}
|
||||
directory_entry based = p_current;
|
||||
dir_read_next(nd, curd, tp, based);
|
||||
if (!curd.empty()) {
|
||||
p_dir = based;
|
||||
p_handles.push(nd);
|
||||
p_current = directory_entry{std::move(curd), tp};
|
||||
p_dir = p;
|
||||
p_handle = d;
|
||||
read_next();
|
||||
}
|
||||
|
||||
void close() noexcept {
|
||||
closedir(static_cast<DIR *>(p_handle));
|
||||
}
|
||||
|
||||
void read_next() {
|
||||
path cur;
|
||||
file_mode tp;
|
||||
dir_read_next(static_cast<DIR *>(p_handle), cur, tp, p_dir);
|
||||
p_current = directory_entry{std::move(cur), tp};
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return p_current.path().empty();
|
||||
}
|
||||
|
||||
directory_entry const &front() const noexcept {
|
||||
return p_current;
|
||||
}
|
||||
|
||||
~dir_range_impl() {
|
||||
close();
|
||||
}
|
||||
|
||||
directory_entry p_current{};
|
||||
path p_dir{};
|
||||
void *p_handle = nullptr;
|
||||
};
|
||||
|
||||
struct rdir_range_impl {
|
||||
using hstack = std::stack<void *, std::list<void *>>;
|
||||
|
||||
void open(path const &p) {
|
||||
DIR *d = opendir(p.string().data());
|
||||
if (!d) {
|
||||
throw fs_error{"opendir failure", p, errno_ec()};
|
||||
}
|
||||
p_dir = p;
|
||||
p_handles.push(d);
|
||||
read_next();
|
||||
}
|
||||
|
||||
void close() noexcept {
|
||||
while (!p_handles.empty()) {
|
||||
closedir(static_cast<DIR *>(p_handles.top()));
|
||||
p_handles.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void read_next() {
|
||||
if (p_handles.empty()) {
|
||||
return;
|
||||
} else {
|
||||
closedir(nd);
|
||||
}
|
||||
path curd;
|
||||
file_mode tp;
|
||||
/* can't reuse info from dirent because we need to expand symlinks */
|
||||
if (p_current.is_directory()) {
|
||||
/* directory, recurse into it and if it contains stuff, return */
|
||||
DIR *nd = opendir(p_current.path().string().data());
|
||||
if (!nd) {
|
||||
throw fs_error{"opendir failure", p_current, errno_ec()};
|
||||
}
|
||||
directory_entry based = p_current;
|
||||
dir_read_next(nd, curd, tp, based);
|
||||
if (!curd.empty()) {
|
||||
p_dir = based;
|
||||
p_handles.push(nd);
|
||||
p_current = directory_entry{std::move(curd), tp};
|
||||
return;
|
||||
} else {
|
||||
closedir(nd);
|
||||
}
|
||||
}
|
||||
/* didn't recurse into a directory, go to next file */
|
||||
dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
|
||||
p_current = directory_entry{std::move(curd), tp};
|
||||
/* end of dir, pop while at it */
|
||||
if (p_current.path().empty()) {
|
||||
closedir(static_cast<DIR *>(p_handles.top()));
|
||||
p_handles.pop();
|
||||
if (!p_handles.empty()) {
|
||||
/* got back to another dir, read next so it's valid */
|
||||
p_dir.remove_name();
|
||||
dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
|
||||
p_current = directory_entry{std::move(curd), tp};
|
||||
}
|
||||
}
|
||||
}
|
||||
/* didn't recurse into a directory, go to next file */
|
||||
dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
|
||||
p_current = directory_entry{std::move(curd), tp};
|
||||
/* end of dir, pop while at it */
|
||||
if (p_current.path().empty()) {
|
||||
closedir(static_cast<DIR *>(p_handles.top()));
|
||||
p_handles.pop();
|
||||
if (!p_handles.empty()) {
|
||||
/* got back to another dir, read next so it's valid */
|
||||
p_dir.remove_name();
|
||||
dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
|
||||
p_current = directory_entry{std::move(curd), tp};
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return p_current.path().empty();
|
||||
}
|
||||
}
|
||||
|
||||
directory_entry const &front() const noexcept {
|
||||
return p_current;
|
||||
}
|
||||
|
||||
~rdir_range_impl() {
|
||||
close();
|
||||
}
|
||||
|
||||
directory_entry p_current{};
|
||||
path p_dir{};
|
||||
hstack p_handles{};
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namesapce fs */
|
||||
|
@ -289,6 +323,49 @@ OSTD_EXPORT void rdir_range_impl::read_next() {
|
|||
namespace ostd {
|
||||
namespace fs {
|
||||
|
||||
OSTD_EXPORT directory_range::directory_range(path const &p):
|
||||
p_impl{std::make_shared<detail::dir_range_impl>()}
|
||||
{
|
||||
p_impl->open(p);
|
||||
}
|
||||
|
||||
OSTD_EXPORT bool directory_range::empty() const noexcept {
|
||||
return p_impl->empty();
|
||||
}
|
||||
|
||||
OSTD_EXPORT void directory_range::pop_front() {
|
||||
p_impl->read_next();
|
||||
}
|
||||
|
||||
OSTD_EXPORT directory_range::reference directory_range::front() const noexcept {
|
||||
return p_impl->front();
|
||||
}
|
||||
|
||||
OSTD_EXPORT recursive_directory_range::recursive_directory_range(path const &p):
|
||||
p_impl{std::make_shared<detail::rdir_range_impl>()}
|
||||
{
|
||||
p_impl->open(p);
|
||||
}
|
||||
|
||||
OSTD_EXPORT bool recursive_directory_range::empty() const noexcept {
|
||||
return p_impl->empty();
|
||||
}
|
||||
|
||||
OSTD_EXPORT void recursive_directory_range::pop_front() {
|
||||
p_impl->read_next();
|
||||
}
|
||||
|
||||
OSTD_EXPORT recursive_directory_range::reference
|
||||
recursive_directory_range::front() const noexcept {
|
||||
return p_impl->front();
|
||||
}
|
||||
|
||||
} /* namespace fs */
|
||||
} /* namespace ostd */
|
||||
|
||||
namespace ostd {
|
||||
namespace fs {
|
||||
|
||||
OSTD_EXPORT path current_path() {
|
||||
auto pmax = pathconf(".", _PC_PATH_MAX);
|
||||
std::vector<char> rbuf;
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
/* Path implementation bits.
|
||||
*
|
||||
* This file is part of libostd. See COPYING.md for futher information.
|
||||
*/
|
||||
|
||||
#error "path doesn't work on Windows at this time"
|
Loading…
Reference in a new issue