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> immutable_value(U &&value) : immutable_value{std::in_place, std::forward<U>(value)} {}
33
34#ifdef __clang_analyzer__
35 template <class... Args>
36 immutable_value([[maybe_unused]] std::in_place_t tag, Args &&...args)
37 : data_{std::make_shared<T>(std::forward<Args>(args)...)} {}
38 immutable_value(immutable_value const &other) noexcept = default;
39 immutable_value(immutable_value &&other) noexcept = default;
40 auto operator=(immutable_value const &other) noexcept -> immutable_value & = default;
41 auto operator=(immutable_value &&other) noexcept -> immutable_value & = default;
42 ~immutable_value() noexcept = default;
43#else
45 template <class... Args>
46 immutable_value([[maybe_unused]] std::in_place_t tag, Args &&...args)
47 : data_{new data_type(std::forward<Args>(args)...)} {}
48
50 immutable_value(immutable_value const &other) noexcept : data_{other.data_} { inc_(); }
51
53 immutable_value(immutable_value &&other) noexcept : data_{std::exchange(other.data_, nullptr)} {}
54
56 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
57 auto operator=(immutable_value const &other) noexcept -> immutable_value & {
58 other.inc_();
59 dec_();
60 data_ = other.data_;
61 return *this;
62 }
63
65 auto operator=(immutable_value &&other) noexcept -> immutable_value & {
66 if (this != &other) {
67 dec_();
68 data_ = std::exchange(other.data_, nullptr);
69 }
70 return *this;
71 }
72
74 ~immutable_value() noexcept { dec_(); }
75#endif
76
78 [[nodiscard]] auto has_value() const noexcept -> bool { return data_ != nullptr; }
79
81 [[nodiscard]] explicit operator bool() const noexcept { return has_value(); }
82
84 [[nodiscard]] auto get() const noexcept -> element_type const & {
85#ifdef __clang_analyzer__
86 return *data_;
87#else
88 return data_->value;
89#endif
90 }
91
93 [[nodiscard]] auto operator*() const noexcept -> element_type const & { return get(); }
94
96 auto operator->() const noexcept -> element_type const * { return &get(); }
97
99 [[nodiscard]] operator T const &() const noexcept { return get(); }
100
101 private:
102#ifdef __clang_analyzer__
103 std::shared_ptr<T> data_;
104#else
105 struct data_type {
106 template <class... Args> data_type(Args &&...args) : value{std::forward<Args>(args)...} {}
107 size_t refs = 1;
108 element_type value;
109 };
110
111 void inc_() const noexcept {
112 if (data_ != nullptr) {
113 ++data_->refs;
114 }
115 }
116
117 void dec_() noexcept {
118 if (data_ != nullptr) {
119 --data_->refs;
120 if (data_->refs == 0) {
121 delete data_;
122 }
123 data_ = nullptr;
124 }
125 }
126
127 data_type *data_ = nullptr;
128#endif
129};
130
132template <typename U, typename... Args> auto make_immutable(Args &&...args) -> immutable_value<U> {
133 static_assert(std::is_constructible_v<U, Args...>);
134 return immutable_value<U>{std::in_place, std::forward<Args>(args)...};
135}
136
140template <class X, class Y>
141[[nodiscard]] auto operator==(const immutable_value<X> &lhs, const immutable_value<Y> &rhs) -> bool {
142 if (lhs && rhs) {
143 return *lhs == *rhs;
144 }
145 return lhs.get() == rhs.get();
146}
147
151template <class X, class Y>
152[[nodiscard]] auto operator<=>(const immutable_value<X> &lhs, const immutable_value<Y> &rhs) {
153 if (lhs && rhs) {
154 return *lhs <=> *rhs;
155 }
156 return lhs.get() <=> rhs.get();
157}
158
160
161} // 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:96
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:84
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:78
immutable_value(std::in_place_t tag, Args &&...args)
Construct a value in place.
Definition immutable_value.hh:46
~immutable_value() noexcept
Decrement reference count and delete contained pointer if zero.
Definition immutable_value.hh:74
immutable_value(immutable_value &&other) noexcept
Move construct an immutable value.
Definition immutable_value.hh:53
immutable_value(U &&value)
Construct a value.
Definition immutable_value.hh:32
auto operator=(immutable_value const &other) noexcept -> immutable_value &
Copy assign an immutable value.
Definition immutable_value.hh:57
immutable_value(immutable_value const &other) noexcept
Copy an immutable value.
Definition immutable_value.hh:50
auto operator*() const noexcept -> element_type const &
Get the value.
Definition immutable_value.hh:93
auto operator=(immutable_value &&other) noexcept -> immutable_value &
Move assign an immutable value.
Definition immutable_value.hh:65
auto make_immutable(Args &&...args) -> immutable_value< U >
Construct an immutable value.
Definition immutable_value.hh:132
auto operator==(const immutable_value< X > &lhs, const immutable_value< Y > &rhs) -> bool
Compare two immutable values.
Definition immutable_value.hh:141