refs #12, multiple fixes for fs::recursive_directory_iterator concerning endless iterations, wrong pop and depth handling and better input_iterator_tag and copy semantics.

This commit is contained in:
Steffen Schuemann 2019-05-04 00:11:16 +02:00
parent 43e75c3869
commit cce8c431c2

View File

@ -725,9 +725,17 @@ public:
void swap(recursive_directory_iterator& rhs); void swap(recursive_directory_iterator& rhs);
private: private:
directory_options _options; struct recursive_directory_iterator_impl {
bool _recursion_pending; directory_options _options;
std::stack<directory_iterator> _dir_iter_stack; bool _recursion_pending;
std::stack<directory_iterator> _dir_iter_stack;
recursive_directory_iterator_impl(directory_options options, bool recursion_pending)
: _options(options)
, _recursion_pending(recursion_pending)
{
}
};
std::shared_ptr<recursive_directory_iterator_impl> _impl;
}; };
// 30.10.14.2 directory_iterator non-member functions // 30.10.14.2 directory_iterator non-member functions
@ -4756,51 +4764,42 @@ GHC_INLINE directory_iterator end(const directory_iterator&) noexcept
// 30.10.14 class recursive_directory_iterator // 30.10.14 class recursive_directory_iterator
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept
: _options(directory_options::none) : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
, _recursion_pending(true)
{ {
_dir_iter_stack.push(directory_iterator()); _impl->_dir_iter_stack.push(directory_iterator());
} }
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p) GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p)
: _options(directory_options::none) : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
, _recursion_pending(true)
{ {
_dir_iter_stack.push(directory_iterator(p)); _impl->_dir_iter_stack.push(directory_iterator(p));
} }
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options)
: _options(options) : _impl(new recursive_directory_iterator_impl(options, true))
, _recursion_pending(true)
{ {
_dir_iter_stack.push(directory_iterator(p, options)); _impl->_dir_iter_stack.push(directory_iterator(p, options));
} }
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept
: _options(options) : _impl(new recursive_directory_iterator_impl(options, true))
, _recursion_pending(true)
{ {
_dir_iter_stack.push(directory_iterator(p, options, ec)); _impl->_dir_iter_stack.push(directory_iterator(p, options, ec));
} }
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept
: _options(directory_options::none) : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
, _recursion_pending(true)
{ {
_dir_iter_stack.push(directory_iterator(p, ec)); _impl->_dir_iter_stack.push(directory_iterator(p, ec));
} }
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs) GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs)
: _options(rhs._options) : _impl(rhs._impl)
, _recursion_pending(rhs._recursion_pending)
, _dir_iter_stack(rhs._dir_iter_stack)
{ {
} }
GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept
: _options(rhs._options) : _impl(std::move(rhs._impl))
, _recursion_pending(rhs._recursion_pending)
, _dir_iter_stack(std::move(rhs._dir_iter_stack))
{ {
} }
@ -4809,43 +4808,39 @@ GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {}
// 30.10.14.1 observers // 30.10.14.1 observers
GHC_INLINE directory_options recursive_directory_iterator::options() const GHC_INLINE directory_options recursive_directory_iterator::options() const
{ {
return _options; return _impl->_options;
} }
GHC_INLINE int recursive_directory_iterator::depth() const GHC_INLINE int recursive_directory_iterator::depth() const
{ {
return static_cast<int>(_dir_iter_stack.empty() ? 0 : _dir_iter_stack.size() - 1); return static_cast<int>(_impl->_dir_iter_stack.size() - 1);
} }
GHC_INLINE bool recursive_directory_iterator::recursion_pending() const GHC_INLINE bool recursive_directory_iterator::recursion_pending() const
{ {
return _recursion_pending; return _impl->_recursion_pending;
} }
GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const
{ {
return *(_dir_iter_stack.top()); return *(_impl->_dir_iter_stack.top());
} }
GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const
{ {
return &(*(_dir_iter_stack.top())); return &(*(_impl->_dir_iter_stack.top()));
} }
// 30.10.14.1 modifiers recursive_directory_iterator& // 30.10.14.1 modifiers recursive_directory_iterator&
GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs)
{ {
_options = rhs._options; _impl = rhs._impl;
_recursion_pending = rhs._recursion_pending;
_dir_iter_stack = rhs._dir_iter_stack;
return *this; return *this;
} }
GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept
{ {
_options = rhs._options; _impl = std::move(rhs._impl);
_recursion_pending = rhs._recursion_pending;
_dir_iter_stack = std::move(rhs._dir_iter_stack);
return *this; return *this;
} }
@ -4854,7 +4849,7 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator+
std::error_code ec; std::error_code ec;
increment(ec); increment(ec);
if (ec) { if (ec) {
throw filesystem_error(detail::systemErrorText(ec.value()), _dir_iter_stack.empty() ? path() : _dir_iter_stack.top()->path(), ec); throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);
} }
return *this; return *this;
} }
@ -4862,56 +4857,60 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator+
GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept
{ {
if (recursion_pending() && is_directory((*this)->status()) && (!is_symlink((*this)->symlink_status()) || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { if (recursion_pending() && is_directory((*this)->status()) && (!is_symlink((*this)->symlink_status()) || (options() & directory_options::follow_directory_symlink) != directory_options::none)) {
_dir_iter_stack.push(directory_iterator((*this)->path(), _options, ec)); _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec));
} }
else { else {
_dir_iter_stack.top().increment(ec); _impl->_dir_iter_stack.top().increment(ec);
} }
while (depth() && _dir_iter_stack.top() == directory_iterator()) { while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
_dir_iter_stack.pop(); _impl->_dir_iter_stack.pop();
_dir_iter_stack.top().increment(ec); _impl->_dir_iter_stack.top().increment(ec);
} }
_impl->_recursion_pending = true;
return *this; return *this;
} }
GHC_INLINE void recursive_directory_iterator::pop() GHC_INLINE void recursive_directory_iterator::pop()
{
std::error_code ec;
pop(ec);
if (ec) {
throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);
}
}
GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec)
{ {
if (depth() == 0) { if (depth() == 0) {
*this = recursive_directory_iterator(); *this = recursive_directory_iterator();
} }
else { else {
_dir_iter_stack.pop(); while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
_impl->_dir_iter_stack.pop();
_impl->_dir_iter_stack.top().increment(ec);
}
} }
} }
GHC_INLINE void recursive_directory_iterator::pop(std::error_code&)
{
pop();
}
GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() GHC_INLINE void recursive_directory_iterator::disable_recursion_pending()
{ {
_recursion_pending = false; _impl->_recursion_pending = false;
} }
// other members as required by 27.2.3, input iterators // other members as required by 27.2.3, input iterators
GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const
{ {
return _dir_iter_stack.top() == rhs._dir_iter_stack.top(); return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top();
} }
GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const
{ {
return _dir_iter_stack.top() != rhs._dir_iter_stack.top(); return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top();
} }
GHC_INLINE void recursive_directory_iterator::swap(recursive_directory_iterator& rhs) GHC_INLINE void recursive_directory_iterator::swap(recursive_directory_iterator& rhs)
{ {
std::swap(_options, rhs._options); std::swap(_impl, rhs._impl);
bool rp = _recursion_pending;
_recursion_pending = rhs._recursion_pending;
rhs._recursion_pending = rp;
_dir_iter_stack.swap(rhs._dir_iter_stack);
} }
// 30.10.14.2 directory_iterator non-member functions // 30.10.14.2 directory_iterator non-member functions