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