-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrecord_internal.ixx
115 lines (101 loc) · 3.9 KB
/
record_internal.ixx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
module;
#include <array>
#include <algorithm>
#include <compare>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
export module Mitama.Data.Extensible.Record:Internal;
import Mitama.Utility.Extensible;
import Mitama.Data.Extensible.Named;
import Mitama.Data.Extensible.StaticString;
import Mitama.Data.Extensible.TypeList;
export namespace mitama {
// This is power of C++20
// FYI:
// https://stackoverflow.com/a/59567081
// https://twitter.com/yaito3014/status/1442645605860347904
// Named... :: class -> [usize; sizeof...(Named)]
// Receive named and returns array of index that sorted state.
template <class ...Named>
constexpr auto sorted_indices = []<std::size_t ...Indices>(std::index_sequence<Indices...>) {
using boxed_index = std::variant<std::integral_constant<std::size_t, Indices>...>;
if constexpr (sizeof...(Named) == 0) {
return boxed_index{};
}
else {
std::array arr{ boxed_index{std::in_place_index<Indices>}... };
auto key = [](boxed_index boxed) {
return std::visit([](auto i) {
return list_element_t<decltype(i)::value, type_list<Named...>>::str;
}, boxed);
};
auto cmp = [key](auto lhs, auto rhs) { return key(lhs) < key(rhs); };
std::sort(arr.begin(), arr.end(), cmp);
return arr;
}
}(std::index_sequence_for<Named...>{});
template <class, class...>
struct sort;
template <std::size_t ...I, class... Named>
struct sort<std::index_sequence<I...>, Named...> {
using type = type_list<list_element_t<sorted_indices<Named...>[I].index(), type_list<Named...>>...>;
};
// Returns sorted `Named...` packed into `type_list`.
// [ Note:
// ```cpp
// using A = decltype("a"_ <= 1);
// using B = decltype("b"_ <= 2);
// using C = decltype("c"_ <= 3);
//
// using expected = type_list<A, B, C>;
//
// static_assert( std::same_as<expected, sorted<C, A, B>>); // OK
// ```
// -- end note ]
template <class ...Named>
using sorted = sort<std::index_sequence_for<Named...>, Named...>::type;
template <class, class, class>
struct difference_impl;
template <class Head, class ...Tail, class... Result, class ...ToRemove>
struct difference_impl<type_list<Head, Tail...>, type_list<ToRemove...>, type_list<Result...>> {
using type = std::conditional_t<
((Head::str == ToRemove::str) || ...),
typename difference_impl<type_list<Tail...>, type_list<ToRemove...>, type_list<Result...>>::type,
typename difference_impl<type_list<Tail...>, type_list<ToRemove...>, type_list<Result..., Head>>::type
>;
};
template <class... Result, class ...ToRemove>
struct difference_impl<type_list<>, type_list<ToRemove...>, type_list<Result...>> {
using type = type_list<Result...>;
};
// A\B
template <class A, class B>
using difference = difference_impl<A, B, type_list<>>::type;
template <class List, static_string ...ToRemove>
using erased = difference<List, type_list<named<ToRemove>...>>;
template <class First, class Second>
concept equivalent_to = []<class ...L, class ...R>(type_list<L...>, type_list<R...>){
if constexpr (sizeof...(L) != sizeof...(R)) return false;
else {
return ((L::str == R::str) && ...);
}
}(default_v<sorted<First>>, default_v<sorted<Second>>);
template <class, class>
struct is_superset_of : std::false_type {};
template <template <class...> class Record, class... A, class... B>
struct is_superset_of<Record<A...>, Record<B...>>
: std::conjunction<
std::is_same<type_list<>, difference<type_list<B...>, type_list<A...>>>,
std::is_convertible<
typename Record<A...>::template typeof<B::tag>,
typename Record<B...>::template typeof<B::tag>
>...
>
{};
// B º A
template <class A, class B>
concept superset_of = is_superset_of<std::remove_cvref_t<A>, std::remove_cvref_t<B>>::value;
}