OpenShot Audio Library | OpenShotAudio  0.6.0
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 
23 namespace juce
24 {
25 
26 enum 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 //==============================================================================
40 struct 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 
481 struct 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 //==============================================================================
497 var::var() noexcept : type (&Instance::attributesVoid) {}
498 var::var (const VariantType& t) noexcept : type (&t) {}
499 var::~var() noexcept { type->cleanUp (value); }
500 
501 //==============================================================================
502 var::var (const var& valueToCopy) : type (valueToCopy.type)
503 {
504  type->createCopy (value, valueToCopy.value);
505 }
506 
507 var::var (const int v) noexcept : type (&Instance::attributesInt) { value.intValue = v; }
508 var::var (const int64 v) noexcept : type (&Instance::attributesInt64) { value.int64Value = v; }
509 var::var (const bool v) noexcept : type (&Instance::attributesBool) { value.boolValue = v; }
510 var::var (const double v) noexcept : type (&Instance::attributesDouble) { value.doubleValue = v; }
511 var::var (NativeFunction m) noexcept : type (&Instance::attributesMethod) { value.methodValue = new NativeFunction (m); }
512 var::var (const Array<var>& v) : type (&Instance::attributesArray) { value.objectValue = new VariantType::RefCountedArray (v); }
513 var::var (const String& v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
514 var::var (const char* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
515 var::var (const wchar_t* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
516 var::var (const void* v, size_t sz) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v, sz); }
517 var::var (const MemoryBlock& v) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v); }
518 
519 var::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 
530 var::var (ReferenceCountedObject* const object) : type (&Instance::attributesObject)
531 {
532  value.objectValue = object;
533 
534  if (object != nullptr)
535  object->incReferenceCount();
536 }
537 
538 var var::undefined() noexcept { return var (Instance::attributesUndefined); }
539 
540 //==============================================================================
541 bool var::isVoid() const noexcept { return type->isVoid; }
542 bool var::isUndefined() const noexcept { return type->isUndefined; }
543 bool var::isInt() const noexcept { return type->isInt; }
544 bool var::isInt64() const noexcept { return type->isInt64; }
545 bool var::isBool() const noexcept { return type->isBool; }
546 bool var::isDouble() const noexcept { return type->isDouble; }
547 bool var::isString() const noexcept { return type->isString; }
548 bool var::isObject() const noexcept { return type->isObject; }
549 bool var::isArray() const noexcept { return type->isArray; }
550 bool var::isBinaryData() const noexcept { return type->isBinary; }
551 bool var::isMethod() const noexcept { return type->isMethod; }
552 
553 var::operator int() const noexcept { return type->toInt (value); }
554 var::operator int64() const noexcept { return type->toInt64 (value); }
555 var::operator bool() const noexcept { return type->toBool (value); }
556 var::operator float() const noexcept { return (float) type->toDouble (value); }
557 var::operator double() const noexcept { return type->toDouble (value); }
558 String var::toString() const { return type->toString (value); }
559 var::operator String() const { return type->toString (value); }
560 ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
561 Array<var>* var::getArray() const noexcept { return type->toArray (value); }
562 MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
563 DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast<DynamicObject*> (getObject()); }
564 
565 //==============================================================================
566 void var::swapWith (var& other) noexcept
567 {
568  std::swap (type, other.type);
569  std::swap (value, other.value);
570 }
571 
572 var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
573 var& var::operator= (const int v) { type->cleanUp (value); type = &Instance::attributesInt; value.intValue = v; return *this; }
574 var& var::operator= (const int64 v) { type->cleanUp (value); type = &Instance::attributesInt64; value.int64Value = v; return *this; }
575 var& var::operator= (const bool v) { type->cleanUp (value); type = &Instance::attributesBool; value.boolValue = v; return *this; }
576 var& var::operator= (const double v) { type->cleanUp (value); type = &Instance::attributesDouble; value.doubleValue = v; return *this; }
577 var& var::operator= (const char* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
578 var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
579 var& var::operator= (const String& v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
580 var& var::operator= (const MemoryBlock& v) { type->cleanUp (value); type = &Instance::attributesBinary; value.binaryValue = new MemoryBlock (v); return *this; }
581 var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
582 var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
583 var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; }
584 
585 var::var (var&& other) noexcept
586  : type (other.type),
587  value (other.value)
588 {
589  other.type = &Instance::attributesVoid;
590 }
591 
592 var& var::operator= (var&& other) noexcept
593 {
594  swapWith (other);
595  return *this;
596 }
597 
598 var::var (String&& v) : type (&Instance::attributesString)
599 {
600  new (value.stringValue) String (std::move (v));
601 }
602 
603 var::var (MemoryBlock&& v) : type (&Instance::attributesBinary)
604 {
605  value.binaryValue = new MemoryBlock (std::move (v));
606 }
607 
608 var::var (Array<var>&& v) : type (&Instance::attributesArray)
609 {
610  value.objectValue = new VariantType::RefCountedArray (std::move (v));
611 }
612 
613 var& 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 //==============================================================================
622 bool var::equals (const var& other) const noexcept
623 {
624  return type->equals (value, other.value, *other.type);
625 }
626 
627 bool var::equalsWithSameType (const var& other) const noexcept
628 {
629  return hasSameTypeAs (other) && equals (other);
630 }
631 
632 bool var::hasSameTypeAs (const var& other) const noexcept
633 {
634  return type == other.type;
635 }
636 
637 bool canCompare (const var& v1, const var& v2)
638 {
639  return v1.type->isComparable && v2.type->isComparable;
640 }
641 
642 static 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 
651 bool operator== (const var& v1, const var& v2) { return v1.equals (v2); }
652 bool operator!= (const var& v1, const var& v2) { return ! v1.equals (v2); }
653 bool operator< (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) < 0; }
654 bool operator> (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) > 0; }
655 bool operator<= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) <= 0; }
656 bool operator>= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) >= 0; }
657 
658 bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
659 bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
660 bool operator== (const var& v1, const char* v2) { return v1.toString() == v2; }
661 bool operator!= (const var& v1, const char* v2) { return v1.toString() != v2; }
662 
663 //==============================================================================
664 var var::clone() const noexcept
665 {
666  return type->clone (*this);
667 }
668 
669 //==============================================================================
670 const var& var::operator[] (const Identifier& propertyName) const
671 {
672  if (auto* o = getDynamicObject())
673  return o->getProperty (propertyName);
674 
675  return getNullVarRef();
676 }
677 
678 const var& var::operator[] (const char* const propertyName) const
679 {
680  return operator[] (Identifier (propertyName));
681 }
682 
683 var var::getProperty (const Identifier& propertyName, const var& defaultReturnValue) const
684 {
685  if (auto* o = getDynamicObject())
686  return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
687 
688  return defaultReturnValue;
689 }
690 
691 bool var::hasProperty (const Identifier& propertyName) const noexcept
692 {
693  if (auto* o = getDynamicObject())
694  return o->hasProperty (propertyName);
695 
696  return false;
697 }
698 
699 var::NativeFunction var::getNativeFunction() const
700 {
701  return isMethod() && (value.methodValue != nullptr) ? *value.methodValue : nullptr;
702 }
703 
704 var 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 
712 var var::call (const Identifier& method) const
713 {
714  return invoke (method, nullptr, 0);
715 }
716 
717 var var::call (const Identifier& method, const var& arg1) const
718 {
719  return invoke (method, &arg1, 1);
720 }
721 
722 var 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 
728 var 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 
734 var 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 
740 var 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 //==============================================================================
747 int var::size() const
748 {
749  if (auto array = getArray())
750  return array->size();
751 
752  return 0;
753 }
754 
755 const var& var::operator[] (int arrayIndex) const
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 
766 var& var::operator[] (int arrayIndex)
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 
777 Array<var>* var::convertToArray()
778 {
779  if (auto array = getArray())
780  return array;
781 
782  Array<var> tempVar;
783 
784  if (! isVoid())
785  tempVar.add (*this);
786 
787  *this = tempVar;
788  return getArray();
789 }
790 
791 void var::append (const var& n)
792 {
793  convertToArray()->add (n);
794 }
795 
796 void var::remove (const int index)
797 {
798  if (auto array = getArray())
799  array->remove (index);
800 }
801 
802 void var::insert (const int index, const var& n)
803 {
804  convertToArray()->insert (index, n);
805 }
806 
807 void var::resize (const int numArrayElementsWanted)
808 {
809  convertToArray()->resize (numArrayElementsWanted);
810 }
811 
812 int var::indexOf (const var& n) const
813 {
814  if (auto array = getArray())
815  return array->indexOf (n);
816 
817  return -1;
818 }
819 
820 //==============================================================================
821 void var::writeToStream (OutputStream& output) const
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 
879 var::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 
887 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
888 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
889 
890 const var var::null;
891 
892 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
893 JUCE_END_IGNORE_WARNINGS_MSVC
894 
895 #endif
896 
897 } // namespace juce
void add(const ElementType &newElement)
Definition: juce_Array.h:418
virtual int64 readInt64()
virtual int readCompressedInt()
virtual void skipNextBytes(int64 numBytesToSkip)
virtual int read(void *destBuffer, int maxBytesToRead)=0
virtual int readInt()
virtual double readDouble()
virtual char readByte()
void * getData() noexcept
void setSize(size_t newSize, bool initialiseNewSpaceToZero=false)
int64 writeFromInputStream(InputStream &, int64 maxNumBytesToWrite) override
static String toHexString(IntegerType number)
Definition: juce_String.h:1097
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