diff --git a/threadpool.hpp b/threadpool.hpp index 9eb06ac..4a4880c 100644 --- a/threadpool.hpp +++ b/threadpool.hpp @@ -72,6 +72,8 @@ struct ThreadPool { /// Used to notify on shutdown std::atomic_bool threadsShouldShutdown { false }; + // implement these out of line + std::size_t QueueLength(std::size_t worker) const { std::unique_lock lk(this->taskQueues[worker].lock); return this->taskQueues[worker].queue.size(); diff --git a/tree.hpp b/tree.hpp index e8d3798..15f76b8 100644 --- a/tree.hpp +++ b/tree.hpp @@ -1,10 +1,13 @@ #pragma once #include -/// Port of tree.py to C++ +/// A simplistic N-ary/generic tree. Probably not very good for data locality. template struct Tree { - // FIXME make T not require default constructability + // FIXME: + // - make T not require default constructability + // - move instead of copy into leaf + // - use "btree-like" repressentation of N-ary nodes to save memory struct Node { protected: friend Tree; diff --git a/vxorg.cpp b/vxorg.cpp index e08ff6a..e6b688b 100644 --- a/vxorg.cpp +++ b/vxorg.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -11,26 +12,45 @@ namespace ind = indicators; -int main() { - std::ifstream ifs("./testdata/samples.sort"); - vxorg::VxHeavenTree tree; +int main(int argc, char** argv) { + if(argc != 4) { + std::fprintf(stderr, "usage: %s [path to list] [source path] [destination path]\n", argv[0]); + return 1; + } + + vxorg::VxHeavenTree sample_tree; // used for os filesystem ops - ThreadPool fsPool(4); + ThreadPool filesystem_threadpool(4); - vxorg::parse_into_tree(tree, ifs); + // Parse into the sample tree + std::ifstream ifs(argv[1]); - std::filesystem::path root = std::filesystem::current_path() / "testdata"; - std::filesystem::path unorg = root / "unorg"; - std::filesystem::path org = root / "org"; + if(!ifs) { + char err[256]{}; + strerror_r(errno, &err[0], sizeof(err)-1); + std::fprintf(stderr, "Could not open sample list \"%s\": %s", argv[1], err); + return 1; + } - if(!std::filesystem::exists(org)) - std::filesystem::create_directories(org); + vxorg::parse_into_tree(sample_tree, ifs); + + std::filesystem::path unorganized_source_path = argv[2]; + std::filesystem::path organized_destination_path = argv[3]; + + + if(!std::filesystem::exists(unorganized_source_path)) { + std::fprintf(stderr, "Source path \"%s\" does not exist", argv[2]); + return 1; + } + + if(!std::filesystem::exists(organized_destination_path)) + std::filesystem::create_directories(organized_destination_path); std::size_t sampleCount = 0; // Walk the tree to get the amount of sample nodes - tree.walk([&](auto* node) { + sample_tree.walk([&](auto* node) { if(node->data().is_sample) sampleCount++; }); @@ -41,16 +61,17 @@ int main() { ind::option::Lead { "■" }, ind::option::Remainder { "-" }, ind::option::End { " ]" }, - ind::option::ForegroundColor { ind::Color::cyan }, + ind::option::ForegroundColor { ind::Color::red }, ind::option::FontStyles { std::vector { ind::FontStyle::bold } }, ind::option::MaxProgress { sampleCount } }; // Walk the tree to perform the operation - tree.walk([&](auto* node) { - auto tabulation_level = node->parent_count(); + sample_tree.walk([&](auto* node) { auto& data = node->data(); #if 0 + auto tabulation_level = node->parent_count(); + if(tabulation_level != 0) { for(auto i = 0; i < tabulation_level; ++i) { std::printf("\t"); @@ -75,26 +96,26 @@ int main() { std::string sample_name = vxorg::get_sample_name(node); // paths - auto path = org / vxorg::get_sample_path(node); - auto source_path = unorg / vxorg::get_sample_name(node); + auto path = organized_destination_path / vxorg::get_sample_path(node); + auto source_path = unorganized_source_path / vxorg::get_sample_name(node); if(!std::filesystem::exists(source_path)) { - std::printf("WARNING: sample %s/%s in tree (source disk file %s) does not exist\n", path.string().c_str(), sample_name.c_str(), + std::printf("WARNING: sample %s in tree (source disk file %s) does not exist\n", sample_name.c_str(), source_path.string().c_str()); } else { - fsPool.add_task([path, source_path, sample_name, &bar]() { + filesystem_threadpool.add_task([path, source_path, sample_name, &bar]() { bar.set_option(ind::option::PostfixText { std::format("Moving {}", sample_name) }); - auto dest_path = path / sample_name; + auto dest_path = path / sample_name; - // possibly TOCTOUable but it should:tm: be fine? - if(!std::filesystem::exists(path)) { - std::filesystem::create_directories(path); - } + // possibly TOCTOUable but it should:tm: be fine? + if(!std::filesystem::exists(path)) { + std::filesystem::create_directories(path); + } - if(std::filesystem::exists(dest_path)) { - std::filesystem::remove(dest_path); - } + if(std::filesystem::exists(dest_path)) { + std::filesystem::remove(dest_path); + } std::filesystem::rename(source_path, dest_path); bar.tick(); @@ -105,5 +126,9 @@ int main() { #endif }); + filesystem_threadpool.shutdown(); + + bar.mark_as_completed(); + std::printf("Done.\n"); return 0; } \ No newline at end of file