Clingo
Loading...
Searching...
No Matches
immutable_value.hh
1#pragma once
2
3#include <cstddef>
4#include <utility>
5
6#ifdef __clang_analyzer__
7#include <memory>
8#endif
9
10namespace CppClingo::Util {
11
14
19template <typename T> class immutable_value {
20 public:
22 using element_type = T;
23
25 constexpr immutable_value() noexcept = default;
26
28 constexpr immutable_value(std::nullptr_t) noexcept {}
29
31 // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
32 template <class U>
33 requires(!std::same_as<std::remove_cvref_t<U>, immutable_value>)
34 immutable_value(U &&value) : immutable_value{std::in_place, std::forward<U>(value)} {}
35
36#ifdef __clang_analyzer__
37 template <class... Args>
38 immutable_value([[maybe_unused]] std::in_place_t tag, Args &&...args)
39 : data_{std::make_shared<T>(std::forward<Args>(args)...)} {}
40 immutable_value(immutable_value const &other) noexcept = default;
41 immutable_value(immutable_value &&other) noexcept = default;
42 auto operator=(immutable_value const &other) noexcept -> immutable_value & = default;
43 auto operator=(immutable_value &&other) noexcept -> immutable_value & = default;
44 ~immutable_value() noexcept = default;
45#else
47 template <class... Args>
48 immutable_value([[maybe_unused]] std::in_place_t tag, Args &&...args)
49 : data_{new data_type(std::forward<Args>(args)...)} {}
50
52 immutable_value(immutable_value const &other) noexcept : data_{other.data_} { inc_(); }
53
55 immutable_value(immutable_value &&other) noexcept : data_{std::exchange(other.data_, nullptr)} {}
56
58 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
59 auto operator=(immutable_value const &other) noexcept -> immutable_value & {
60 other.inc_();
61 dec_();
62 data_ = other.data_;
63 return *this;
64 }
65
67 auto operator=(immutable_value &&other) noexcept -> immutable_value & {
68 if (this != &other) {
69 dec_();
70 data_ = std::exchange(other.data_, nullptr);
71 }
72 return *this;
73 }
74
76 ~immutable_value() noexcept { dec_(); }
77#endif
78
80 [[nodiscard]] auto has_value() const noexcept -> bool { return data_ != nullptr; }
81
83 [[nodiscard]] explicit operator bool() const noexcept { return has_value(); }
84
86 [[nodiscard]] auto get() const noexcept -> element_type const & {
87#ifdef __clang_analyzer__
88 return *data_;
89#else
90 return data_->value;
91#endif
92 }
93
95 [[nodiscard]] auto operator*() const noexcept -> element_type const & { return get(); }
96
98 auto operator->() const noexcept -> element_type const * { return &get(); }
99
101 [[nodiscard]] operator T const &() const noexcept { return get(); }
102
103 private:
104#ifdef __clang_analyzer__
105 std::shared_ptr<T> data_;
106#else
107 struct data_type {
108 template <class... Args> data_type(Args &&...args) : value{std::forward<Args>(args)...} {}
109 size_t refs = 1;
110 element_type value;
111 };
112
113 void inc_() const noexcept {
114 if (data_ != nullptr) {
115 ++data_->refs;
116 }
117 }
118
119 void dec_() noexcept {
120 if (data_ != nullptr) {
121 --data_->refs;
122 if (data_->refs == 0) {
123 delete data_;
124 }
125 data_ = nullptr;
126 }
127 }
128
129 data_type *data_ = nullptr;
130#endif
131};
132
134template <typename U, typename... Args> auto make_immutable(Args &&...args) -> immutable_value<U> {
135 static_assert(std::is_constructible_v<U, Args...>);
136 return immutable_value<U>{std::in_place, std::forward<Args>(args)...};
137}
138
142template <class X, class Y>
143[[nodiscard]] auto operator==(const immutable_value<X> &lhs, const immutable_value<Y> &rhs) -> bool {
144 if (lhs && rhs) {
145 return *lhs == *rhs;
146 }
147 return lhs.get() == rhs.get();
148}
149
153template <class X, class Y>
154[[nodiscard]] auto operator<=>(const immutable_value<X> &lhs, const immutable_value<Y> &rhs) {
155 if (lhs && rhs) {
156 return *lhs <=> *rhs;
157 }
158 return lhs.get() <=> rhs.get();
159}
160
162
163} // namespace CppClingo::Util
An immutable value imlementation.
Definition immutable_value.hh:19
auto operator->() const noexcept -> element_type const *
Get the member of pointer.
Definition immutable_value.hh:98
T element_type
The type of the stored pointer.
Definition immutable_value.hh:22
auto get() const noexcept -> element_type const &
Get the value.
Definition immutable_value.hh:86
constexpr immutable_value() noexcept=default
Construct a null pointer.
auto has_value() const noexcept -> bool
Check if the value is engaged.
Definition immutable_value.hh:80
immutable_value(std::in_place_t tag, Args &&...args)
Construct a value in place.
Definition immutable_value.hh:48
~immutable_value() noexcept
Decrement reference count and delete contained pointer if zero.
Definition immutable_value.hh:76
immutable_value(immutable_value &&other) noexcept
Move construct an immutable value.
Definition immutable_value.hh:55
auto operator=(immutable_value const &other) noexcept -> immutable_value &
Copy assign an immutable value.
Definition immutable_value.hh:59
immutable_value(immutable_value const &other) noexcept
Copy an immutable value.
Definition immutable_value.hh:52
auto operator*() const noexcept -> element_type const &
Get the value.
Definition immutable_value.hh:95
auto operator=(immutable_value &&other) noexcept -> immutable_value &
Move assign an immutable value.
Definition immutable_value.hh:67
immutable_value(U &&value)
Construct a value.
Definition immutable_value.hh:34
auto make_immutable(Args &&...args) -> immutable_value< U >
Construct an immutable value.
Definition immutable_value.hh:134
auto operator==(const immutable_value< X > &lhs, const immutable_value< Y > &rhs) -> bool
Compare two immutable values.
Definition immutable_value.hh:143