AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
values.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include <type_traits>
15#include <cassert>
16#include <utility>
17#include <functional>
18#include <optional>
19#include <glm/glm.hpp>
20#include <AUI/Common/SharedPtrTypes.h>
21#include <AUI/Common/AOptional.h>
22#include <AUI/Thread/AMutex.h>
23#include <AUI/Traits/concepts.h>
24
25namespace aui {
40 struct noncopyable {
41 noncopyable() = default;
42 noncopyable(const noncopyable&) = delete;
43 noncopyable& operator=(const noncopyable&) = delete;
44 };
45
46
51 template<typename T>
52 class assert_not_used_when_null {
53 private:
54 T mValue;
55
56 public:
57 assert_not_used_when_null(T value) noexcept: mValue(std::move(value)) {}
58
59 template<typename AnyType>
60 operator AnyType() noexcept {
61 if constexpr(!std::is_same_v<AnyType, bool>) {
62 AUI_ASSERTX(mValue != nullptr, "value is used when null");
63 }
64 return AnyType(mValue);
65 }
66
67 [[nodiscard]]
68 T value() const noexcept {
69 return mValue;
70 }
71
72 template<typename AnyType>
73 bool operator==(const AnyType& v) const noexcept {
74 return mValue == v;
75 }
76
77 template<typename AnyType>
78 bool operator!=(const AnyType& v) const noexcept {
79 return mValue != v;
80 }
81 };
82
83
84 template<typename T>
85 struct non_null_lateinit {
86 private:
87 void checkForNull() const { AUI_ASSERTX(value != nullptr, "this value couldn't be null"); }
88 public:
89 T value;
90 non_null_lateinit() {
91
92 }
93
94 non_null_lateinit(T value): value(std::move(value)) {
95 checkForNull();
96 }
97
98 operator T() const noexcept {
99 checkForNull();
100 return value;
101 }
102 auto operator->() const {
103 checkForNull();
104 return &*value;
105 }
106 };
107
108 template<typename T>
109 struct non_null: non_null_lateinit<T> {
110 non_null(T value): non_null_lateinit<T>(std::move(value)) {}
111 };
112
126 template<typename T>
127 struct no_escape {
128 static_assert(!std::is_reference<T>::value, "use undecorated type (without reference)");
129 static_assert(!std::is_pointer_v<T>, "use undecorated type (without pointer)");
130 private:
131 T* value;
132
133 public:
134 no_escape(T& value): value(&value) {
135 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
136 }
137 // referring to a temporary value; no_escape should never be used anything else than as argument
138 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
139 no_escape(T&& value): value(&value) {
140 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
141 }
142 no_escape(T* value): value(value) {
143 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
144 }
145
146 no_escape(const _<T>& value): value(&*value) {
147 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
148 }
149 no_escape(const _unique<T>& value): value(&*value) {
150 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
151 }
152
153 template<typename DerivedFromT, std::enable_if_t<std::is_base_of_v<T, DerivedFromT> && !std::is_same_v<DerivedFromT, T>, bool> = true>
154 no_escape(const _<DerivedFromT>& value): value(&*value) {
155 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
156 }
157
158 template<typename DerivedFromT, std::enable_if_t<std::is_base_of_v<T, DerivedFromT> && !std::is_same_v<DerivedFromT, T>, bool> = true>
159 no_escape(const _unique<DerivedFromT>& value): value(&*value) {
160 AUI_ASSERTX(no_escape::value != nullptr, "the argument could not be null");
161 }
162
163 [[nodiscard]]
164 T* ptr() const noexcept {
165 return value;
166 }
167
168 T* operator->() const noexcept {
169 return value;
170 }
171
172 T& operator*() const noexcept {
173 return *value;
174 }
175 };
176
181 template<typename T = void>
182 struct lazy {
183 private:
184 mutable AOptional<T> value;
185 std::function<T()> initializer;
186 public:
187 template<typename Factory, std::enable_if_t<std::is_invocable_r_v<T, Factory>, bool> = true>
188 lazy(Factory&& initializer) noexcept : initializer(std::forward<Factory>(initializer)) {}
189
190 lazy(const lazy<T>& other) noexcept: value(other.value), initializer(other.initializer) {}
191 lazy(lazy<T>&& other) noexcept: value(std::move(other.value)), initializer(std::move(other.initializer)) {}
192
193 T& get() {
194 if (!value) {
195 value = initializer();
196 }
197 return *value;
198 }
199 const T& get() const {
200 return const_cast<lazy<T>*>(this)->get();
201 }
202
203 operator T&() {
204 return get();
205 }
206 operator const T&() const {
207 return get();
208 }
209
210 T& operator*() {
211 return get();
212 }
213 const T& operator*() const {
214 return get();
215 }
216
217 T* operator->() {
218 return &get();
219 }
220 T const * operator->() const {
221 return &get();
222 }
223
224 lazy<T>& operator=(T&& t) {
225 value = std::move(t);
226 return *this;
227 }
228 lazy<T>& operator=(const T& t) {
229 value = t;
230 return *this;
231 }
232
233 void reset() {
234 value.reset();
235 }
236
237 explicit operator bool() const noexcept requires requires { !aui::same_as<T, bool>; } {
238 return hasValue();
239 }
240
241 [[nodiscard]]
242 bool hasValue() const noexcept {
243 return value.hasValue();
244 }
245 };
246
251 template<>
252 struct lazy<void> {
253 private:
254 mutable bool value = false;
255 std::function<void()> initializer;
256 public:
257 template<typename Factory, std::enable_if_t<std::is_invocable_r_v<void, Factory>, bool> = true>
258 lazy(Factory&& initializer) noexcept : initializer(std::forward<Factory>(initializer)) {}
259
260 lazy(const lazy<void>& other) noexcept: value(other.value), initializer(other.initializer) {}
261 lazy(lazy<void>&& other) noexcept: value(other.value), initializer(std::move(other.initializer)) {}
262
263 void get() {
264 if (!value) {
265 value = true;
266 initializer();
267 }
268 }
269 void get() const {
270 return const_cast<lazy<void>*>(this)->get();
271 }
272
273 void operator*() {
274 return get();
275 }
276 const void operator*() const {
277 return get();
278 }
279
280
281 void reset() {
282 value = false;
283 }
284
285 [[nodiscard]]
286 bool hasValue() const noexcept {
287 return value;
288 }
289 };
290
296 template<typename T>
297 struct atomic_lazy {
298 private:
299 mutable AMutex sync;
300 mutable AOptional<T> value;
301 std::function<T()> initializer;
302 public:
303 template<typename Factory, std::enable_if_t<std::is_invocable_r_v<T, Factory>, bool> = true>
304 atomic_lazy(Factory&& initializer) : initializer(std::forward<Factory>(initializer)) {}
305
306 atomic_lazy(const atomic_lazy<T>& other) {
307 std::unique_lock lock(other.sync);
308 value = other.value;
309 initializer = other.initializer;
310 }
311 atomic_lazy(atomic_lazy<T>&& other) noexcept {
312 std::unique_lock lock(other.sync);
313 value = std::move(other.value);
314 initializer = std::move(other.initializer);
315 }
316
317 T& get() {
318 if (!value) {
319 std::unique_lock lock(sync);
320 if (!value) {
321 value = initializer();
322 }
323 }
324 return *value;
325 }
326 const T& get() const {
327 return const_cast<atomic_lazy<T>*>(this)->get();
328 }
329
330 operator T&() {
331 return get();
332 }
333 operator const T&() const {
334 return get();
335 }
336
337 T& operator*() {
338 return get();
339 }
340 const T& operator*() const {
341 return get();
342 }
343
344 T* operator->() {
345 return &get();
346 }
347 T const * operator->() const {
348 return &get();
349 }
350
351 atomic_lazy<T>& operator=(T&& t) {
352 std::unique_lock lock(sync);
353 value = std::move(t);
354 return *this;
355 }
356
357 atomic_lazy<T>& operator=(const T& t) {
358 std::unique_lock lock(sync);
359 value = t;
360 return *this;
361 }
362
363 void reset() {
364 std::unique_lock lock(sync);
365 value.reset();
366 }
367
368 [[nodiscard]]
369 bool hasValue() const noexcept {
370 std::unique_lock lock(sync);
371 return value.hasValue();
372 }
373 };
374
375 namespace constraint {
382 template<typename T>
383 class avoid_copy {
384 private:
385 T* value;
386
387 public:
388 avoid_copy(T& value): value(&value) { // implicit initializer
389
390 }
391 operator T&() const { // implicit conversion
392 return *value;
393 }
394
395 T& operator*() const { // std dereference
396 return *value;
397 }
398 T* operator->() const { // allow pointer-style calls
399 return value;
400 }
401 };
402
409 template<typename T>
410 class move_only {
411 private:
412 T value;
413
414 public:
415 move_only(T&& rhs): value(std::move(rhs)) {
416
417 }
418 move_only(move_only&& rhs) noexcept: value(std::move(rhs.value)) {
419
420 }
421 move_only(const move_only&) = delete;
422
423 operator const T&() const {
424 return value;
425 }
426 operator T&() {
427 return value;
428 }
429
430 const T& operator*() const {
431 return value;
432 }
433 const T* operator->() const {
434 return &value;
435 }
436 T* operator->() {
437 return &value;
438 }
439 };
440 }
441
442
443
451 template<aui::arithmetic UnderlyingType,
452 auto /* UnderlyingType*/ min,
453 auto /* UnderlyingType*/ max> // min and max are defined auto because some static analyzers won't work with
454 // float value template arguments
455 requires aui::convertible_to<decltype(min), UnderlyingType> && aui::convertible_to<decltype(max), UnderlyingType>
456 struct ranged_number {
457 public:
458 static constexpr auto MIN = min;
459 static constexpr auto MAX = max;
460
461 ranged_number(UnderlyingType value): value(glm::clamp(value, static_cast<UnderlyingType>(min), static_cast<UnderlyingType>(max))) {}
462 ranged_number(): value(min) {}
463
464 operator UnderlyingType() const { // make it possible to work with ranged_number like with the underlying type
465 return value;
466 }
467
468 private:
469 UnderlyingType value;
470 };
471
472 using float_within_0_1 = ranged_number<float, 0, 1>;
473}
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition AOptional.h:32
Definition Factory.h:18
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:178
Concept shortcut to std::is_arithmetic_v.
Definition concepts.h:145
Definition concepts.h:42
Definition concepts.h:70
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition Assert.h:74
Basic syscall-based synchronization primitive.
Definition AMutex.h:33
Clamps the possible values for a number to the specified range: [min;max].
Definition values.h:456