diff --git a/include/hibf/config.hpp b/include/hibf/config.hpp index cc98ef94..87abd64f 100644 --- a/include/hibf/config.hpp +++ b/include/hibf/config.hpp @@ -11,6 +11,7 @@ #include // for size_t #include // for path #include // for function +#include // for ostream #include // for insert_iterator #include // for unordered_flat_set @@ -82,6 +83,9 @@ struct config // bool compressed{false}; //!\} + void read_from(std::istream & stream); + void write_to(std::ostream & stream) const; + private: friend class cereal::access; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cb361587..daa3df9a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ set (HIBF_SOURCE_FILES hierarchical_interleaved_bloom_filter.cpp + config.cpp detail/layout/simple_binning.cpp detail/layout/execute.cpp detail/layout/compute_fpr_correction.cpp diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 00000000..281882ea --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,60 @@ +// --------------------------------------------------------------------------------------------------- +// Copyright (c) 2006-2023, Knut Reinert & Freie Universität Berlin +// Copyright (c) 2016-2023, Knut Reinert & MPI für molekulare Genetik +// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License +// shipped with this file and also available at: https://github.com/seqan/hibf/blob/main/LICENSE.md +// --------------------------------------------------------------------------------------------------- + +#include +#include +#include + +#include +#include + +#include + +namespace hibf +{ + +void config::read_from(std::istream & stream) +{ + std::string line; + std::stringstream config_str; + + while (std::getline(stream, line) && line != prefix::meta_hibf_config_start) + ; + + assert(line == prefix::meta_hibf_config_start); + + // TODO ##CONFIG: as prefix + while (std::getline(stream, line) && line != prefix::meta_hibf_config_end) + { + assert(line.size() >= 2); + assert(std::string_view{line}.substr(0, 1) == hibf::prefix::meta_header); + config_str << line.substr(1); // remove hibf::prefix::meta_header + } + + assert(line == prefix::meta_hibf_config_end); + + cereal::JSONInputArchive iarchive(config_str); + iarchive(*this); +} + +void config::write_to(std::ostream & stream) const +{ + // write json file to temprorary string stream with cereal + std::stringstream config_stream{}; + cereal::JSONOutputArchive output(config_stream); // stream to cout + output(cereal::make_nvp("hibf_config", *this)); + + // write config + stream << prefix::meta_hibf_config_start << '\n'; + std::string line; + while (std::getline(config_stream, line, '\n')) + stream << prefix::meta_header << line << '\n'; + stream << prefix::meta_header << "}\n" // last closing bracket isn't written by loop above + << prefix::meta_hibf_config_end << '\n'; +} + +} // namespace hibf diff --git a/test/unit/hibf/CMakeLists.txt b/test/unit/hibf/CMakeLists.txt index 55498c5b..8b326d3d 100644 --- a/test/unit/hibf/CMakeLists.txt +++ b/test/unit/hibf/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectories () +hibf_test (config_test.cpp) hibf_test (hierarchical_interleaved_bloom_filter_test.cpp) hibf_test (interleaved_bloom_filter_test.cpp) diff --git a/test/unit/hibf/config_test.cpp b/test/unit/hibf/config_test.cpp new file mode 100644 index 00000000..ec2eb853 --- /dev/null +++ b/test/unit/hibf/config_test.cpp @@ -0,0 +1,130 @@ +#include // for Test, TestInfo, EXPECT_EQ, Message, TEST, TestPartResult + +#include // for size_t +#include // for operator<<, char_traits, basic_ostream, basic_stringstream, strings... +#include // for allocator, string +#include // for operator<< +#include // for vector + +#include // for config + +TEST(config_test, write_to) +{ + std::stringstream ss{}; + + hibf::config configuration; + + configuration.number_of_user_bins = 123456789; + configuration.number_of_hash_functions = 4; + configuration.maximum_false_positive_rate = 0.0001; + configuration.threads = 31; + configuration.sketch_bits = 8; + configuration.tmax = 128; + configuration.alpha = 1.0; + configuration.max_rearrangement_ratio = 0.333; + configuration.disable_estimate_union = true; + configuration.disable_rearrangement = false; + configuration.disable_cutoffs = false; + + configuration.write_to(ss); + + std::string const expected_file{"@HIBF_CONFIG\n" + "@{\n" + "@ \"hibf_config\": {\n" + "@ \"version\": 1,\n" + "@ \"number_of_user_bins\": 123456789,\n" + "@ \"number_of_hash_functions\": 4,\n" + "@ \"maximum_false_positive_rate\": 0.0001,\n" + "@ \"threads\": 31,\n" + "@ \"sketch_bits\": 8,\n" + "@ \"tmax\": 128,\n" + "@ \"alpha\": 1.0,\n" + "@ \"max_rearrangement_ratio\": 0.333,\n" + "@ \"disable_estimate_union\": true,\n" + "@ \"disable_rearrangement\": false,\n" + "@ \"disable_cutoffs\": false\n" + "@ }\n" + "@}\n" + "@HIBF_CONFIG_END\n"}; + + EXPECT_EQ(ss.str(), expected_file); +} + +TEST(config_test, read_from) +{ + std::stringstream ss{"@HIBF_CONFIG\n" + "@{\n" + "@ \"hibf_config\": {\n" + "@ \"version\": 1,\n" + "@ \"number_of_user_bins\": 123456789,\n" + "@ \"number_of_hash_functions\": 4,\n" + "@ \"maximum_false_positive_rate\": 0.0001,\n" + "@ \"threads\": 31,\n" + "@ \"sketch_bits\": 8,\n" + "@ \"tmax\": 128,\n" + "@ \"alpha\": 1.0,\n" + "@ \"max_rearrangement_ratio\": 0.333,\n" + "@ \"disable_estimate_union\": true,\n" + "@ \"disable_rearrangement\": false,\n" + "@ \"disable_cutoffs\": false\n" + "@ }\n" + "@}\n" + "@HIBF_CONFIG_END\n"}; + + hibf::config configuration; + configuration.read_from(ss); + + EXPECT_EQ(configuration.number_of_user_bins, 123456789); + EXPECT_EQ(configuration.number_of_hash_functions, 4); + EXPECT_EQ(configuration.maximum_false_positive_rate, 0.0001); + EXPECT_EQ(configuration.threads, 31); + EXPECT_EQ(configuration.sketch_bits, 8); + EXPECT_EQ(configuration.tmax, 128); + EXPECT_EQ(configuration.alpha, 1.0); + EXPECT_EQ(configuration.max_rearrangement_ratio, 0.333); + EXPECT_EQ(configuration.disable_estimate_union, true); + EXPECT_EQ(configuration.disable_rearrangement, false); + EXPECT_EQ(configuration.disable_cutoffs, false); +} + +TEST(config_test, read_from_with_more_meta) +{ + std::stringstream ss{"@blah some chopper stuff\n" + "@blah some chopper stuff\n" + "@blah some chopper stuff\n" + "@blah some chopper stuff\n" + "@blah some chopper stuff\n" + "@HIBF_CONFIG\n" + "@{\n" + "@ \"hibf_config\": {\n" + "@ \"version\": 1,\n" + "@ \"number_of_user_bins\": 123456789,\n" + "@ \"number_of_hash_functions\": 4,\n" + "@ \"maximum_false_positive_rate\": 0.0001,\n" + "@ \"threads\": 31,\n" + "@ \"sketch_bits\": 8,\n" + "@ \"tmax\": 128,\n" + "@ \"alpha\": 1.0,\n" + "@ \"max_rearrangement_ratio\": 0.333,\n" + "@ \"disable_estimate_union\": true,\n" + "@ \"disable_rearrangement\": false,\n" + "@ \"disable_cutoffs\": false\n" + "@ }\n" + "@}\n" + "@HIBF_CONFIG_END\n"}; + + hibf::config configuration; + configuration.read_from(ss); + + EXPECT_EQ(configuration.number_of_user_bins, 123456789); + EXPECT_EQ(configuration.number_of_hash_functions, 4); + EXPECT_EQ(configuration.maximum_false_positive_rate, 0.0001); + EXPECT_EQ(configuration.threads, 31); + EXPECT_EQ(configuration.sketch_bits, 8); + EXPECT_EQ(configuration.tmax, 128); + EXPECT_EQ(configuration.alpha, 1.0); + EXPECT_EQ(configuration.max_rearrangement_ratio, 0.333); + EXPECT_EQ(configuration.disable_estimate_union, true); + EXPECT_EQ(configuration.disable_rearrangement, false); + EXPECT_EQ(configuration.disable_cutoffs, false); +}