VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_core / containers / juce_Variant.cpp
blob2321da3d81c3332a97b20db30c53c63ed4ba0c3c
1 /*
2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
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.
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.
20 ==============================================================================
23 namespace juce
26 enum VariantStreamMarkers
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
39 //==============================================================================
40 struct var::VariantType
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 {};
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;
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;
80 bool (*equals) (const ValueUnion&, const ValueUnion&, const VariantType&) = nullptr;
81 void (*writeToStream) (const ValueUnion&, OutputStream&) = nullptr;
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; }
96 // void ========================================================================
97 static bool voidEquals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) noexcept
99 return otherType.isVoid || otherType.isUndefined;
102 static void voidWriteToStream (const ValueUnion&, OutputStream& output)
104 output.writeCompressedInt (0);
107 constexpr explicit VariantType (VoidTag) noexcept
108 : isVoid (true),
109 isComparable (true),
110 equals (voidEquals),
111 writeToStream (voidWriteToStream) {}
113 // undefined ===================================================================
114 static String undefinedToString (const ValueUnion&) { return "undefined"; }
116 static bool undefinedEquals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) noexcept
118 return otherType.isVoid || otherType.isUndefined;
121 static void undefinedWriteToStream (const ValueUnion&, OutputStream& output)
123 output.writeCompressedInt (1);
124 output.writeByte (varMarker_Undefined);
127 constexpr explicit VariantType (UndefinedTag) noexcept
128 : isUndefined (true),
129 toString (undefinedToString),
130 equals (undefinedEquals),
131 writeToStream (undefinedWriteToStream) {}
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; }
140 static bool intEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
142 if (otherType.isDouble || otherType.isInt64 || otherType.isString)
143 return otherType.equals (otherData, data, VariantType { IntTag{} });
145 return otherType.toInt (otherData) == data.intValue;
148 static void intWriteToStream (const ValueUnion& data, OutputStream& output)
150 output.writeCompressedInt (5);
151 output.writeByte (varMarker_Int);
152 output.writeInt (data.intValue);
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) {}
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; }
173 static bool int64Equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
175 if (otherType.isDouble || otherType.isString)
176 return otherType.equals (otherData, data, VariantType { Int64Tag{} });
178 return otherType.toInt64 (otherData) == data.int64Value;
181 static void int64WriteToStream (const ValueUnion& data, OutputStream& output)
183 output.writeCompressedInt (9);
184 output.writeByte (varMarker_Int64);
185 output.writeInt64 (data.int64Value);
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) {}
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 data.doubleValue != 0.0; }
206 static bool doubleEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
208 return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
211 static void doubleWriteToStream (const ValueUnion& data, OutputStream& output)
213 output.writeCompressedInt (9);
214 output.writeByte (varMarker_Double);
215 output.writeDouble (data.doubleValue);
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) {}
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; }
236 static bool boolEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
238 return otherType.toBool (otherData) == data.boolValue;
241 static void boolWriteToStream (const ValueUnion& data, OutputStream& output)
243 output.writeCompressedInt (1);
244 output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
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) {}
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); }
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
268 return getString (data)->getIntValue() != 0
269 || getString (data)->trim().equalsIgnoreCase ("true")
270 || getString (data)->trim().equalsIgnoreCase ("yes");
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)); }
276 static bool stringEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
278 return otherType.toString (otherData) == *getString (data);
281 static void stringWriteToStream (const ValueUnion& data, OutputStream& output)
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);
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) {}
305 // object ======================================================================
306 static String objectToString (const ValueUnion& data)
308 return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue);
311 static bool objectToBool (const ValueUnion& data) noexcept { return data.objectValue != nullptr; }
312 static ReferenceCountedObject* objectToObject (const ValueUnion& data) noexcept { return data.objectValue; }
314 static var objectClone (const var& original)
316 if (auto* d = original.getDynamicObject())
317 return d->clone().get();
319 jassertfalse; // can only clone DynamicObjects!
320 return {};
323 static void objectCleanUp (ValueUnion& data) noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
325 static void objectCreateCopy (ValueUnion& dest, const ValueUnion& source)
327 dest.objectValue = source.objectValue;
328 if (dest.objectValue != nullptr)
329 dest.objectValue->incReferenceCount();
332 static bool objectEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
334 return otherType.toObject (otherData) == data.objectValue;
337 static void objectWriteToStream (const ValueUnion&, OutputStream& output)
339 jassertfalse; // Can't write an object to a stream!
340 output.writeCompressedInt (0);
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) {}
354 // array =======================================================================
355 static String arrayToString (const ValueUnion&) { return "[Array]"; }
356 static ReferenceCountedObject* arrayToObject (const ValueUnion&) noexcept { return nullptr; }
358 static Array<var>* arrayToArray (const ValueUnion& data) noexcept
360 if (auto* a = dynamic_cast<RefCountedArray*> (data.objectValue))
361 return &(a->array);
363 return nullptr;
366 static bool arrayEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
368 auto* thisArray = arrayToArray (data);
369 auto* otherArray = otherType.toArray (otherData);
370 return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
373 static var arrayClone (const var& original)
375 Array<var> arrayCopy;
377 if (auto* array = arrayToArray (original.value))
379 arrayCopy.ensureStorageAllocated (array->size());
381 for (auto& i : *array)
382 arrayCopy.add (i.clone());
385 return var (arrayCopy);
388 static void arrayWriteToStream (const ValueUnion& data, OutputStream& output)
390 if (auto* array = arrayToArray (data))
392 MemoryOutputStream buffer (512);
393 buffer.writeCompressedInt (array->size());
395 for (auto& i : *array)
396 i.writeToStream (buffer);
398 output.writeCompressedInt (1 + (int) buffer.getDataSize());
399 output.writeByte (varMarker_Array);
400 output << buffer;
404 struct RefCountedArray : public ReferenceCountedObject
406 RefCountedArray (const Array<var>& a) : array (a) { incReferenceCount(); }
407 RefCountedArray (Array<var>&& a) : array (std::move (a)) { incReferenceCount(); }
408 Array<var> array;
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) {}
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); }
428 static String binaryToString (const ValueUnion& data) { return data.binaryValue->toBase64Encoding(); }
429 static MemoryBlock* binaryToBinary (const ValueUnion& data) noexcept { return data.binaryValue; }
431 static bool binaryEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
433 const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
434 return otherBlock != nullptr && *otherBlock == *data.binaryValue;
437 static void binaryWriteToStream (const ValueUnion& data, OutputStream& output)
439 output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
440 output.writeByte (varMarker_Binary);
441 output << *data.binaryValue;
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) {}
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); }
457 static String methodToString (const ValueUnion&) { return "Method"; }
458 static bool methodToBool (const ValueUnion& data) noexcept { return data.methodValue != nullptr; }
460 static bool methodEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
462 return otherType.isMethod && otherData.methodValue == data.methodValue;
465 static void methodWriteToStream (const ValueUnion&, OutputStream& output)
467 jassertfalse; // Can't write a method to a stream!
468 output.writeCompressedInt (0);
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) {}
481 struct var::Instance
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{} };
496 constexpr var::VariantType var::Instance::attributesVoid;
497 constexpr var::VariantType var::Instance::attributesUndefined;
498 constexpr var::VariantType var::Instance::attributesInt;
499 constexpr var::VariantType var::Instance::attributesInt64;
500 constexpr var::VariantType var::Instance::attributesBool;
501 constexpr var::VariantType var::Instance::attributesDouble;
502 constexpr var::VariantType var::Instance::attributesMethod;
503 constexpr var::VariantType var::Instance::attributesArray;
504 constexpr var::VariantType var::Instance::attributesString;
505 constexpr var::VariantType var::Instance::attributesBinary;
506 constexpr var::VariantType var::Instance::attributesObject;
508 //==============================================================================
509 var::var() noexcept : type (&Instance::attributesVoid) {}
510 var::var (const VariantType& t) noexcept : type (&t) {}
511 var::~var() noexcept { type->cleanUp (value); }
513 //==============================================================================
514 var::var (const var& valueToCopy) : type (valueToCopy.type)
516 type->createCopy (value, valueToCopy.value);
519 var::var (const int v) noexcept : type (&Instance::attributesInt) { value.intValue = v; }
520 var::var (const int64 v) noexcept : type (&Instance::attributesInt64) { value.int64Value = v; }
521 var::var (const bool v) noexcept : type (&Instance::attributesBool) { value.boolValue = v; }
522 var::var (const double v) noexcept : type (&Instance::attributesDouble) { value.doubleValue = v; }
523 var::var (NativeFunction m) noexcept : type (&Instance::attributesMethod) { value.methodValue = new NativeFunction (m); }
524 var::var (const Array<var>& v) : type (&Instance::attributesArray) { value.objectValue = new VariantType::RefCountedArray (v); }
525 var::var (const String& v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
526 var::var (const char* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
527 var::var (const wchar_t* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
528 var::var (const void* v, size_t sz) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v, sz); }
529 var::var (const MemoryBlock& v) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v); }
531 var::var (const StringArray& v) : type (&Instance::attributesArray)
533 Array<var> strings;
534 strings.ensureStorageAllocated (v.size());
536 for (auto& i : v)
537 strings.add (var (i));
539 value.objectValue = new VariantType::RefCountedArray (strings);
542 var::var (ReferenceCountedObject* const object) : type (&Instance::attributesObject)
544 value.objectValue = object;
546 if (object != nullptr)
547 object->incReferenceCount();
550 var var::undefined() noexcept { return var (Instance::attributesUndefined); }
552 //==============================================================================
553 bool var::isVoid() const noexcept { return type->isVoid; }
554 bool var::isUndefined() const noexcept { return type->isUndefined; }
555 bool var::isInt() const noexcept { return type->isInt; }
556 bool var::isInt64() const noexcept { return type->isInt64; }
557 bool var::isBool() const noexcept { return type->isBool; }
558 bool var::isDouble() const noexcept { return type->isDouble; }
559 bool var::isString() const noexcept { return type->isString; }
560 bool var::isObject() const noexcept { return type->isObject; }
561 bool var::isArray() const noexcept { return type->isArray; }
562 bool var::isBinaryData() const noexcept { return type->isBinary; }
563 bool var::isMethod() const noexcept { return type->isMethod; }
565 var::operator int() const noexcept { return type->toInt (value); }
566 var::operator int64() const noexcept { return type->toInt64 (value); }
567 var::operator bool() const noexcept { return type->toBool (value); }
568 var::operator float() const noexcept { return (float) type->toDouble (value); }
569 var::operator double() const noexcept { return type->toDouble (value); }
570 String var::toString() const { return type->toString (value); }
571 var::operator String() const { return type->toString (value); }
572 ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
573 Array<var>* var::getArray() const noexcept { return type->toArray (value); }
574 MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
575 DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast<DynamicObject*> (getObject()); }
577 //==============================================================================
578 void var::swapWith (var& other) noexcept
580 std::swap (type, other.type);
581 std::swap (value, other.value);
584 var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
585 var& var::operator= (const int v) { type->cleanUp (value); type = &Instance::attributesInt; value.intValue = v; return *this; }
586 var& var::operator= (const int64 v) { type->cleanUp (value); type = &Instance::attributesInt64; value.int64Value = v; return *this; }
587 var& var::operator= (const bool v) { type->cleanUp (value); type = &Instance::attributesBool; value.boolValue = v; return *this; }
588 var& var::operator= (const double v) { type->cleanUp (value); type = &Instance::attributesDouble; value.doubleValue = v; return *this; }
589 var& var::operator= (const char* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
590 var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
591 var& var::operator= (const String& v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
592 var& var::operator= (const MemoryBlock& v) { type->cleanUp (value); type = &Instance::attributesBinary; value.binaryValue = new MemoryBlock (v); return *this; }
593 var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
594 var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
595 var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; }
597 var::var (var&& other) noexcept
598 : type (other.type),
599 value (other.value)
601 other.type = &Instance::attributesVoid;
604 var& var::operator= (var&& other) noexcept
606 swapWith (other);
607 return *this;
610 var::var (String&& v) : type (&Instance::attributesString)
612 new (value.stringValue) String (std::move (v));
615 var::var (MemoryBlock&& v) : type (&Instance::attributesBinary)
617 value.binaryValue = new MemoryBlock (std::move (v));
620 var::var (Array<var>&& v) : type (&Instance::attributesArray)
622 value.objectValue = new VariantType::RefCountedArray (std::move (v));
625 var& var::operator= (String&& v)
627 type->cleanUp (value);
628 type = &Instance::attributesString;
629 new (value.stringValue) String (std::move (v));
630 return *this;
633 //==============================================================================
634 bool var::equals (const var& other) const noexcept
636 return type->equals (value, other.value, *other.type);
639 bool var::equalsWithSameType (const var& other) const noexcept
641 return hasSameTypeAs (other) && equals (other);
644 bool var::hasSameTypeAs (const var& other) const noexcept
646 return type == other.type;
649 bool canCompare (const var& v1, const var& v2)
651 return v1.type->isComparable && v2.type->isComparable;
654 static int compare (const var& v1, const var& v2)
656 if (v1.isString() && v2.isString())
657 return v1.toString().compare (v2.toString());
659 auto diff = static_cast<double> (v1) - static_cast<double> (v2);
660 return diff == 0 ? 0 : (diff < 0 ? -1 : 1);
663 bool operator== (const var& v1, const var& v2) { return v1.equals (v2); }
664 bool operator!= (const var& v1, const var& v2) { return ! v1.equals (v2); }
665 bool operator< (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) < 0; }
666 bool operator> (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) > 0; }
667 bool operator<= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) <= 0; }
668 bool operator>= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) >= 0; }
670 bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
671 bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
672 bool operator== (const var& v1, const char* v2) { return v1.toString() == v2; }
673 bool operator!= (const var& v1, const char* v2) { return v1.toString() != v2; }
675 //==============================================================================
676 var var::clone() const noexcept
678 return type->clone (*this);
681 //==============================================================================
682 const var& var::operator[] (const Identifier& propertyName) const
684 if (auto* o = getDynamicObject())
685 return o->getProperty (propertyName);
687 return getNullVarRef();
690 const var& var::operator[] (const char* const propertyName) const
692 return operator[] (Identifier (propertyName));
695 var var::getProperty (const Identifier& propertyName, const var& defaultReturnValue) const
697 if (auto* o = getDynamicObject())
698 return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
700 return defaultReturnValue;
703 bool var::hasProperty (const Identifier& propertyName) const noexcept
705 if (auto* o = getDynamicObject())
706 return o->hasProperty (propertyName);
708 return false;
711 var::NativeFunction var::getNativeFunction() const
713 return isMethod() && (value.methodValue != nullptr) ? *value.methodValue : nullptr;
716 var var::invoke (const Identifier& method, const var* arguments, int numArguments) const
718 if (auto* o = getDynamicObject())
719 return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments));
721 return {};
724 var var::call (const Identifier& method) const
726 return invoke (method, nullptr, 0);
729 var var::call (const Identifier& method, const var& arg1) const
731 return invoke (method, &arg1, 1);
734 var var::call (const Identifier& method, const var& arg1, const var& arg2) const
736 var args[] = { arg1, arg2 };
737 return invoke (method, args, 2);
740 var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3)
742 var args[] = { arg1, arg2, arg3 };
743 return invoke (method, args, 3);
746 var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
748 var args[] = { arg1, arg2, arg3, arg4 };
749 return invoke (method, args, 4);
752 var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
754 var args[] = { arg1, arg2, arg3, arg4, arg5 };
755 return invoke (method, args, 5);
758 //==============================================================================
759 int var::size() const
761 if (auto array = getArray())
762 return array->size();
764 return 0;
767 const var& var::operator[] (int arrayIndex) const
769 auto array = getArray();
771 // When using this method, the var must actually be an array, and the index
772 // must be in-range!
773 jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
775 return array->getReference (arrayIndex);
778 var& var::operator[] (int arrayIndex)
780 auto array = getArray();
782 // When using this method, the var must actually be an array, and the index
783 // must be in-range!
784 jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
786 return array->getReference (arrayIndex);
789 Array<var>* var::convertToArray()
791 if (auto array = getArray())
792 return array;
794 Array<var> tempVar;
796 if (! isVoid())
797 tempVar.add (*this);
799 *this = tempVar;
800 return getArray();
803 void var::append (const var& n)
805 convertToArray()->add (n);
808 void var::remove (const int index)
810 if (auto array = getArray())
811 array->remove (index);
814 void var::insert (const int index, const var& n)
816 convertToArray()->insert (index, n);
819 void var::resize (const int numArrayElementsWanted)
821 convertToArray()->resize (numArrayElementsWanted);
824 int var::indexOf (const var& n) const
826 if (auto array = getArray())
827 return array->indexOf (n);
829 return -1;
832 //==============================================================================
833 void var::writeToStream (OutputStream& output) const
835 type->writeToStream (value, output);
838 var var::readFromStream (InputStream& input)
840 const int numBytes = input.readCompressedInt();
842 if (numBytes > 0)
844 switch (input.readByte())
846 case varMarker_Int: return var (input.readInt());
847 case varMarker_Int64: return var (input.readInt64());
848 case varMarker_BoolTrue: return var (true);
849 case varMarker_BoolFalse: return var (false);
850 case varMarker_Double: return var (input.readDouble());
852 case varMarker_String:
854 MemoryOutputStream mo;
855 mo.writeFromInputStream (input, numBytes - 1);
856 return var (mo.toUTF8());
859 case varMarker_Binary:
861 MemoryBlock mb ((size_t) numBytes - 1);
863 if (numBytes > 1)
865 const int numRead = input.read (mb.getData(), numBytes - 1);
866 mb.setSize ((size_t) numRead);
869 return var (mb);
872 case varMarker_Array:
874 var v;
875 auto* destArray = v.convertToArray();
877 for (int i = input.readCompressedInt(); --i >= 0;)
878 destArray->add (readFromStream (input));
880 return v;
883 default:
884 input.skipNextBytes (numBytes - 1); break;
888 return {};
891 var::NativeFunctionArgs::NativeFunctionArgs (const var& t, const var* args, int numArgs) noexcept
892 : thisObject (t), arguments (args), numArguments (numArgs)
896 //==============================================================================
897 #if JUCE_ALLOW_STATIC_NULL_VARIABLES
899 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
900 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
902 const var var::null;
904 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
905 JUCE_END_IGNORE_WARNINGS_MSVC
907 #endif
909 } // namespace juce