OpenShot Audio Library | OpenShotAudio 0.4.0
Loading...
Searching...
No Matches
juce_Variant.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26enum VariantStreamMarkers
27{
28 varMarker_Int = 1,
29 varMarker_BoolTrue = 2,
30 varMarker_BoolFalse = 3,
31 varMarker_Double = 4,
32 varMarker_String = 5,
33 varMarker_Int64 = 6,
34 varMarker_Array = 7,
35 varMarker_Binary = 8,
36 varMarker_Undefined = 9
37};
38
39//==============================================================================
40struct var::VariantType
41{
42 struct VoidTag {};
43 struct UndefinedTag {};
44 struct IntTag {};
45 struct Int64Tag {};
46 struct DoubleTag {};
47 struct BoolTag {};
48 struct StringTag {};
49 struct ObjectTag {};
50 struct ArrayTag {};
51 struct BinaryTag {};
52 struct MethodTag {};
53
54 // members =====================================================================
55 bool isVoid = false;
56 bool isUndefined = false;
57 bool isInt = false;
58 bool isInt64 = false;
59 bool isBool = false;
60 bool isDouble = false;
61 bool isString = false;
62 bool isObject = false;
63 bool isArray = false;
64 bool isBinary = false;
65 bool isMethod = false;
66 bool isComparable = false;
67
68 int (*toInt) (const ValueUnion&) = defaultToInt;
69 int64 (*toInt64) (const ValueUnion&) = defaultToInt64;
70 double (*toDouble) (const ValueUnion&) = defaultToDouble;
71 String (*toString) (const ValueUnion&) = defaultToString;
72 bool (*toBool) (const ValueUnion&) = defaultToBool;
73 ReferenceCountedObject* (*toObject) (const ValueUnion&) = defaultToObject;
74 Array<var>* (*toArray) (const ValueUnion&) = defaultToArray;
75 MemoryBlock* (*toBinary) (const ValueUnion&) = defaultToBinary;
76 var (*clone) (const var&) = defaultClone;
77 void (*cleanUp) (ValueUnion&) = defaultCleanUp;
78 void (*createCopy) (ValueUnion&, const ValueUnion&) = defaultCreateCopy;
79
80 bool (*equals) (const ValueUnion&, const ValueUnion&, const VariantType&) = nullptr;
81 void (*writeToStream) (const ValueUnion&, OutputStream&) = nullptr;
82
83 // defaults ====================================================================
84 static int defaultToInt (const ValueUnion&) { return 0; }
85 static int64 defaultToInt64 (const ValueUnion&) { return 0; }
86 static double defaultToDouble (const ValueUnion&) { return 0; }
87 static String defaultToString (const ValueUnion&) { return {}; }
88 static bool defaultToBool (const ValueUnion&) { return false; }
89 static ReferenceCountedObject* defaultToObject (const ValueUnion&) { return nullptr; }
90 static Array<var>* defaultToArray (const ValueUnion&) { return nullptr; }
91 static MemoryBlock* defaultToBinary (const ValueUnion&) { return nullptr; }
92 static var defaultClone (const var& other) { return other; }
93 static void defaultCleanUp (ValueUnion&) {}
94 static void defaultCreateCopy (ValueUnion& dest, const ValueUnion& source) { dest = source; }
95
96 // void ========================================================================
97 static bool voidEquals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) noexcept
98 {
99 return otherType.isVoid || otherType.isUndefined;
100 }
101
102 static void voidWriteToStream (const ValueUnion&, OutputStream& output)
103 {
104 output.writeCompressedInt (0);
105 }
106
107 constexpr explicit VariantType (VoidTag) noexcept
108 : isVoid (true),
109 isComparable (true),
110 equals (voidEquals),
111 writeToStream (voidWriteToStream) {}
112
113 // undefined ===================================================================
114 static String undefinedToString (const ValueUnion&) { return "undefined"; }
115
116 static bool undefinedEquals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) noexcept
117 {
118 return otherType.isVoid || otherType.isUndefined;
119 }
120
121 static void undefinedWriteToStream (const ValueUnion&, OutputStream& output)
122 {
123 output.writeCompressedInt (1);
124 output.writeByte (varMarker_Undefined);
125 }
126
127 constexpr explicit VariantType (UndefinedTag) noexcept
128 : isUndefined (true),
129 toString (undefinedToString),
130 equals (undefinedEquals),
131 writeToStream (undefinedWriteToStream) {}
132
133 // int =========================================================================
134 static int intToInt (const ValueUnion& data) noexcept { return data.intValue; }
135 static int64 intToInt64 (const ValueUnion& data) noexcept { return (int64) data.intValue; }
136 static double intToDouble (const ValueUnion& data) noexcept { return (double) data.intValue; }
137 static String intToString (const ValueUnion& data) { return String (data.intValue); }
138 static bool intToBool (const ValueUnion& data) noexcept { return data.intValue != 0; }
139
140 static bool intEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
141 {
142 if (otherType.isDouble || otherType.isInt64 || otherType.isString)
143 return otherType.equals (otherData, data, VariantType { IntTag{} });
144
145 return otherType.toInt (otherData) == data.intValue;
146 }
147
148 static void intWriteToStream (const ValueUnion& data, OutputStream& output)
149 {
150 output.writeCompressedInt (5);
151 output.writeByte (varMarker_Int);
152 output.writeInt (data.intValue);
153 }
154
155 constexpr explicit VariantType (IntTag) noexcept
156 : isInt (true),
157 isComparable (true),
158 toInt (intToInt),
159 toInt64 (intToInt64),
160 toDouble (intToDouble),
161 toString (intToString),
162 toBool (intToBool),
163 equals (intEquals),
164 writeToStream (intWriteToStream) {}
165
166 // int64 =======================================================================
167 static int int64ToInt (const ValueUnion& data) noexcept { return (int) data.int64Value; }
168 static int64 int64ToInt64 (const ValueUnion& data) noexcept { return data.int64Value; }
169 static double int64ToDouble (const ValueUnion& data) noexcept { return (double) data.int64Value; }
170 static String int64ToString (const ValueUnion& data) { return String (data.int64Value); }
171 static bool int64ToBool (const ValueUnion& data) noexcept { return data.int64Value != 0; }
172
173 static bool int64Equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
174 {
175 if (otherType.isDouble || otherType.isString)
176 return otherType.equals (otherData, data, VariantType { Int64Tag{} });
177
178 return otherType.toInt64 (otherData) == data.int64Value;
179 }
180
181 static void int64WriteToStream (const ValueUnion& data, OutputStream& output)
182 {
183 output.writeCompressedInt (9);
184 output.writeByte (varMarker_Int64);
185 output.writeInt64 (data.int64Value);
186 }
187
188 constexpr explicit VariantType (Int64Tag) noexcept
189 : isInt64 (true),
190 isComparable (true),
191 toInt (int64ToInt),
192 toInt64 (int64ToInt64),
193 toDouble (int64ToDouble),
194 toString (int64ToString),
195 toBool (int64ToBool),
196 equals (int64Equals),
197 writeToStream (int64WriteToStream) {}
198
199 // double ======================================================================
200 static int doubleToInt (const ValueUnion& data) noexcept { return (int) data.doubleValue; }
201 static int64 doubleToInt64 (const ValueUnion& data) noexcept { return (int64) data.doubleValue; }
202 static double doubleToDouble (const ValueUnion& data) noexcept { return data.doubleValue; }
203 static String doubleToString (const ValueUnion& data) { return serialiseDouble (data.doubleValue); }
204 static bool doubleToBool (const ValueUnion& data) noexcept { return ! exactlyEqual (data.doubleValue, 0.0); }
205
206 static bool doubleEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
207 {
208 return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
209 }
210
211 static void doubleWriteToStream (const ValueUnion& data, OutputStream& output)
212 {
213 output.writeCompressedInt (9);
214 output.writeByte (varMarker_Double);
215 output.writeDouble (data.doubleValue);
216 }
217
218 constexpr explicit VariantType (DoubleTag) noexcept
219 : isDouble (true),
220 isComparable (true),
221 toInt (doubleToInt),
222 toInt64 (doubleToInt64),
223 toDouble (doubleToDouble),
224 toString (doubleToString),
225 toBool (doubleToBool),
226 equals (doubleEquals),
227 writeToStream (doubleWriteToStream) {}
228
229 // bool ========================================================================
230 static int boolToInt (const ValueUnion& data) noexcept { return data.boolValue ? 1 : 0; }
231 static int64 boolToInt64 (const ValueUnion& data) noexcept { return data.boolValue ? 1 : 0; }
232 static double boolToDouble (const ValueUnion& data) noexcept { return data.boolValue ? 1.0 : 0.0; }
233 static String boolToString (const ValueUnion& data) { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
234 static bool boolToBool (const ValueUnion& data) noexcept { return data.boolValue; }
235
236 static bool boolEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
237 {
238 return otherType.toBool (otherData) == data.boolValue;
239 }
240
241 static void boolWriteToStream (const ValueUnion& data, OutputStream& output)
242 {
243 output.writeCompressedInt (1);
244 output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
245 }
246
247 constexpr explicit VariantType (BoolTag) noexcept
248 : isBool (true),
249 isComparable (true),
250 toInt (boolToInt),
251 toInt64 (boolToInt64),
252 toDouble (boolToDouble),
253 toString (boolToString),
254 toBool (boolToBool),
255 equals (boolEquals),
256 writeToStream (boolWriteToStream) {}
257
258 // string ======================================================================
259 static const String* getString (const ValueUnion& data) noexcept { return unalignedPointerCast<const String*> (data.stringValue); }
260 static String* getString ( ValueUnion& data) noexcept { return unalignedPointerCast<String*> (data.stringValue); }
261
262 static int stringToInt (const ValueUnion& data) noexcept { return getString (data)->getIntValue(); }
263 static int64 stringToInt64 (const ValueUnion& data) noexcept { return getString (data)->getLargeIntValue(); }
264 static double stringToDouble (const ValueUnion& data) noexcept { return getString (data)->getDoubleValue(); }
265 static String stringToString (const ValueUnion& data) { return *getString (data); }
266 static bool stringToBool (const ValueUnion& data) noexcept
267 {
268 return getString (data)->getIntValue() != 0
269 || getString (data)->trim().equalsIgnoreCase ("true")
270 || getString (data)->trim().equalsIgnoreCase ("yes");
271 }
272
273 static void stringCleanUp (ValueUnion& data) noexcept { getString (data)-> ~String(); }
274 static void stringCreateCopy (ValueUnion& dest, const ValueUnion& source) { new (dest.stringValue) String (*getString (source)); }
275
276 static bool stringEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
277 {
278 return otherType.toString (otherData) == *getString (data);
279 }
280
281 static void stringWriteToStream (const ValueUnion& data, OutputStream& output)
282 {
283 auto* s = getString (data);
284 const size_t len = s->getNumBytesAsUTF8() + 1;
285 HeapBlock<char> temp (len);
286 s->copyToUTF8 (temp, len);
287 output.writeCompressedInt ((int) (len + 1));
288 output.writeByte (varMarker_String);
289 output.write (temp, len);
290 }
291
292 constexpr explicit VariantType (StringTag) noexcept
293 : isString (true),
294 isComparable (true),
295 toInt (stringToInt),
296 toInt64 (stringToInt64),
297 toDouble (stringToDouble),
298 toString (stringToString),
299 toBool (stringToBool),
300 cleanUp (stringCleanUp),
301 createCopy (stringCreateCopy),
302 equals (stringEquals),
303 writeToStream (stringWriteToStream) {}
304
305 // object ======================================================================
306 static String objectToString (const ValueUnion& data)
307 {
308 return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue);
309 }
310
311 static bool objectToBool (const ValueUnion& data) noexcept { return data.objectValue != nullptr; }
312 static ReferenceCountedObject* objectToObject (const ValueUnion& data) noexcept { return data.objectValue; }
313
314 static var objectClone (const var& original)
315 {
316 if (auto* d = original.getDynamicObject())
317 return d->clone().release();
318
319 jassertfalse; // can only clone DynamicObjects!
320 return {};
321 }
322
323 static void objectCleanUp (ValueUnion& data) noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
324
325 static void objectCreateCopy (ValueUnion& dest, const ValueUnion& source)
326 {
327 dest.objectValue = source.objectValue;
328 if (dest.objectValue != nullptr)
329 dest.objectValue->incReferenceCount();
330 }
331
332 static bool objectEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
333 {
334 return otherType.toObject (otherData) == data.objectValue;
335 }
336
337 static void objectWriteToStream (const ValueUnion&, OutputStream& output)
338 {
339 jassertfalse; // Can't write an object to a stream!
340 output.writeCompressedInt (0);
341 }
342
343 constexpr explicit VariantType (ObjectTag) noexcept
344 : isObject (true),
345 toString (objectToString),
346 toBool (objectToBool),
347 toObject (objectToObject),
348 clone (objectClone),
349 cleanUp (objectCleanUp),
350 createCopy (objectCreateCopy),
351 equals (objectEquals),
352 writeToStream (objectWriteToStream) {}
353
354 // array =======================================================================
355 static String arrayToString (const ValueUnion&) { return "[Array]"; }
356 static ReferenceCountedObject* arrayToObject (const ValueUnion&) noexcept { return nullptr; }
357
358 static Array<var>* arrayToArray (const ValueUnion& data) noexcept
359 {
360 if (auto* a = dynamic_cast<RefCountedArray*> (data.objectValue))
361 return &(a->array);
362
363 return nullptr;
364 }
365
366 static bool arrayEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
367 {
368 auto* thisArray = arrayToArray (data);
369 auto* otherArray = otherType.toArray (otherData);
370 return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
371 }
372
373 static var arrayClone (const var& original)
374 {
375 Array<var> arrayCopy;
376
377 if (auto* array = arrayToArray (original.value))
378 {
379 arrayCopy.ensureStorageAllocated (array->size());
380
381 for (auto& i : *array)
382 arrayCopy.add (i.clone());
383 }
384
385 return var (arrayCopy);
386 }
387
388 static void arrayWriteToStream (const ValueUnion& data, OutputStream& output)
389 {
390 if (auto* array = arrayToArray (data))
391 {
392 MemoryOutputStream buffer (512);
393 buffer.writeCompressedInt (array->size());
394
395 for (auto& i : *array)
396 i.writeToStream (buffer);
397
398 output.writeCompressedInt (1 + (int) buffer.getDataSize());
399 output.writeByte (varMarker_Array);
400 output << buffer;
401 }
402 }
403
404 struct RefCountedArray final : public ReferenceCountedObject
405 {
406 RefCountedArray (const Array<var>& a) : array (a) { incReferenceCount(); }
407 RefCountedArray (Array<var>&& a) : array (std::move (a)) { incReferenceCount(); }
408 Array<var> array;
409 };
410
411 constexpr explicit VariantType (ArrayTag) noexcept
412 : isObject (true),
413 isArray (true),
414 toString (arrayToString),
415 toBool (objectToBool),
416 toObject (arrayToObject),
417 toArray (arrayToArray),
418 clone (arrayClone),
419 cleanUp (objectCleanUp),
420 createCopy (objectCreateCopy),
421 equals (arrayEquals),
422 writeToStream (arrayWriteToStream) {}
423
424 // binary ======================================================================
425 static void binaryCleanUp (ValueUnion& data) noexcept { delete data.binaryValue; }
426 static void binaryCreateCopy (ValueUnion& dest, const ValueUnion& source) { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
427
428 static String binaryToString (const ValueUnion& data) { return data.binaryValue->toBase64Encoding(); }
429 static MemoryBlock* binaryToBinary (const ValueUnion& data) noexcept { return data.binaryValue; }
430
431 static bool binaryEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
432 {
433 const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
434 return otherBlock != nullptr && *otherBlock == *data.binaryValue;
435 }
436
437 static void binaryWriteToStream (const ValueUnion& data, OutputStream& output)
438 {
439 output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
440 output.writeByte (varMarker_Binary);
441 output << *data.binaryValue;
442 }
443
444 constexpr explicit VariantType (BinaryTag) noexcept
445 : isBinary (true),
446 toString (binaryToString),
447 toBinary (binaryToBinary),
448 cleanUp (binaryCleanUp),
449 createCopy (binaryCreateCopy),
450 equals (binaryEquals),
451 writeToStream (binaryWriteToStream) {}
452
453 // method ======================================================================
454 static void methodCleanUp (ValueUnion& data) noexcept { if (data.methodValue != nullptr ) delete data.methodValue; }
455 static void methodCreateCopy (ValueUnion& dest, const ValueUnion& source) { dest.methodValue = new NativeFunction (*source.methodValue); }
456
457 static String methodToString (const ValueUnion&) { return "Method"; }
458 static bool methodToBool (const ValueUnion& data) noexcept { return data.methodValue != nullptr; }
459
460 static bool methodEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
461 {
462 return otherType.isMethod && otherData.methodValue == data.methodValue;
463 }
464
465 static void methodWriteToStream (const ValueUnion&, OutputStream& output)
466 {
467 jassertfalse; // Can't write a method to a stream!
468 output.writeCompressedInt (0);
469 }
470
471 constexpr explicit VariantType (MethodTag) noexcept
472 : isMethod (true),
473 toString (methodToString),
474 toBool (methodToBool),
475 cleanUp (methodCleanUp),
476 createCopy (methodCreateCopy),
477 equals (methodEquals),
478 writeToStream (methodWriteToStream) {}
479};
480
481struct var::Instance
482{
483 static constexpr VariantType attributesVoid { VariantType::VoidTag{} };
484 static constexpr VariantType attributesUndefined { VariantType::UndefinedTag{} };
485 static constexpr VariantType attributesInt { VariantType::IntTag{} };
486 static constexpr VariantType attributesInt64 { VariantType::Int64Tag{} };
487 static constexpr VariantType attributesBool { VariantType::BoolTag{} };
488 static constexpr VariantType attributesDouble { VariantType::DoubleTag{} };
489 static constexpr VariantType attributesMethod { VariantType::MethodTag{} };
490 static constexpr VariantType attributesArray { VariantType::ArrayTag{} };
491 static constexpr VariantType attributesString { VariantType::StringTag{} };
492 static constexpr VariantType attributesBinary { VariantType::BinaryTag{} };
493 static constexpr VariantType attributesObject { VariantType::ObjectTag{} };
494};
495
496//==============================================================================
497var::var() noexcept : type (&Instance::attributesVoid) {}
498var::var (const VariantType& t) noexcept : type (&t) {}
499var::~var() noexcept { type->cleanUp (value); }
500
501//==============================================================================
502var::var (const var& valueToCopy) : type (valueToCopy.type)
503{
504 type->createCopy (value, valueToCopy.value);
505}
506
507var::var (const int v) noexcept : type (&Instance::attributesInt) { value.intValue = v; }
508var::var (const int64 v) noexcept : type (&Instance::attributesInt64) { value.int64Value = v; }
509var::var (const bool v) noexcept : type (&Instance::attributesBool) { value.boolValue = v; }
510var::var (const double v) noexcept : type (&Instance::attributesDouble) { value.doubleValue = v; }
511var::var (NativeFunction m) noexcept : type (&Instance::attributesMethod) { value.methodValue = new NativeFunction (m); }
512var::var (const Array<var>& v) : type (&Instance::attributesArray) { value.objectValue = new VariantType::RefCountedArray (v); }
513var::var (const String& v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
514var::var (const char* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
515var::var (const wchar_t* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
516var::var (const void* v, size_t sz) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v, sz); }
517var::var (const MemoryBlock& v) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v); }
518
519var::var (const StringArray& v) : type (&Instance::attributesArray)
520{
521 Array<var> strings;
522 strings.ensureStorageAllocated (v.size());
523
524 for (auto& i : v)
525 strings.add (var (i));
526
527 value.objectValue = new VariantType::RefCountedArray (strings);
528}
529
530var::var (ReferenceCountedObject* const object) : type (&Instance::attributesObject)
531{
532 value.objectValue = object;
533
534 if (object != nullptr)
535 object->incReferenceCount();
536}
537
538var var::undefined() noexcept { return var (Instance::attributesUndefined); }
539
540//==============================================================================
541bool var::isVoid() const noexcept { return type->isVoid; }
542bool var::isUndefined() const noexcept { return type->isUndefined; }
543bool var::isInt() const noexcept { return type->isInt; }
544bool var::isInt64() const noexcept { return type->isInt64; }
545bool var::isBool() const noexcept { return type->isBool; }
546bool var::isDouble() const noexcept { return type->isDouble; }
547bool var::isString() const noexcept { return type->isString; }
548bool var::isObject() const noexcept { return type->isObject; }
549bool var::isArray() const noexcept { return type->isArray; }
550bool var::isBinaryData() const noexcept { return type->isBinary; }
551bool var::isMethod() const noexcept { return type->isMethod; }
552
553var::operator int() const noexcept { return type->toInt (value); }
554var::operator int64() const noexcept { return type->toInt64 (value); }
555var::operator bool() const noexcept { return type->toBool (value); }
556var::operator float() const noexcept { return (float) type->toDouble (value); }
557var::operator double() const noexcept { return type->toDouble (value); }
558String var::toString() const { return type->toString (value); }
559var::operator String() const { return type->toString (value); }
560ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
561Array<var>* var::getArray() const noexcept { return type->toArray (value); }
562MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
563DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast<DynamicObject*> (getObject()); }
564
565//==============================================================================
566void var::swapWith (var& other) noexcept
567{
568 std::swap (type, other.type);
569 std::swap (value, other.value);
570}
571
572var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
573var& var::operator= (const int v) { type->cleanUp (value); type = &Instance::attributesInt; value.intValue = v; return *this; }
574var& var::operator= (const int64 v) { type->cleanUp (value); type = &Instance::attributesInt64; value.int64Value = v; return *this; }
575var& var::operator= (const bool v) { type->cleanUp (value); type = &Instance::attributesBool; value.boolValue = v; return *this; }
576var& var::operator= (const double v) { type->cleanUp (value); type = &Instance::attributesDouble; value.doubleValue = v; return *this; }
577var& var::operator= (const char* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
578var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
579var& var::operator= (const String& v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
580var& var::operator= (const MemoryBlock& v) { type->cleanUp (value); type = &Instance::attributesBinary; value.binaryValue = new MemoryBlock (v); return *this; }
581var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
582var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
583var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; }
584
585var::var (var&& other) noexcept
586 : type (other.type),
587 value (other.value)
588{
589 other.type = &Instance::attributesVoid;
590}
591
592var& var::operator= (var&& other) noexcept
593{
594 swapWith (other);
595 return *this;
596}
597
598var::var (String&& v) : type (&Instance::attributesString)
599{
600 new (value.stringValue) String (std::move (v));
601}
602
603var::var (MemoryBlock&& v) : type (&Instance::attributesBinary)
604{
605 value.binaryValue = new MemoryBlock (std::move (v));
606}
607
608var::var (Array<var>&& v) : type (&Instance::attributesArray)
609{
610 value.objectValue = new VariantType::RefCountedArray (std::move (v));
611}
612
613var& var::operator= (String&& v)
614{
615 type->cleanUp (value);
616 type = &Instance::attributesString;
617 new (value.stringValue) String (std::move (v));
618 return *this;
619}
620
621//==============================================================================
622bool var::equals (const var& other) const noexcept
623{
624 return type->equals (value, other.value, *other.type);
625}
626
627bool var::equalsWithSameType (const var& other) const noexcept
628{
629 return hasSameTypeAs (other) && equals (other);
630}
631
632bool var::hasSameTypeAs (const var& other) const noexcept
633{
634 return type == other.type;
635}
636
637bool canCompare (const var& v1, const var& v2)
638{
639 return v1.type->isComparable && v2.type->isComparable;
640}
641
642static int compare (const var& v1, const var& v2)
643{
644 if (v1.isString() && v2.isString())
645 return v1.toString().compare (v2.toString());
646
647 auto diff = static_cast<double> (v1) - static_cast<double> (v2);
648 return exactlyEqual (diff, 0.0) ? 0 : (diff < 0 ? -1 : 1);
649}
650
651bool operator== (const var& v1, const var& v2) { return v1.equals (v2); }
652bool operator!= (const var& v1, const var& v2) { return ! v1.equals (v2); }
653bool operator< (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) < 0; }
654bool operator> (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) > 0; }
655bool operator<= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) <= 0; }
656bool operator>= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) >= 0; }
657
658bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
659bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
660bool operator== (const var& v1, const char* v2) { return v1.toString() == v2; }
661bool operator!= (const var& v1, const char* v2) { return v1.toString() != v2; }
662
663//==============================================================================
665{
666 return type->clone (*this);
667}
668
669//==============================================================================
671{
672 if (auto* o = getDynamicObject())
673 return o->getProperty (propertyName);
674
675 return getNullVarRef();
676}
677
678const var& var::operator[] (const char* const propertyName) const
679{
681}
682
684{
685 if (auto* o = getDynamicObject())
686 return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
687
688 return defaultReturnValue;
689}
690
691bool var::hasProperty (const Identifier& propertyName) const noexcept
692{
693 if (auto* o = getDynamicObject())
694 return o->hasProperty (propertyName);
695
696 return false;
697}
698
699var::NativeFunction var::getNativeFunction() const
700{
701 return isMethod() && (value.methodValue != nullptr) ? *value.methodValue : nullptr;
702}
703
704var var::invoke (const Identifier& method, const var* arguments, int numArguments) const
705{
706 if (auto* o = getDynamicObject())
707 return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments));
708
709 return {};
710}
711
713{
714 return invoke (method, nullptr, 0);
715}
716
717var var::call (const Identifier& method, const var& arg1) const
718{
719 return invoke (method, &arg1, 1);
720}
721
722var var::call (const Identifier& method, const var& arg1, const var& arg2) const
723{
724 var args[] = { arg1, arg2 };
725 return invoke (method, args, 2);
726}
727
728var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3)
729{
730 var args[] = { arg1, arg2, arg3 };
731 return invoke (method, args, 3);
732}
733
734var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
735{
736 var args[] = { arg1, arg2, arg3, arg4 };
737 return invoke (method, args, 4);
738}
739
740var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
741{
742 var args[] = { arg1, arg2, arg3, arg4, arg5 };
743 return invoke (method, args, 5);
744}
745
746//==============================================================================
747int var::size() const
748{
749 if (auto array = getArray())
750 return array->size();
751
752 return 0;
753}
754
756{
757 auto array = getArray();
758
759 // When using this method, the var must actually be an array, and the index
760 // must be in-range!
761 jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
762
763 return array->getReference (arrayIndex);
764}
765
767{
768 auto array = getArray();
769
770 // When using this method, the var must actually be an array, and the index
771 // must be in-range!
772 jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
773
774 return array->getReference (arrayIndex);
775}
776
777Array<var>* var::convertToArray()
778{
779 if (auto array = getArray())
780 return array;
781
783
784 if (! isVoid())
785 tempVar.add (*this);
786
787 *this = tempVar;
788 return getArray();
789}
790
791void var::append (const var& n)
792{
793 convertToArray()->add (n);
794}
795
796void var::remove (const int index)
797{
798 if (auto array = getArray())
799 array->remove (index);
800}
801
802void var::insert (const int index, const var& n)
803{
804 convertToArray()->insert (index, n);
805}
806
808{
809 convertToArray()->resize (numArrayElementsWanted);
810}
811
812int var::indexOf (const var& n) const
813{
814 if (auto array = getArray())
815 return array->indexOf (n);
816
817 return -1;
818}
819
820//==============================================================================
822{
823 type->writeToStream (value, output);
824}
825
827{
828 const int numBytes = input.readCompressedInt();
829
830 if (numBytes > 0)
831 {
832 switch (input.readByte())
833 {
834 case varMarker_Int: return var (input.readInt());
835 case varMarker_Int64: return var (input.readInt64());
836 case varMarker_BoolTrue: return var (true);
837 case varMarker_BoolFalse: return var (false);
838 case varMarker_Double: return var (input.readDouble());
839
840 case varMarker_String:
841 {
843 mo.writeFromInputStream (input, numBytes - 1);
844 return var (mo.toUTF8());
845 }
846
847 case varMarker_Binary:
848 {
849 MemoryBlock mb ((size_t) numBytes - 1);
850
851 if (numBytes > 1)
852 {
853 const int numRead = input.read (mb.getData(), numBytes - 1);
854 mb.setSize ((size_t) numRead);
855 }
856
857 return var (mb);
858 }
859
860 case varMarker_Array:
861 {
862 var v;
863 auto* destArray = v.convertToArray();
864
865 for (int i = input.readCompressedInt(); --i >= 0;)
866 destArray->add (readFromStream (input));
867
868 return v;
869 }
870
871 default:
872 input.skipNextBytes (numBytes - 1); break;
873 }
874 }
875
876 return {};
877}
878
879var::NativeFunctionArgs::NativeFunctionArgs (const var& t, const var* args, int numArgs) noexcept
880 : thisObject (t), arguments (args), numArguments (numArgs)
881{
882}
883
884//==============================================================================
885#if JUCE_ALLOW_STATIC_NULL_VARIABLES
886
887JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
888JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
889
890const var var::null;
891
892JUCE_END_IGNORE_WARNINGS_GCC_LIKE
893JUCE_END_IGNORE_WARNINGS_MSVC
894
895#endif
896
897} // namespace juce
virtual int64 readInt64()
virtual int readCompressedInt()
virtual void skipNextBytes(int64 numBytesToSkip)
virtual int read(void *destBuffer, int maxBytesToRead)=0
virtual double readDouble()
virtual char readByte()
static String toHexString(IntegerType number)
static String charToString(juce_wchar character)
static var undefined() noexcept
void insert(int index, const var &value)
int size() const
var invoke(const Identifier &method, const var *arguments, int numArguments) const
void writeToStream(OutputStream &output) const
var() noexcept
~var() noexcept
Array< var > * getArray() const noexcept
int indexOf(const var &value) const
const var & operator[](int arrayIndex) const
NativeFunction getNativeFunction() const
bool hasProperty(const Identifier &propertyName) const noexcept
static var readFromStream(InputStream &input)
void append(const var &valueToAppend)
bool equals(const var &other) const noexcept
bool equalsWithSameType(const var &other) const noexcept
void resize(int numArrayElementsWanted)
var getProperty(const Identifier &propertyName, const var &defaultReturnValue) const
void remove(int index)
var call(const Identifier &method) const
bool hasSameTypeAs(const var &other) const noexcept
var clone() const noexcept
MemoryBlock * getBinaryData() const noexcept