1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "Prerequisites/BsPrerequisitesUtil.h" |
6 | #include "Debug/BsDebug.h" |
7 | #include <algorithm> |
8 | #include <typeinfo> |
9 | |
10 | namespace bs |
11 | { |
12 | /** @addtogroup General |
13 | * @{ |
14 | */ |
15 | |
16 | /** Class capable of storing any general type, and safely extracting the proper type from the internal data. */ |
17 | class Any |
18 | { |
19 | private: |
20 | class DataBase |
21 | { |
22 | public: |
23 | virtual ~DataBase() = default; |
24 | |
25 | virtual DataBase* clone() const = 0; |
26 | }; |
27 | |
28 | template <typename ValueType> |
29 | class Data : public DataBase |
30 | { |
31 | public: |
32 | Data(const ValueType& value) |
33 | :value(value) |
34 | { } |
35 | |
36 | DataBase* clone() const override |
37 | { |
38 | return bs_new<Data>(Data(value)); |
39 | } |
40 | |
41 | ValueType value; |
42 | }; |
43 | |
44 | public: |
45 | Any() = default; |
46 | |
47 | template <typename ValueType> |
48 | Any(const ValueType& value) |
49 | :mData(bs_new<Data<ValueType>>(value)) |
50 | { } |
51 | |
52 | Any(std::nullptr_t) |
53 | :mData(nullptr) |
54 | { } |
55 | |
56 | Any(const Any& other) |
57 | :mData(other.mData != nullptr ? other.mData->clone() : nullptr) |
58 | { } |
59 | |
60 | ~Any() |
61 | { |
62 | if (mData != nullptr) |
63 | bs_delete(mData); |
64 | } |
65 | |
66 | /** Swaps the contents of this object with another. */ |
67 | Any& swap(Any& rhs) |
68 | { |
69 | std::swap(mData, rhs.mData); |
70 | return *this; |
71 | } |
72 | |
73 | template <typename ValueType> |
74 | Any& operator= (const ValueType& rhs) |
75 | { |
76 | Any(rhs).swap(*this); |
77 | return *this; |
78 | } |
79 | |
80 | Any& operator= (const Any& rhs) |
81 | { |
82 | Any(rhs).swap(*this); |
83 | return *this; |
84 | } |
85 | |
86 | /** Returns true if no type is set. */ |
87 | bool empty() const |
88 | { |
89 | return mData == nullptr; |
90 | } |
91 | |
92 | private: |
93 | template <typename ValueType> |
94 | friend ValueType* any_cast(Any*); |
95 | |
96 | template <typename ValueType> |
97 | friend ValueType* any_cast_unsafe(Any*); |
98 | |
99 | DataBase* mData = nullptr; |
100 | }; |
101 | |
102 | /** |
103 | * Returns a pointer to the internal data of the specified type. |
104 | * |
105 | * @note Will return null if cast fails. |
106 | */ |
107 | template <typename ValueType> |
108 | ValueType* any_cast(Any* operand) |
109 | { |
110 | if (operand != nullptr) |
111 | return &static_cast<Any::Data<ValueType>*>(operand->mData)->value; |
112 | else |
113 | return nullptr; |
114 | } |
115 | |
116 | /** |
117 | * Returns a const pointer to the internal data of the specified type. |
118 | * |
119 | * @note Will return null if cast fails. |
120 | */ |
121 | template <typename ValueType> |
122 | const ValueType* any_cast(const Any* operand) |
123 | { |
124 | return any_cast<ValueType>(const_cast<Any*>(operand)); |
125 | } |
126 | |
127 | /** |
128 | * Returns a copy of the internal data of the specified type. |
129 | * |
130 | * @note Throws an exception if cast fails. |
131 | */ |
132 | template <typename ValueType> |
133 | ValueType any_cast(const Any& operand) |
134 | { |
135 | return *any_cast<ValueType>(const_cast<Any*>(&operand)); |
136 | } |
137 | |
138 | /** |
139 | * Returns a copy of the internal data of the specified type. |
140 | * |
141 | * @note Throws an exception if cast fails. |
142 | */ |
143 | template <typename ValueType> |
144 | ValueType any_cast(Any& operand) |
145 | { |
146 | return *any_cast<ValueType>(&operand); |
147 | } |
148 | |
149 | /** |
150 | * Returns a reference to the internal data of the specified type. |
151 | * |
152 | * @note Throws an exception if cast fails. |
153 | */ |
154 | template <typename ValueType> |
155 | const ValueType& any_cast_ref(const Any & operand) |
156 | { |
157 | return *any_cast<ValueType>(const_cast<Any*>(&operand)); |
158 | } |
159 | |
160 | /** |
161 | * Returns a reference to the internal data of the specified type. |
162 | * |
163 | * @note Throws an exception if cast fails. |
164 | */ |
165 | template <typename ValueType> |
166 | ValueType& any_cast_ref(Any& operand) |
167 | { |
168 | return *any_cast<ValueType>(&operand); |
169 | } |
170 | |
171 | /** Casts a type without performing any kind of checks. */ |
172 | template <typename ValueType> |
173 | ValueType* any_cast_unsafe(Any* operand) |
174 | { |
175 | return &static_cast<Any::Data<ValueType>*>(operand->mData)->value; |
176 | } |
177 | |
178 | /** Casts a type without performing any kind of checks. */ |
179 | template <typename ValueType> |
180 | const ValueType* any_cast_unsafe(const Any* operand) |
181 | { |
182 | return any_cast_unsafe<ValueType>(const_cast<Any*>(operand)); |
183 | } |
184 | |
185 | /** @} */ |
186 | } |
187 | |