summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/entity.hpp25
-rw-r--r--test/entity.cpp29
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 {