diff --git a/README.md b/README.md index 3ef1d78..9f3f787 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ This template is the result of learnings from many previous projects and should - Reproducible dependency management via [CPM.cmake](https://github.com/TheLartians/CPM.cmake) - Installable target with automatic versioning information and header generation via [PackageProject.cmake](https://github.com/TheLartians/PackageProject.cmake) - Automatic [documentation](https://thelartians.github.io/ModernCppStarter) and deployment with [Doxygen](https://www.doxygen.nl) and [GitHub Pages](https://pages.github.com) -- Support for [sanitizer tools, and more](#additional-tools) ## Usage @@ -42,7 +41,7 @@ This template is the result of learnings from many previous projects and should Eventually, you can remove any unused files, such as the standalone directory or irrelevant github workflows for your project. Feel free to replace the License with one suited for your project. -To cleanly separate the library and subproject code, the outer `CMakeList.txt` only defines the library itself while the tests and other subprojects are self-contained in their own directories. +To cleanly separate the library and subproject code, the outer `CMakeList.txt` only defines the library itself while the tests and other subprojects are self-contained in their own directories. During development it is usually convenient to [build all subprojects at once](#build-everything-at-once). ### Build and run the standalone target diff --git a/include/xsparse/level_capabilities/co_iteration.hpp b/include/xsparse/level_capabilities/co_iteration.hpp index dc76ca7..285a581 100644 --- a/include/xsparse/level_capabilities/co_iteration.hpp +++ b/include/xsparse/level_capabilities/co_iteration.hpp @@ -6,8 +6,37 @@ #include #include +#include + namespace xsparse::level_capabilities { + /** + * @brief The class template for Coiteration of level formats. + * + * @details Uses a generic function object F to compare elements + * from different sequences at the same position and returns a tuple of the + * minimum index and the corresponding elements from each sequence. + * + * @tparam F - A function object that is used to compare elements from different ranges. + * Its input is a tuple of booleans corresponding to each of the levels. The output is a boolean + * that is the result of the function. + * @tparam IK - The type of the first element of each range. + * @tparam PK - The type of the second element of each range. + * @tparam Levels - A tuple of level formats, where each level is itself a tuple of elements + * to be iterated. + * @tparam Is - A tuple of indices that is used to keep track of the current position in each + * level. + * + * @note Coiteration is only allowed through tuples of levels if the following criterion is met: + * If: + * 1. the levels are all ordered (i.e. has the `is_ordered == True` property) + * 2. if any of the level are do not have the is_ordered property, it must have the locate + * function, else return False. Then do a check that `m_comparisonHelper` defines + * a conjunctive merge (i.e. AND operation). + * Otherwise, coiteration is not allowed. + * + * This check is done automatically in the constructor, via the function ` + */ template class Coiterate; @@ -15,8 +44,8 @@ namespace xsparse::level_capabilities class Coiterate, std::tuple> { private: - std::tuple const m_levelsTuple; - F const m_comparisonHelper; + std::tuple const m_levelsTuple; // tuple of levels + F const m_comparisonHelper; // comparison function public: explicit inline Coiterate(F f, Levels&... levels) @@ -30,6 +59,71 @@ namespace xsparse::level_capabilities } } + template + consteval bool is_level_ordered() const noexcept + /** + * @brief Check if a single level is ordered or not at index I. + */ + { + return std::decay_t(m_levelsTuple))>::LevelProperties::is_ordered; + } + + template + consteval auto ordered_level_mask_impl(std::index_sequence) const noexcept + /** + * @brief Template recursion to construct tuples of true/false indicating ordered/unordered levels. + */ + { + return std::make_tuple(is_level_ordered()...); + } + + consteval auto ordered_level_mask() const noexcept + /** + * @brief Compute a tuple of true/false indicating ordered/unordered levels. + * + * @details If all levels are ordered, return a tuple of true. If any of the levels + * are unordered, return a tuple of true/false, where the true/false indicates + * ordered/unordered levels. Also does a compiler-time check that the levels meet the + * coiteration criteria given the function object `f`. This function IS compiler-evaluated. + * + * @return A tuple of true/false indicating ordered/unordered levels. + */ + { + return ordered_level_mask_impl(std::index_sequence_for()); + } + + // template + // consteval auto filter(Tuple t) + // /** + // * @brief Helper function to recursively filter out the levels that are ordered. + // */ + // { + // constexpr auto tup_size = std::tuple_size_v; + + // if constexpr(Index == tup_size) + // return std::tuple<>{}; + // else { + // constexpr auto v = std::get(t()); + // if constexpr(v) { + // constexpr auto level = std::get(m_levelsTuple); + // return std::tuple_cat(std::tuple(level), filter(t)); + // } else { + // return filter(t); + // } + // } + // } + + // constexpr auto ordered_levels() const noexcept + // /** + // * @brief Compute a tuple of the ordered levels in Coiterate. + // * + // * @return A tuple of the ordered levels in Coiterate. + // */ + // { + // constexpr auto levels = filter([&] {return ordered_level_mask();}); + // return levels; + // } + public: class coiteration_helper { @@ -38,7 +132,13 @@ namespace xsparse::level_capabilities std::tuple const m_i; PK const m_pkm1; std::tuple m_iterHelpers; - + // pull out first element of tuple and rest via unpacking... + // -> if level is not ordered, static_assert to make sure has locate_v and also + // static_assert over F(false,...) and F(true,, ...) + // -> if level is ordered, static_assert to make sure is_ordered is true and + // stati_ciassert over F(false, ...) + // have a tuple of only ordered levels stored as reference + // -> and then add in locate public: explicit inline coiteration_helper(Coiterate const& coiterate, std::tuple i, @@ -56,6 +156,7 @@ namespace xsparse::level_capabilities { private: coiteration_helper const& m_coiterHelper; + // TODO: add LevelCapabilities to hashed levels std::tuple iterators; IK min_ik; @@ -123,6 +224,8 @@ namespace xsparse::level_capabilities template inline auto locate(iter i) const noexcept + // TODO: if consteval: locate over unordered levels (using is_ordered) and + // deref other levels aka what is already here. { return (std::get<0>(*i) == min_ik) ? std::optional>( @@ -133,6 +236,9 @@ namespace xsparse::level_capabilities template inline void advance_iter(iter& i) const noexcept { + // TODO: anything that fails a conjunctive check, we must + // have is_ordered and we iterate into, otherwise we can + // locate into it. -> optimization for conjunctive operations if (static_cast(std::get<0>(*i)) == min_ik) { ++i; diff --git a/include/xsparse/level_capabilities/coordinate_iterate.hpp b/include/xsparse/level_capabilities/coordinate_iterate.hpp index 5e1e19c..66a2f9c 100755 --- a/include/xsparse/level_capabilities/coordinate_iterate.hpp +++ b/include/xsparse/level_capabilities/coordinate_iterate.hpp @@ -141,6 +141,7 @@ namespace xsparse::level_capabilities }; iteration_helper iter_helper(typename BaseTraits::I i, typename BaseTraits::PKM1 pkm1) + /*Create an instance of iteration_helper that manages the iteration process.*/ { return iteration_helper{ *static_cast(this), i, pkm1 }; } @@ -150,7 +151,7 @@ namespace xsparse::level_capabilities class coordinate_position_iterate { using BaseTraits = util::base_traits; - + public: class iteration_helper { @@ -269,6 +270,101 @@ namespace xsparse::level_capabilities return iteration_helper{ *static_cast(this), i, pkm1 }; } }; + + template