ezEngine  Milestone 7
Variant_inl.h
1 
2 EZ_FORCE_INLINE ezVariant::ezVariant()
3 {
4  m_Type = Type::Invalid;
5  m_bIsShared = false;
6 }
7 
8 EZ_FORCE_INLINE ezVariant::ezVariant(const ezVariant& other)
9 {
10  CopyFrom(other);
11 }
12 
13 EZ_FORCE_INLINE ezVariant::ezVariant(ezVariant&& other)
14 {
15  MoveFrom(std::move(other));
16 }
17 
18 template <typename T>
19 EZ_FORCE_INLINE ezVariant::ezVariant(const T& value)
20 {
21  Init(value);
22 }
23 
24 EZ_FORCE_INLINE ezVariant::~ezVariant()
25 {
26  Release();
27 }
28 
29 EZ_FORCE_INLINE void ezVariant::operator=(const ezVariant& other)
30 {
31  if (this != &other)
32  {
33  Release();
34  CopyFrom(other);
35  }
36 }
37 
38 EZ_FORCE_INLINE void ezVariant::operator=(ezVariant&& other)
39 {
40  if (this != &other)
41  {
42  Release();
43  MoveFrom(std::move(other));
44  }
45 }
46 
47 template <typename T>
48 EZ_FORCE_INLINE void ezVariant::operator=(const T& value)
49 {
50  Release();
51  Init(value);
52 }
53 
54 EZ_FORCE_INLINE bool ezVariant::operator!=(const ezVariant& other) const
55 {
56  return !(*this == other);
57 }
58 
59 template <typename T>
60 EZ_FORCE_INLINE bool ezVariant::operator==(const T& other) const
61 {
62  struct TypeInfo
63  {
64  enum
65  {
66  isNumber = TypeDeduction<T>::value > Type::Invalid && TypeDeduction<T>::value <= Type::Double
67  };
68  };
69 
70  if (IsFloatingPoint(m_Type))
71  {
72  return ezVariantHelper::CompareFloat(*this, other, ezTraitInt<TypeInfo::isNumber>());
73  }
74  else if (IsNumber(m_Type))
75  {
76  return ezVariantHelper::CompareNumber(*this, other, ezTraitInt<TypeInfo::isNumber>());
77  }
78 
79  EZ_ASSERT_DEV(IsA<T>(), "Stored type '%d' does not match comparison type '%d'", m_Type, TypeDeduction<T>::value);
80  return Cast<T>() == other;
81 }
82 
83 template <typename T>
84 EZ_FORCE_INLINE bool ezVariant::operator!=(const T& other) const
85 {
86  return !(*this == other);
87 }
88 
89 EZ_FORCE_INLINE bool ezVariant::IsValid() const
90 {
91  return m_Type != Type::Invalid;
92 }
93 
94 template <typename T>
95 EZ_FORCE_INLINE bool ezVariant::IsA() const
96 {
97  return m_Type == TypeDeduction<T>::value;
98 }
99 
101 {
102  return static_cast<Type::Enum>(m_Type);
103 }
104 
105 template <typename T>
106 EZ_FORCE_INLINE const T& ezVariant::Get() const
107 {
108  EZ_ASSERT_DEV(IsA<T>(), "Stored type '%d' does not match requested type '%d'", m_Type, TypeDeduction<T>::value);
109  return Cast<T>();
110 }
111 
112 EZ_FORCE_INLINE void* ezVariant::GetData()
113 {
114  return m_bIsShared ? m_Data.shared->m_Ptr : &m_Data;
115 }
116 
117 EZ_FORCE_INLINE const void* ezVariant::GetData() const
118 {
119  return m_bIsShared ? m_Data.shared->m_Ptr : &m_Data;
120 }
121 
122 template <typename T>
123 EZ_FORCE_INLINE bool ezVariant::CanConvertTo() const
124 {
125  return CanConvertTo(static_cast<Type::Enum>(TypeDeduction<T>::value));
126 }
127 
128 template <typename T>
129 T ezVariant::ConvertTo(ezResult* out_pConversionStatus /* = nullptr*/) const
130 {
131  if (!CanConvertTo<T>())
132  {
133  if (out_pConversionStatus != nullptr)
134  *out_pConversionStatus = EZ_FAILURE;
135 
136  return T();
137  }
138 
139  if (m_Type == TypeDeduction<T>::value)
140  {
141  if (out_pConversionStatus != nullptr)
142  *out_pConversionStatus = EZ_SUCCESS;
143 
144  return Cast<T>();
145  }
146 
147  T result;
148  bool bSuccessful = true;
149  ezVariantHelper::To(*this, result, bSuccessful);
150 
151  if (out_pConversionStatus != nullptr)
152  *out_pConversionStatus = bSuccessful ? EZ_SUCCESS : EZ_FAILURE;
153 
154  return result;
155 }
156 
157 // for some reason MSVC does not accept the template keyword here
158 #if EZ_ENABLED(EZ_COMPILER_MSVC)
159  #define CALL_FUNCTOR(functor, type) functor.operator()<type>()
160 #else
161  #define CALL_FUNCTOR(functor, type) functor.template operator()<type>()
162 #endif
163 
164 template <typename Functor>
165 void ezVariant::DispatchTo(Functor& functor, Type::Enum type)
166 {
167  switch (type)
168  {
169  case Type::Bool:
170  CALL_FUNCTOR(functor, bool);
171  break;
172 
173  case Type::Int8:
174  CALL_FUNCTOR(functor, ezInt8);
175  break;
176 
177  case Type::UInt8:
178  CALL_FUNCTOR(functor, ezUInt8);
179  break;
180 
181  case Type::Int16:
182  CALL_FUNCTOR(functor, ezInt16);
183  break;
184 
185  case Type::UInt16:
186  CALL_FUNCTOR(functor, ezUInt16);
187  break;
188 
189  case Type::Int32:
190  CALL_FUNCTOR(functor, ezInt32);
191  break;
192 
193  case Type::UInt32:
194  CALL_FUNCTOR(functor, ezUInt32);
195  break;
196 
197  case Type::Int64:
198  CALL_FUNCTOR(functor, ezInt64);
199  break;
200 
201  case Type::UInt64:
202  CALL_FUNCTOR(functor, ezUInt64);
203  break;
204 
205  case Type::Float:
206  CALL_FUNCTOR(functor, float);
207  break;
208 
209  case Type::Double:
210  CALL_FUNCTOR(functor, double);
211  break;
212 
213  case Type::Color:
214  CALL_FUNCTOR(functor, ezColor);
215  break;
216 
217  case Type::Vector2:
218  CALL_FUNCTOR(functor, ezVec2);
219  break;
220 
221  case Type::Vector3:
222  CALL_FUNCTOR(functor, ezVec3);
223  break;
224 
225  case Type::Vector4:
226  CALL_FUNCTOR(functor, ezVec4);
227  break;
228 
229  case Type::Quaternion:
230  CALL_FUNCTOR(functor, ezQuat);
231  break;
232 
233  case Type::Matrix3:
234  CALL_FUNCTOR(functor, ezMat3);
235  break;
236 
237  case Type::Matrix4:
238  CALL_FUNCTOR(functor, ezMat4);
239  break;
240 
241  case Type::String:
242  CALL_FUNCTOR(functor, ezString);
243  break;
244 
245  case Type::Time:
246  CALL_FUNCTOR(functor, ezTime);
247  break;
248 
249  case Type::Uuid:
250  CALL_FUNCTOR(functor, ezUuid);
251  break;
252 
253  case Type::VariantArray:
254  CALL_FUNCTOR(functor, ezVariantArray);
255  break;
256 
258  CALL_FUNCTOR(functor, ezVariantDictionary);
259  break;
260 
262  CALL_FUNCTOR(functor, ezReflectedClass*);
263  break;
264 
265  case Type::VoidPointer:
266  CALL_FUNCTOR(functor, void*);
267  break;
268 
269  default:
270  EZ_REPORT_FAILURE("Could not dispatch type '%d'", type);
271  break;
272  }
273 }
274 
275 #undef CALL_FUNCTOR
276 
278 
279 template <typename T>
280 EZ_FORCE_INLINE void ezVariant::Init(const T& value)
281 {
282  EZ_CHECK_AT_COMPILETIME_MSG(TypeDeduction<T>::value != Type::Invalid, "value of this type cannot be stored in a Variant");
283 
284  m_Type = TypeDeduction<T>::value;
285 
286  Store<typename TypeDeduction<T>::StorageType, T>(value, ezTraitInt<(sizeof(typename TypeDeduction<T>::StorageType) > sizeof(Data)) || TypeDeduction<T>::forceSharing>());
287 }
288 
289 template <typename StorageType, typename T>
290 EZ_FORCE_INLINE void ezVariant::Store(const T& value, ezTraitInt<0>)
291 {
292  EZ_CHECK_AT_COMPILETIME_MSG(ezIsPodType<T>::value, "in place data needs to be POD");
293  ezMemoryUtils::CopyConstruct(reinterpret_cast<T*>(&m_Data), value, 1);
294  m_bIsShared = false;
295 }
296 
297 template <typename StorageType, typename T>
298 EZ_FORCE_INLINE void ezVariant::Store(const T& value, ezTraitInt<1>)
299 {
300  m_Data.shared = EZ_DEFAULT_NEW(TypedSharedData<StorageType>, value);
301  m_bIsShared = true;
302 }
303 
304 inline void ezVariant::Release()
305 {
306  if (m_bIsShared)
307  {
308  if (m_Data.shared->m_uiRef.Decrement() == 0)
309  {
310  EZ_DEFAULT_DELETE(m_Data.shared);
311  }
312  }
313 }
314 
315 inline void ezVariant::CopyFrom(const ezVariant& other)
316 {
317  m_Type = other.m_Type;
318  m_bIsShared = other.m_bIsShared;
319 
320  if (m_bIsShared)
321  {
322  m_Data.shared = other.m_Data.shared;
323  m_Data.shared->m_uiRef.Increment();
324  }
325  else if (other.IsValid())
326  {
327  m_Data = other.m_Data;
328  }
329 }
330 
331 EZ_FORCE_INLINE void ezVariant::MoveFrom(ezVariant&& other)
332 {
333  m_Type = other.m_Type;
334  m_bIsShared = other.m_bIsShared;
335  m_Data = other.m_Data;
336 
337  other.m_Type = Type::Invalid;
338  other.m_bIsShared = false;
339  other.m_Data.shared = nullptr;
340 }
341 
342 template <typename T>
343 EZ_FORCE_INLINE T& ezVariant::Cast()
344 {
345  EZ_CHECK_AT_COMPILETIME_MSG(TypeDeduction<T>::value != Type::Invalid, "Value of this type cannot be compared against a Variant");
346  const bool validType = ezConversionTest<T, typename TypeDeduction<T>::StorageType>::sameType;
347  EZ_CHECK_AT_COMPILETIME_MSG(validType, "Invalid Cast, can only cast to storage type");
348 
349  return (sizeof(T) > sizeof(Data) || TypeDeduction<T>::forceSharing) ?
350  *static_cast<T*>(m_Data.shared->m_Ptr) :
351  *reinterpret_cast<T*>(&m_Data);
352 }
353 
354 template <typename T>
355 EZ_FORCE_INLINE const T& ezVariant::Cast() const
356 {
357  EZ_CHECK_AT_COMPILETIME_MSG(TypeDeduction<T>::value != Type::Invalid, "Value of this type cannot be compared against a Variant");
358  const bool validType = ezConversionTest<T, typename TypeDeduction<T>::StorageType>::sameType;
359  EZ_CHECK_AT_COMPILETIME_MSG(validType, "Invalid Cast, can only cast to storage type");
360 
361  return (sizeof(T) > sizeof(Data) || TypeDeduction<T>::forceSharing) ?
362  *static_cast<const T*>(m_Data.shared->m_Ptr) :
363  *reinterpret_cast<const T*>(&m_Data);
364 }
365 
366 EZ_FORCE_INLINE bool ezVariant::IsNumber(ezUInt32 type)
367 {
368  return type > Type::Invalid && type <= Type::Double;
369 }
370 
371 EZ_FORCE_INLINE bool ezVariant::IsFloatingPoint(ezUInt32 type)
372 {
373  return type == Type::Float || type == Type::Double;
374 }
375 
376 template <typename T>
377 T ezVariant::ConvertNumber() const
378 {
379  switch (m_Type)
380  {
381  case Type::Bool:
382  return static_cast<T>(Cast<bool>());
383  case Type::Int8:
384  return static_cast<T>(Cast<ezInt8>());
385  case Type::UInt8:
386  return static_cast<T>(Cast<ezUInt8>());
387  case Type::Int16:
388  return static_cast<T>(Cast<ezInt16>());
389  case Type::UInt16:
390  return static_cast<T>(Cast<ezUInt16>());
391  case Type::Int32:
392  return static_cast<T>(Cast<ezInt32>());
393  case Type::UInt32:
394  return static_cast<T>(Cast<ezUInt32>());
395  case Type::Int64:
396  return static_cast<T>(Cast<ezInt64>());
397  case Type::UInt64:
398  return static_cast<T>(Cast<ezUInt64>());
399  case Type::Float:
400  return static_cast<T>(Cast<float>());
401  case Type::Double:
402  return static_cast<T>(Cast<double>());
403  }
404 
405  EZ_REPORT_FAILURE("Variant is not a number");
406  return T(0);
407 }
408