diff options
Diffstat (limited to 'src/envfs.h')
| -rw-r--r-- | src/envfs.h | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/envfs.h b/src/envfs.h new file mode 100644 index 00000000..8790b071 --- /dev/null +++ b/src/envfs.h @@ -0,0 +1,193 @@ +#ifndef ENV_ENVFS_H +#define ENV_ENVFS_H + +#include <thread> + +namespace env +{ + +struct File +{ + std::wstring name; + std::wstring lcname; + FILETIME lastModified; + + File(std::wstring_view name, FILETIME ft); +}; + +struct Directory +{ + std::wstring name; + std::wstring lcname; + + std::vector<Directory> dirs; + std::vector<File> files; + + Directory(); + Directory(std::wstring_view name); +}; + + +template <class T> +class ThreadPool +{ +public: + ThreadPool(std::size_t max=1) + { + setMax(max); + } + + ~ThreadPool() + { + stopAndJoin(); + } + + void setMax(std::size_t n) + { + m_threads.resize(n); + } + + void stopAndJoin() + { + for (auto& ti : m_threads) { + ti.stop = true; + ti.wakeup(); + } + + for (auto& ti : m_threads) { + if (ti.thread.joinable()) { + ti.thread.join(); + } + } + } + + void waitForAll() + { + for (;;) { + bool done = true; + + for (auto& ti : m_threads) { + if (ti.busy) { + done = false; + break; + } + } + + if (done) { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + T& request() + { + if (m_threads.empty()) { + std::terminate(); + } + + for (;;) { + for (auto& ti : m_threads) { + bool expected = false; + + if (ti.busy.compare_exchange_strong(expected, true)) { + ti.wakeup(); + return ti.o; + } + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + template <class F> + void forEach(F&& f) + { + for (auto& ti : m_threads) { + f(ti.o); + } + } + +private: + struct ThreadInfo + { + std::thread thread; + std::atomic<bool> busy; + T o; + + std::condition_variable cv; + std::mutex mutex; + bool ready; + + std::atomic<bool> stop; + + ThreadInfo() + : busy(true), ready(false), stop(false) + { + thread = std::thread([&]{ run(); }); + } + + void wakeup() + { + { + std::scoped_lock lock(mutex); + ready = true; + } + + cv.notify_one(); + } + + void run() + { + busy = false; + + while (!stop) { + std::unique_lock lock(mutex); + cv.wait(lock, [&]{ return ready; }); + + if (stop) { + break; + } + + o.run(); + + ready = false; + busy = false; + } + } + }; + + std::list<ThreadInfo> m_threads; +}; + + +using DirStartF = void (void*, std::wstring_view); +using DirEndF = void (void*, std::wstring_view); +using FileF = void (void*, std::wstring_view, FILETIME); + +void setHandleCloserThreadCount(std::size_t n); + + +class DirectoryWalker +{ +public: + void forEachEntry( + const std::wstring& path, void* cx, + DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF); + +private: + std::vector<std::unique_ptr<unsigned char[]>> m_buffers; +}; + + +void forEachEntry( + const std::wstring& path, void* cx, + DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF); + +Directory getFilesAndDirs(const std::wstring& path); +Directory getFilesAndDirsWithFind(const std::wstring& path); + +} // namespace + +#endif // ENV_ENVFS_H |
