From cc476ac1fd576f8815d9f3bb60cc82e9f3f1fd93 Mon Sep 17 00:00:00 2001 From: gulrak Date: Tue, 7 May 2019 19:49:01 +0200 Subject: [PATCH] refs #13, rework of POSIX directory_iterator handling, performance optimization --- examples/du.cpp | 2 +- include/ghc/filesystem.hpp | 99 ++++++++++++++++++-------------------- 2 files changed, 48 insertions(+), 53 deletions(-) diff --git a/examples/du.cpp b/examples/du.cpp index 88436d9..95b9580 100644 --- a/examples/du.cpp +++ b/examples/du.cpp @@ -52,6 +52,6 @@ int main(int argc, char* argv[]) std::cerr << "Error: " << fe.what() << std::endl; exit(1); } - std::cout << totalSize << " bytes in " << totalFiles << " and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl; + std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl; return 0; } diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 39c1361..4429a14 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -342,6 +342,8 @@ class GHC_FS_API_CLASS path iterator end() const; private: + friend class directory_iterator; + void append_name(const char* name); static constexpr value_type generic_separator = '/'; template class input_iterator_range @@ -1909,7 +1911,8 @@ inline path& path::assign(const Source& source) template <> inline path& path::assign(const path& source) { - return assign(source._path); + _path = source._path; + return *this; } template @@ -1959,6 +1962,19 @@ GHC_INLINE path& path::operator/=(const path& p) return *this; } +GHC_INLINE void path::append_name(const char* name) +{ + if(_path.empty()) { + this->operator/=(path(name)); + } + else { + if(_path.back() != path::generic_separator) { + _path.push_back(path::generic_separator); + } + _path += name; + } +} + #endif // GHC_EXPAND_IMPL template @@ -4537,7 +4553,8 @@ class directory_iterator::impl if (_dirHandle != INVALID_HANDLE_VALUE) { do { if (FindNextFileW(_dirHandle, &_findData)) { - _current = _base / std::wstring(_findData.cFileName); + _current = _base; + _current.append_name(detail::toUtf8(_findData.cFileName).c_str()); copyToDirEntry(ec); } else { @@ -4584,32 +4601,17 @@ class directory_iterator::impl // POSIX implementation class directory_iterator::impl { - size_t directory_entry_buffer_size(DIR* d) - { - size_t result = std::max(sizeof(::dirent), sizeof(::dirent) - sizeof(::dirent::d_name) + NAME_MAX) + 1; - if (d) { - long rc = ::fpathconf(dirfd(d), _PC_NAME_MAX); - if (rc > long(result)) { - result = static_cast(rc); - } - } - return result; - } - + public: impl(const path& path, directory_options options) : _base(path) , _options(options) - , _dir((path.empty() ? nullptr : ::opendir(path.native().c_str())), - [](DIR* d) { - if (d) { - ::closedir(d); - } - }) - , _bufferSize(directory_entry_buffer_size(_dir.get())) - , _buffer(new char[_bufferSize]) - , _entry(reinterpret_cast<::dirent*>(&_buffer[0])) + , _dir(nullptr) + , _entry(nullptr) { + if(!path.empty()) { + _dir = ::opendir(path.native().c_str()); + } if (!path.empty()) { if (!_dir) { auto error = errno; @@ -4624,40 +4626,30 @@ class directory_iterator::impl } } impl(const impl& other) = delete; - int i_readdir_r(DIR* dir, struct dirent* entry, struct dirent** result) + ~impl() { -#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)) - errno = 0; - auto de = readdir(dir); - if (de) { - *entry = *de; - *result = entry; - return 0; + if(_dir) { + ::closedir(_dir); } - return errno; -#else - return ::readdir_r(dir, entry, result); -#endif } void increment(std::error_code& ec) { if (_dir) { do { - dirent* result = 0; - if (0 == i_readdir_r(_dir.get(), _entry, &result)) { - if (result) { - _current = _base / path(_entry->d_name); - _dir_entry = directory_entry(_current, ec); - } - else { - _dir.reset(); - _current = path(); - break; - } + errno = 0; + _entry = readdir(_dir); + if (_entry) { + _current = _base; + _current.append_name(_entry->d_name); + _dir_entry = directory_entry(_current, ec); } else { + ::closedir(_dir); + _dir = nullptr; _current = path(); - ec = std::error_code(errno, std::system_category()); + if(errno) { + ec = std::error_code(errno, std::system_category()); + } break; } } while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); @@ -4666,9 +4658,7 @@ class directory_iterator::impl path _base; directory_options _options; path _current; - std::shared_ptr _dir; - size_t _bufferSize; - std::unique_ptr _buffer; + DIR* _dir; struct ::dirent* _entry; directory_entry _dir_entry; std::error_code _ec; @@ -4893,9 +4883,14 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment else { _impl->_dir_iter_stack.top().increment(ec); } - while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { + if(!ec) { + while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { + _impl->_dir_iter_stack.pop(); + _impl->_dir_iter_stack.top().increment(ec); + } + } + else if(!_impl->_dir_iter_stack.empty()) { _impl->_dir_iter_stack.pop(); - _impl->_dir_iter_stack.top().increment(ec); } _impl->_recursion_pending = true; return *this;