HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
polymorphic_value.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/os_detect.hpp"
7#include "TTauri/Foundation/assert.hpp"
8#include <array>
9#include <memory>
10#include <type_traits>
11
12namespace tt {
13
14template<typename T>
15constexpr bool should_call_destructor() {
16 return std::is_destructible_v<T> && (!std::is_trivially_destructible_v<T> || std::has_virtual_destructor_v<T>);
17}
18
19template<typename T, size_t S>
21private:
22 using base_type = T;
23 static constexpr size_t capacity = S;
24
25 alignas(16) std::array<std::byte,capacity> _data;
26 bool has_value;
27
28public:
29 polymorphic_value() : has_value(false) {}
30
32 if constexpr (should_call_destructor<T>()) {
33 if (has_value) {
34 std::destroy_at(this->operator->());
35 }
36 }
37 }
38
39 polymorphic_value(polymorphic_value const &other) = delete;
40 polymorphic_value(polymorphic_value &&other) = delete;
41 polymorphic_value &operator=(polymorphic_value const &other) = delete;
42 polymorphic_value &operator=(polymorphic_value &&other) = delete;
43
44 template<typename O>
45 std::enable_if_t<std::is_base_of_v<base_type, O>, polymorphic_value> &operator=(O const &other) {
46 static_assert(sizeof(O) <= capacity, "Assignment of a type larger than capacity of polymorphic_value");
47 reset();
48 new(data()) O(other);
49
50 if constexpr (should_call_destructor<T>()) {
51 has_value = true;
52 }
53 return *this;
54 }
55
56 template<typename O>
57 std::enable_if_t<std::is_base_of_v<base_type, O>, polymorphic_value> &operator=(O &&other) {
58 static_assert(sizeof(O) <= capacity, "Assignment of a type larger than capacity of polymorphic_value");
59 reset();
60 new(data()) O(std::forward<O>(other));
61
62 if constexpr (should_call_destructor<T>()) {
63 has_value = true;
64 }
65 return *this;
66 }
67
68 template<typename O, typename... Args>
69 std::enable_if_t<std::is_base_of_v<base_type, O>, void> emplace(Args &&... args) {
70 static_assert(sizeof(O) <= capacity, "Assignment of a type larger than capacity of polymorphic_value");
71 reset();
72 new(data()) O(std::forward<Args>(args)...);
73
74 if constexpr (should_call_destructor<T>()) {
75 has_value = true;
76 }
77 }
78
79 void reset() noexcept {
80 if constexpr (should_call_destructor<T>()) {
81 if (has_value) {
82 std::destroy_at(this->operator->());
83 }
84 has_value = false;
85 }
86 }
87
88 void *data() noexcept {
89 return reinterpret_cast<void *>(_data.data());
90 }
91
92 void const *data() const noexcept {
93 return reinterpret_cast<void const *>(_data.data());
94 }
95
96 T const &operator*() const noexcept {
97 if constexpr (should_call_destructor<T>()) {
98 tt_assert(has_value);
99 }
100 return *reinterpret_cast<T const *>(data());
101 }
102
103 T &operator*() noexcept {
104 if constexpr (should_call_destructor<T>()) {
105 tt_assert(has_value);
106 }
107 return *reinterpret_cast<T *>(data());
108 }
109
110 T const *operator->() const noexcept {
111 if constexpr (should_call_destructor<T>()) {
112 tt_assert(has_value);
113 }
114 return reinterpret_cast<T const *>(data());
115 }
116
117 T *operator->() noexcept {
118 if constexpr (should_call_destructor<T>()) {
119 tt_assert(has_value);
120 }
121 return reinterpret_cast<T *>(data());
122 }
123};
124
125}
Definition polymorphic_value.hpp:20
T data(T... args)