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
10namespace 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