Clingo
Loading...
Searching...
No Matches
record.hh
1#pragma once
2
3#include <clingo/util/hash.hh>
4
5#include <optional>
6#include <tuple>
7#include <type_traits>
8#include <utility>
9
10namespace CppClingo::Util::Record {
11
14
16template <auto T, auto C, class V> struct AttributeValue {
18 static constexpr auto tag = T;
20 static constexpr auto compare = C;
22 using Val = V;
24 constexpr AttributeValue(Val val) : val(std::forward<Val>(val)) {}
27};
28
30template <auto T, bool C = true> struct AttributeName {
32 static constexpr auto tag = T;
34 static constexpr auto compare = C;
36 // NOLINTNEXTLINE(cppcoreguidelines-c-copy-assignment-signature)
37 template <class Val> constexpr auto operator=(Val &&val) const {
38 if constexpr (std::is_member_pointer_v<std::decay_t<Val>>) {
39 return AttributeValue<tag, compare, Val>{std::forward<Val>(val)};
40 } else {
41 return AttributeValue<tag, compare, Val &&>{std::forward<Val>(val)};
42 }
43 }
44};
45
47template <auto i, auto needle, auto tag, auto... tags> constexpr auto get_index_() {
48 if constexpr (needle == tag) {
49 return i;
50 } else {
51 return get_index_<i + 1, needle, tags...>();
52 }
53}
54
56template <auto tag, class... Attrs> constexpr auto get_index([[maybe_unused]] std::tuple<Attrs...> names) {
57 return get_index_<0, tag, Attrs::tag...>();
58}
59
61template <class Arg, class... Attrs>
62constexpr auto is_valid_argument([[maybe_unused]] std::tuple<Attrs...> attrs) -> bool {
63 return ((std::remove_cvref_t<Arg>::tag == Attrs::tag) || ...);
64}
65
67template <class Arg, class... Args> constexpr auto is_unique_argument() {
68 return ((Arg::tag != Args::tag) && ...);
69}
70
72template <class Arg, class... Args> constexpr auto check_unique_arguments() {
73 if constexpr (sizeof...(Args) > 0) {
74 return is_unique_argument<Arg, Args...>() && check_unique_arguments<Args...>();
75 }
76 return true;
77}
78
80template <class Rec, class... Args>
81concept ValidArguments = (is_valid_argument<Args>(Rec::attributes()) && ...) && check_unique_arguments<Args...>();
82
87template <auto tag, bool Opt, class Rec, class Arg, class... Args>
88auto select_value(Rec const &rec, Arg &arg, Args &...args) -> decltype(auto) {
89 if constexpr (tag == Arg::tag) {
90 if constexpr (Opt) {
91 using M = std::decay_t<decltype(rec.template get_value<tag>())>;
92 return arg.val ? M{*std::forward<typename Arg::Val>(arg.val)} : M{rec.template get_value<tag>()};
93 } else {
94 return std::forward<typename Arg::Val>(arg.val);
95 }
96 } else if constexpr (sizeof...(args) == 0) {
97 return rec.template get_value<tag>();
98 } else {
99 return select_value<tag, Opt>(rec, args...);
100 }
101}
102
107// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
108template <bool Opt = false, typename Rec, typename... Args> auto update_record(Rec const &x, Args &&...args) -> Rec {
109 return [&]<class... Attrs>([[maybe_unused]] std::tuple<Attrs...> attrs) {
110 return Rec{select_value<Attrs::tag, Opt>(x, args...)...};
111 }(Rec::attributes());
112}
113
118template <class Rec, class... Args> auto rewrite_record(Rec const &x, Args &&...args) -> std::optional<Rec> {
119 if ((!args.val.has_value() && ...)) {
120 return std::nullopt;
121 }
122 return update_record<true>(x, std::forward<Args>(args)...);
123}
124
126template <class Rec, size_t n, size_t... I> [[nodiscard]] static constexpr auto comparison_sequence() {
127 if constexpr (n == std::tuple_size_v<std::remove_cvref_t<decltype(Rec::attributes())>>) {
128 return std::index_sequence<I...>{};
129 } else {
130 auto constexpr attr = std::get<n>(Rec::attributes());
131 if constexpr (attr.compare) {
132 return comparison_sequence<Rec, n + 1, I..., attr.tag>();
133 } else {
134 return comparison_sequence<Rec, n + 1, I...>();
135 }
136 }
137}
138
139namespace Comp {
140
142template <class T, size_t E> auto operator==(std::span<T, E> const &a, std::span<T, E> const &b) {
143 return std::equal(a.begin(), a.end(), b.begin(), b.end());
144}
145
147template <class T, size_t E> auto operator<=>(std::span<T, E> const &a, std::span<T, E> const &b) {
148 return std::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end());
149}
150
152template <class Base>
153[[nodiscard]] auto compare([[maybe_unused]] Base const &a, [[maybe_unused]] Base const &b) -> std::strong_ordering {
154 return std::strong_ordering::equal;
155}
156
158template <class Base, auto Tag, auto... Tags>
159[[nodiscard]] auto compare(Base const &a, Base const &b) -> std::strong_ordering {
160 if (auto comp = a.template get_value<Tag>() <=> b.template get_value<Tag>(); comp != 0) {
161 return comp;
162 }
163 return compare<Base, Tags...>(a, b);
164}
165
167template <class Base, auto... Tags> [[nodiscard]] auto equal(Base const &a, Base const &b) -> bool {
168 return ((a.template get_value<Tags>() == b.template get_value<Tags>()) && ...);
169}
170
171} // namespace Comp
172
176template <class Rec> class Base {
177 public:
179 template <auto tag> [[nodiscard]] auto get_value() const -> decltype(auto) {
180 static constexpr auto mem = std::get<get_index<tag>(Rec::attributes())>(Rec::attributes()).val;
181 if constexpr (std::is_member_function_pointer_v<decltype(mem)>) {
182 return (static_cast<Rec const *>(this)->*mem)();
183 } else {
184 return static_cast<Rec const *>(this)->*mem;
185 }
186 }
188 template <class... Args>
189 requires ValidArguments<Rec, Args...>
190 [[nodiscard]] auto update(Args &&...args) const {
191 return update_record(*static_cast<Rec const *>(this), std::forward<Args>(args)...);
192 }
194 template <class... Args>
195 requires ValidArguments<Rec, Args...>
196 [[nodiscard]] auto rewrite(Args &&...args) const {
197 return rewrite_record(*static_cast<Rec const *>(this), std::forward<Args>(args)...);
198 }
199
201 [[nodiscard]] auto equal(Base const &other) const -> bool {
202 return [&]<auto... Tags>(std::index_sequence<Tags...>) {
203 return Comp::equal<Base, Tags...>(*this, other);
204 }(comparison_sequence<Rec, 0>());
205 }
207 [[nodiscard]] auto compare(Base const &other) const -> std::strong_ordering {
208 return [&]<auto... Tags>(std::index_sequence<Tags...>) {
209 return Comp::compare<Base, Tags...>(*this, other);
210 }(comparison_sequence<Rec, 0>());
211 }
213 [[nodiscard]] auto hash() const -> size_t {
214 return [&]<auto... Tags>(std::index_sequence<Tags...>) {
215 return value_hash_record<Rec>(get_value<Tags>()...);
216 }(comparison_sequence<Rec, 0>());
217 }
218};
219
221
222} // namespace CppClingo::Util::Record
Record base class to enable keyword argument based record updates.
Definition record.hh:176
auto compare(Base const &other) const -> std::strong_ordering
Compare to records.
Definition record.hh:207
auto rewrite(Args &&...args) const
See rewrite_record().
Definition record.hh:196
auto get_value() const -> decltype(auto)
Get the attribute with the given tag.
Definition record.hh:179
auto update(Args &&...args) const
See update_record().
Definition record.hh:190
auto equal(Base const &other) const -> bool
Equality compare to records.
Definition record.hh:201
auto hash() const -> size_t
Compute the hash of the record.
Definition record.hh:213
Concept requiring arguments to be valid.
Definition record.hh:81
Base
The base of a number.
Definition number.hh:17
@ equal
The equal to symbol (=).
constexpr auto is_unique_argument()
Check if an argument is unique.
Definition record.hh:67
constexpr auto get_index(std::tuple< Attrs... > names)
Get the index of an attribute tag.
Definition record.hh:56
constexpr auto check_unique_arguments()
Check if all arguments are unique.
Definition record.hh:72
auto select_value(Rec const &rec, Arg &arg, Args &...args) -> decltype(auto)
Select the argument with the given tag among the given arguments.
Definition record.hh:88
auto update_record(Rec const &x, Args &&...args) -> Rec
Update a record by returning a copy with the given arguments updated.
Definition record.hh:108
constexpr auto is_valid_argument(std::tuple< Attrs... > attrs) -> bool
Check if an argument is valid.
Definition record.hh:62
constexpr auto get_index_()
Get the index of an attribute tag.
Definition record.hh:47
auto rewrite_record(Rec const &x, Args &&...args) -> std::optional< Rec >
Rewrite a record by returning a copy with the given arguments updated.
Definition record.hh:118
A named attribute.
Definition record.hh:30
static constexpr auto compare
Whether the attribute is relevant for comparison.
Definition record.hh:34
static constexpr auto tag
The tag of the attribute.
Definition record.hh:32
constexpr auto operator=(Val &&val) const
Helper to bind an attribute to a value.
Definition record.hh:37
Helper to capture a value bound by an attribute.
Definition record.hh:16
constexpr AttributeValue(Val val)
Construct a bound attribute.
Definition record.hh:24
Val val
The value of the attribute.
Definition record.hh:26
static constexpr auto tag
The tag of the attribute.
Definition record.hh:18
static constexpr auto compare
Whether the attribute is relevant for comparison.
Definition record.hh:20
V Val
The type of the stored value.
Definition record.hh:22