diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/folder/iterator.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/folder/iterator.h')
-rw-r--r-- | util/folder/iterator.h | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/util/folder/iterator.h b/util/folder/iterator.h new file mode 100644 index 0000000000..69e025b9c4 --- /dev/null +++ b/util/folder/iterator.h @@ -0,0 +1,109 @@ +#pragma once + +#include "fts.h" + +#include <util/system/error.h> +#include <util/generic/ptr.h> +#include <util/generic/iterator.h> +#include <util/generic/yexception.h> + +/// Note this magic API traverses directory hierarchy + +class TDirIterator: public TInputRangeAdaptor<TDirIterator> { + struct TFtsDestroy { + static inline void Destroy(FTS* f) noexcept { + yfts_close(f); + } + }; + +public: + class TError: public TSystemError { + public: + inline TError(int err) + : TSystemError(err) + { + } + }; + + using TCompare = int (*)(const FTSENT**, const FTSENT**); + + struct TOptions { + inline TOptions() { + Init(FTS_PHYSICAL); + } + + inline TOptions(int opts) { + Init(opts); + } + + inline TOptions& SetMaxLevel(size_t level) noexcept { + MaxLevel = level; + + return *this; + } + + inline TOptions& SetSortFunctor(TCompare cmp) noexcept { + Cmp = cmp; + + return *this; + } + + TOptions& SetSortByName() noexcept; + + int FtsOptions; + size_t MaxLevel; + TCompare Cmp; + + private: + inline void Init(int opts) noexcept { + FtsOptions = opts | FTS_NOCHDIR; + MaxLevel = Max<size_t>(); + Cmp = nullptr; + } + }; + + inline TDirIterator(const TString& path, const TOptions& options = TOptions()) + : Options_(options) + , Path_(path) + { + Trees_[0] = Path_.begin(); + Trees_[1] = nullptr; + + ClearLastSystemError(); + FileTree_.Reset(yfts_open(Trees_, Options_.FtsOptions, Options_.Cmp)); + + const int err = LastSystemError(); + + if (err) { + ythrow TError(err) << "can not open '" << Path_ << "'"; + } + } + + inline FTSENT* Next() { + FTSENT* ret = yfts_read(FileTree_.Get()); + + if (ret) { + if ((size_t)(ret->fts_level + 1) > Options_.MaxLevel) { + yfts_set(FileTree_.Get(), ret, FTS_SKIP); + } + } else { + const int err = LastSystemError(); + + if (err) { + ythrow TError(err) << "error while iterating " << Path_; + } + } + + return ret; + } + + inline void Skip(FTSENT* ent) { + yfts_set(FileTree_.Get(), ent, FTS_SKIP); + } + +private: + TOptions Options_; + TString Path_; + char* Trees_[2]; + THolder<FTS, TFtsDestroy> FileTree_; +}; |