3#include <clingo/util/hash.hh>
10namespace CppClingo::Util::Record {
18 static constexpr auto tag = T;
32 static constexpr auto tag = T;
37 template <
class Val>
constexpr auto operator=(Val &&val)
const {
38 if constexpr (std::is_member_pointer_v<std::decay_t<Val>>) {
47template <
auto i,
auto needle,
auto tag,
auto... tags>
constexpr auto get_index_() {
48 if constexpr (needle == tag) {
56template <
auto tag,
class... Attrs>
constexpr auto get_index([[maybe_unused]] std::tuple<Attrs...> names) {
61template <
class Arg,
class... Attrs>
63 return ((std::remove_cvref_t<Arg>::tag == Attrs::tag) || ...);
68 return ((Arg::tag != Args::tag) && ...);
73 if constexpr (
sizeof...(Args) > 0) {
80template <
class Rec,
class... Args>
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) {
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>()};
94 return std::forward<typename Arg::Val>(arg.val);
96 }
else if constexpr (
sizeof...(args) == 0) {
97 return rec.template get_value<tag>();
99 return select_value<tag, Opt>(rec, args...);
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());
118template <
class Rec,
class... Args>
auto rewrite_record(Rec
const &x, Args &&...args) -> std::optional<Rec> {
119 if ((!args.val.has_value() && ...)) {
122 return update_record<true>(x, std::forward<Args>(args)...);
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...>{};
130 auto constexpr attr = std::get<n>(Rec::attributes());
131 if constexpr (attr.compare) {
132 return comparison_sequence<Rec, n + 1, I..., attr.tag>();
134 return comparison_sequence<Rec, n + 1, I...>();
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());
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());
153[[nodiscard]]
auto compare([[maybe_unused]] Base
const &a, [[maybe_unused]] Base
const &b) -> std::strong_ordering {
154 return std::strong_ordering::equal;
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) {
163 return compare<
Base, Tags...>(a, b);
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>()) && ...);
176template <
class Rec>
class Base {
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)();
184 return static_cast<Rec
const *
>(
this)->*mem;
188 template <
class... Args>
190 [[nodiscard]]
auto update(Args &&...args)
const {
191 return update_record(*
static_cast<Rec
const *
>(
this), std::forward<Args>(args)...);
194 template <
class... Args>
196 [[nodiscard]]
auto rewrite(Args &&...args)
const {
197 return rewrite_record(*
static_cast<Rec
const *
>(
this), std::forward<Args>(args)...);
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>());
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>());
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>());
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