move directory range structural details into implementation

This commit is contained in:
q66 2018-12-02 03:24:52 +01:00
parent 466b80b96b
commit 256a35697a
4 changed files with 171 additions and 164 deletions

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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"