1 //-----------------------------------------------------------------------------
2 // Project : SDK Core
3 //
4 // Category : SDK Core Interfaces
5 // Filename : pluginterfaces/base/fvariant.h
6 // Created by : Steinberg, 01/2004
7 // Description : Basic Interface
8 //
9 //-----------------------------------------------------------------------------
10 // This file is part of a Steinberg SDK. It is subject to the license terms
11 // in the LICENSE file found in the top-level directory of this distribution
12 // and at www.steinberg.net/sdklicenses.
13 // No part of the SDK, including this file, may be copied, modified, propagated,
14 // or distributed except according to the terms contained in the LICENSE file.
15 //-----------------------------------------------------------------------------
16
17 #pragma once
18
19 #include "pluginterfaces/base/fstrdefs.h"
20 #include "pluginterfaces/base/funknown.h"
21
22 //------------------------------------------------------------------------
23 namespace Steinberg {
24
25 class FUnknown;
26
27 //------------------------------------------------------------------------
28 // FVariant struct declaration
29 //------------------------------------------------------------------------
30 /** A Value of variable type.
31 \ingroup pluginBase
32 */
33 class FVariant
34 {
35 //------------------------------------------------------------------------
36 public:
37 enum
38 {
39 kEmpty = 0,
40 kInteger = 1 << 0,
41 kFloat = 1 << 1,
42 kString8 = 1 << 2,
43 kObject = 1 << 3,
44 kOwner = 1 << 4,
45 kString16 = 1 << 5
46 };
47
48 //------------------------------------------------------------------------
49 // ctors
FVariant()50 inline FVariant () { memset (this, 0, sizeof (FVariant)); }
51 inline FVariant (const FVariant& variant);
52
FVariant(bool b)53 inline FVariant (bool b) : type (kInteger), intValue (b) {}
FVariant(uint32 v)54 inline FVariant (uint32 v) : type (kInteger), intValue (v) {}
FVariant(int64 v)55 inline FVariant (int64 v) : type (kInteger), intValue (v) {}
FVariant(double v)56 inline FVariant (double v) : type (kFloat), floatValue (v) {}
FVariant(const char8 * str)57 inline FVariant (const char8* str) : type (kString8), string8 (str) {}
FVariant(const char16 * str)58 inline FVariant (const char16* str) : type (kString16), string16 (str) {}
type(kObject)59 inline FVariant (FUnknown* obj, bool owner = false) : type (kObject), object (obj)
60 {
61 setOwner (owner);
62 }
~FVariant()63 inline ~FVariant () { empty (); }
64
65 //------------------------------------------------------------------------
66 inline FVariant& operator= (const FVariant& variant);
67
set(bool b)68 inline void set (bool b)
69 {
70 setInt (b);
71 }
72
set(uint32 v)73 inline void set (uint32 v)
74 {
75 setInt (v);
76 }
77
set(int64 v)78 inline void set (int64 v)
79 {
80 setInt (v);
81 }
82
set(double v)83 inline void set (double v)
84 {
85 setFloat (v);
86 }
87
set(const char8 * c)88 inline void set (const char8* c)
89 {
90 setString8 (c);
91 }
92
set(const char16 * c)93 inline void set (const char16* c)
94 {
95 setString16 (c);
96 }
97
setInt(int64 v)98 inline void setInt (int64 v)
99 {
100 empty ();
101 type = kInteger;
102 intValue = v;
103 }
104
setFloat(double v)105 inline void setFloat (double v)
106 {
107 empty ();
108 type = kFloat;
109 floatValue = v;
110 }
setString8(const char8 * v)111 inline void setString8 (const char8* v)
112 {
113 empty ();
114 type = kString8;
115 string8 = v;
116 }
setString16(const char16 * v)117 inline void setString16 (const char16* v)
118 {
119 empty ();
120 type = kString16;
121 string16 = v;
122 }
123
setObject(FUnknown * obj)124 inline void setObject (FUnknown* obj)
125 {
126 empty ();
127 type = kObject;
128 object = obj;
129 }
130
131 template <typename T>
132 inline T get () const;
133
getInt()134 inline int64 getInt () const { return (type & kInteger) ? intValue : 0; }
getFloat()135 inline double getFloat () const { return (type & kFloat) ? floatValue : 0.; }
getNumber()136 inline double getNumber () const
137 {
138 return (type & kInteger) ? static_cast<double> (intValue) : (type & kFloat) ? floatValue :
139 0.;
140 }
getString8()141 inline const char8* getString8 () const { return (type & kString8) ? string8 : nullptr; }
getString16()142 inline const char16* getString16 () const { return (type & kString16) ? string16 : nullptr; }
143
getObject()144 inline FUnknown* getObject () const { return (type & kObject) ? object : nullptr; }
145
getType()146 inline uint16 getType () const { return static_cast<uint16> (type & ~(kOwner)); }
isEmpty()147 inline bool isEmpty () const { return getType () == kEmpty; }
isOwner()148 inline bool isOwner () const { return (type & kOwner) != 0; }
isString()149 inline bool isString () const { return (type & (kString8 | kString16)) != 0; }
setOwner(bool state)150 inline void setOwner (bool state)
151 {
152 if (state)
153 type |= kOwner;
154 else
155 type &= ~kOwner;
156 }
157
158 void empty ();
159 //------------------------------------------------------------------------
160 uint16 type;
161 union
162 {
163 int64 intValue;
164 double floatValue;
165 const char8* string8;
166 const char16* string16;
167 FUnknown* object;
168 };
169 };
170
171 //------------------------------------------------------------------------
172 inline bool operator== (const FVariant& v1, const FVariant& v2)
173 {
174 #if SMTG_PLATFORM_64
175 return v1.type == v2.type && v1.intValue == v2.intValue;
176 #else
177 if (v1.type != v2.type)
178 return false;
179 if (v1.type & (FVariant::kString8 | FVariant::kString16 | FVariant::kObject))
180 return v1.string8 == v2.string8; // pointer type comparisons
181 return v1.intValue == v2.intValue; // intValue & double comparison
182
183 #endif
184 }
185
186 template <>
187 inline bool FVariant::get<bool> () const
188 {
189 return getInt () != 0;
190 }
191
192 template <>
193 inline uint32 FVariant::get<uint32> () const
194 {
195 return static_cast<uint32> (getInt ());
196 }
197
198 template <>
199 inline int32 FVariant::get<int32> () const
200 {
201 return static_cast<int32> (getInt ());
202 }
203
204 template <>
205 inline int64 FVariant::get<int64> () const
206 {
207 return static_cast<int64> (getInt ());
208 }
209
210 template <>
211 inline float FVariant::get<float> () const
212 {
213 return static_cast<float> (getFloat ());
214 }
215
216 template <>
217 inline double FVariant::get<double> () const
218 {
219 return getFloat ();
220 }
221
222 template <>
223 inline const char8* FVariant::get<const char8*> () const
224 {
225 return getString8 ();
226 }
227
228 template <>
229 inline const char16* FVariant::get<const char16*> () const
230 {
231 return getString16 ();
232 }
233
234 template <>
235 inline FUnknown* FVariant::get<FUnknown*> () const
236 {
237 return getObject ();
238 }
239
240 //------------------------------------------------------------------------
241 inline bool operator!= (const FVariant& v1, const FVariant& v2) { return !(v1 == v2); }
242
243 //------------------------------------------------------------------------
FVariant(const FVariant & variant)244 inline FVariant::FVariant (const FVariant& variant) : type (kEmpty) { *this = variant; }
245
246 //------------------------------------------------------------------------
empty()247 inline void FVariant::empty ()
248 {
249 if (type & kOwner)
250 {
251 if ((type & kString8) && string8)
252 delete[] string8;
253 else if ((type & kString16) && string16)
254 delete[] string16;
255
256 else if ((type & kObject) && object)
257 object->release ();
258 }
259 memset (this, 0, sizeof (FVariant));
260 }
261
262 //------------------------------------------------------------------------
263 inline FVariant& FVariant::operator= (const FVariant& variant)
264 {
265 empty ();
266
267 type = variant.type;
268
269 if ((type & kString8) && variant.string8)
270 {
271 string8 = new char8[strlen (variant.string8) + 1];
272 strcpy (const_cast<char8*> (string8), variant.string8);
273 type |= kOwner;
274 }
275 else if ((type & kString16) && variant.string16)
276 {
277 int32 len = strlen16 (variant.string16);
278 string16 = new char16[len + 1];
279 char16* tmp = const_cast<char16*> (string16);
280 memcpy (tmp, variant.string16, len * sizeof (char16));
281 tmp[len] = 0;
282 type |= kOwner;
283 }
284 else if ((type & kObject) && variant.object)
285 {
286 object = variant.object;
287 object->addRef ();
288 type |= kOwner;
289 }
290 else
291 intValue = variant.intValue; // copy memory
292
293 return *this;
294 }
295
296 //------------------------------------------------------------------------
297 } // namespace Steinberg
298