diff options
-rw-r--r-- | src/entity.hpp | 25 | ||||
-rw-r--r-- | test/entity.cpp | 29 |
2 files changed, 49 insertions, 5 deletions
diff --git a/src/entity.hpp b/src/entity.hpp index 3c32ea23..51698651 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -6,6 +6,7 @@ #include <utility> #include <algorithm> #include <tuple> +#include <array> #include <Corrade/Containers/StringView.h> namespace floormat {} @@ -314,14 +315,28 @@ struct except_nth_<0, parameter_pack<As...>, X<T, Ts...>> { template<std::size_t N, typename T> using except_nth = typename except_nth_<N, parameter_pack<>, T>::type; -template<typename F, typename KeyT, typename Tuple> -struct sort_tuple_; - -template<typename F, typename KeyT, template<typename...> class Tuple, typename... Ts> -struct sort_tuple_<F, KeyT, Tuple<Ts...>> { +template<typename Tuple, auto KeyFn, auto Comp> +struct sort_tuple_ { + template<std::size_t... Is> + static consteval auto sort_indices(const Tuple& tuple, const std::index_sequence<Is...>&) { + std::array<std::size_t, sizeof...(Is)> indices = { Is..., }; + using KeyT = decltype(KeyFn(std::get<0>(tuple))); + std::array<KeyT, sizeof...(Is)> keys = { KeyFn(std::get<Is>(tuple))..., }; + std::sort(indices.begin(), indices.end(), [&](std::size_t a, std::size_t b) { return Comp(keys[a], keys[b]); }); + return indices; + } + template<auto Array> + struct helper { + template<std::size_t... Is> + static consteval auto do_sort(const Tuple& tuple, const std::index_sequence<Is...>&) { + return std::make_tuple(std::get<Array[Is]>(tuple)...); + } + }; }; + + } // namespace detail template<typename F, typename Tuple> diff --git a/test/entity.cpp b/test/entity.cpp index 838d18cd..e1bbb055 100644 --- a/test/entity.cpp +++ b/test/entity.cpp @@ -64,10 +64,39 @@ static constexpr bool test_visitor() return true; } +namespace test_sorting { + +template<std::size_t I> +struct item { + static constexpr std::size_t size = I-1; + std::array<char, I> data; + consteval item(const char(&str)[I]) { + std::copy(str, str+I, data.data()); + } + template<std::size_t J> + constexpr bool operator==(const item<J>& o) const { return data == o.data; } +}; + +static constexpr void test() +{ + using namespace floormat::entities::detail; + constexpr auto tuple = std::make_tuple(item{"bb"}, item{"aaa"}, item{"cccc"}, item{"d"}); + constexpr auto size = std::tuple_size_v<std::decay_t<decltype(tuple)>>; + constexpr auto key = [](const auto& x) constexpr { return StringView(x.data.data(), x.data.size()); }; + constexpr auto comp = [](auto a, auto b) constexpr { return a < b; }; + using Sort = sort_tuple_<std::decay_t<decltype(tuple)>, key, comp>; + constexpr auto indices = Sort::sort_indices(tuple, std::make_index_sequence<size>()); + constexpr auto tuple2 = Sort::helper<indices>::do_sort(tuple, std::make_index_sequence<size>()); + static_assert(tuple2 == std::make_tuple(item{"aaa"}, item{"bb"}, item{"cccc"}, item{"d"})); +} + +} // namespace test_sorting + void test_app::test_entity() { static_assert(test_accessors()); static_assert(test_visitor()); + test_sorting::test(); } namespace type_tests { |