mirror of
https://git.mirrors.martin98.com/https://github.com/gulrak/filesystem
synced 2025-06-04 11:13:58 +08:00
refs #13, rework of POSIX directory_iterator handling, performance optimization
This commit is contained in:
parent
280a8590f9
commit
cc476ac1fd
@ -52,6 +52,6 @@ int main(int argc, char* argv[])
|
|||||||
std::cerr << "Error: " << fe.what() << std::endl;
|
std::cerr << "Error: " << fe.what() << std::endl;
|
||||||
exit(1);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -342,6 +342,8 @@ public:
|
|||||||
iterator end() const;
|
iterator end() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class directory_iterator;
|
||||||
|
void append_name(const char* name);
|
||||||
static constexpr value_type generic_separator = '/';
|
static constexpr value_type generic_separator = '/';
|
||||||
template <typename InputIterator>
|
template <typename InputIterator>
|
||||||
class input_iterator_range
|
class input_iterator_range
|
||||||
@ -1909,7 +1911,8 @@ inline path& path::assign(const Source& source)
|
|||||||
template <>
|
template <>
|
||||||
inline path& path::assign<path>(const path& source)
|
inline path& path::assign<path>(const path& source)
|
||||||
{
|
{
|
||||||
return assign(source._path);
|
_path = source._path;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
@ -1959,6 +1962,19 @@ GHC_INLINE path& path::operator/=(const path& p)
|
|||||||
return *this;
|
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
|
#endif // GHC_EXPAND_IMPL
|
||||||
|
|
||||||
template <class Source>
|
template <class Source>
|
||||||
@ -4537,7 +4553,8 @@ public:
|
|||||||
if (_dirHandle != INVALID_HANDLE_VALUE) {
|
if (_dirHandle != INVALID_HANDLE_VALUE) {
|
||||||
do {
|
do {
|
||||||
if (FindNextFileW(_dirHandle, &_findData)) {
|
if (FindNextFileW(_dirHandle, &_findData)) {
|
||||||
_current = _base / std::wstring(_findData.cFileName);
|
_current = _base;
|
||||||
|
_current.append_name(detail::toUtf8(_findData.cFileName).c_str());
|
||||||
copyToDirEntry(ec);
|
copyToDirEntry(ec);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -4584,32 +4601,17 @@ public:
|
|||||||
// POSIX implementation
|
// POSIX implementation
|
||||||
class directory_iterator::impl
|
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<size_t>(rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
impl(const path& path, directory_options options)
|
impl(const path& path, directory_options options)
|
||||||
: _base(path)
|
: _base(path)
|
||||||
, _options(options)
|
, _options(options)
|
||||||
, _dir((path.empty() ? nullptr : ::opendir(path.native().c_str())),
|
, _dir(nullptr)
|
||||||
[](DIR* d) {
|
, _entry(nullptr)
|
||||||
if (d) {
|
|
||||||
::closedir(d);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
, _bufferSize(directory_entry_buffer_size(_dir.get()))
|
|
||||||
, _buffer(new char[_bufferSize])
|
|
||||||
, _entry(reinterpret_cast<::dirent*>(&_buffer[0]))
|
|
||||||
{
|
{
|
||||||
|
if(!path.empty()) {
|
||||||
|
_dir = ::opendir(path.native().c_str());
|
||||||
|
}
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
if (!_dir) {
|
if (!_dir) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
@ -4624,40 +4626,30 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl(const impl& other) = delete;
|
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))
|
if(_dir) {
|
||||||
errno = 0;
|
::closedir(_dir);
|
||||||
auto de = readdir(dir);
|
|
||||||
if (de) {
|
|
||||||
*entry = *de;
|
|
||||||
*result = entry;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return errno;
|
|
||||||
#else
|
|
||||||
return ::readdir_r(dir, entry, result);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
void increment(std::error_code& ec)
|
void increment(std::error_code& ec)
|
||||||
{
|
{
|
||||||
if (_dir) {
|
if (_dir) {
|
||||||
do {
|
do {
|
||||||
dirent* result = 0;
|
errno = 0;
|
||||||
if (0 == i_readdir_r(_dir.get(), _entry, &result)) {
|
_entry = readdir(_dir);
|
||||||
if (result) {
|
if (_entry) {
|
||||||
_current = _base / path(_entry->d_name);
|
_current = _base;
|
||||||
|
_current.append_name(_entry->d_name);
|
||||||
_dir_entry = directory_entry(_current, ec);
|
_dir_entry = directory_entry(_current, ec);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_dir.reset();
|
::closedir(_dir);
|
||||||
_current = path();
|
_dir = nullptr;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_current = path();
|
_current = path();
|
||||||
|
if(errno) {
|
||||||
ec = std::error_code(errno, std::system_category());
|
ec = std::error_code(errno, std::system_category());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
|
} while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
|
||||||
@ -4666,9 +4658,7 @@ public:
|
|||||||
path _base;
|
path _base;
|
||||||
directory_options _options;
|
directory_options _options;
|
||||||
path _current;
|
path _current;
|
||||||
std::shared_ptr<DIR> _dir;
|
DIR* _dir;
|
||||||
size_t _bufferSize;
|
|
||||||
std::unique_ptr<char[]> _buffer;
|
|
||||||
struct ::dirent* _entry;
|
struct ::dirent* _entry;
|
||||||
directory_entry _dir_entry;
|
directory_entry _dir_entry;
|
||||||
std::error_code _ec;
|
std::error_code _ec;
|
||||||
@ -4893,10 +4883,15 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment
|
|||||||
else {
|
else {
|
||||||
_impl->_dir_iter_stack.top().increment(ec);
|
_impl->_dir_iter_stack.top().increment(ec);
|
||||||
}
|
}
|
||||||
|
if(!ec) {
|
||||||
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
|
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
|
||||||
_impl->_dir_iter_stack.pop();
|
_impl->_dir_iter_stack.pop();
|
||||||
_impl->_dir_iter_stack.top().increment(ec);
|
_impl->_dir_iter_stack.top().increment(ec);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if(!_impl->_dir_iter_stack.empty()) {
|
||||||
|
_impl->_dir_iter_stack.pop();
|
||||||
|
}
|
||||||
_impl->_recursion_pending = true;
|
_impl->_recursion_pending = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user