The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
22KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_Variant.h"
  21. #include "juce_DynamicObject.h"
  22. #include "../io/streams/juce_MemoryOutputStream.h"
  23. enum VariantStreamMarkers
  24. {
  25. varMarker_Int = 1,
  26. varMarker_BoolTrue = 2,
  27. varMarker_BoolFalse = 3,
  28. varMarker_Double = 4,
  29. varMarker_String = 5,
  30. varMarker_Int64 = 6
  31. };
  32. //==============================================================================
  33. class var::VariantType
  34. {
  35. public:
  36. VariantType() noexcept {}
  37. virtual ~VariantType() noexcept {}
  38. virtual int toInt (const ValueUnion&) const noexcept { return 0; }
  39. virtual int64 toInt64 (const ValueUnion&) const noexcept { return 0; }
  40. virtual double toDouble (const ValueUnion&) const noexcept { return 0; }
  41. virtual String toString (const ValueUnion&) const { return String::empty; }
  42. virtual bool toBool (const ValueUnion&) const noexcept { return false; }
  43. virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
  44. virtual bool isVoid() const noexcept { return false; }
  45. virtual bool isInt() const noexcept { return false; }
  46. virtual bool isInt64() const noexcept { return false; }
  47. virtual bool isBool() const noexcept { return false; }
  48. virtual bool isDouble() const noexcept { return false; }
  49. virtual bool isString() const noexcept { return false; }
  50. virtual bool isObject() const noexcept { return false; }
  51. virtual bool isMethod() const noexcept { return false; }
  52. virtual void cleanUp (ValueUnion&) const noexcept {}
  53. virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; }
  54. virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0;
  55. virtual void writeToStream (const ValueUnion& data, OutputStream& output) const = 0;
  56. };
  57. //==============================================================================
  58. class var::VariantType_Void : public var::VariantType
  59. {
  60. public:
  61. VariantType_Void() noexcept {}
  62. static const VariantType_Void instance;
  63. bool isVoid() const noexcept { return true; }
  64. bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept { return otherType.isVoid(); }
  65. void writeToStream (const ValueUnion&, OutputStream& output) const { output.writeCompressedInt (0); }
  66. };
  67. //==============================================================================
  68. class var::VariantType_Int : public var::VariantType
  69. {
  70. public:
  71. VariantType_Int() noexcept {}
  72. static const VariantType_Int instance;
  73. int toInt (const ValueUnion& data) const noexcept { return data.intValue; };
  74. int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.intValue; };
  75. double toDouble (const ValueUnion& data) const noexcept { return (double) data.intValue; }
  76. String toString (const ValueUnion& data) const { return String (data.intValue); }
  77. bool toBool (const ValueUnion& data) const noexcept { return data.intValue != 0; }
  78. bool isInt() const noexcept { return true; }
  79. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  80. {
  81. return otherType.toInt (otherData) == data.intValue;
  82. }
  83. void writeToStream (const ValueUnion& data, OutputStream& output) const
  84. {
  85. output.writeCompressedInt (5);
  86. output.writeByte (varMarker_Int);
  87. output.writeInt (data.intValue);
  88. }
  89. };
  90. //==============================================================================
  91. class var::VariantType_Int64 : public var::VariantType
  92. {
  93. public:
  94. VariantType_Int64() noexcept {}
  95. static const VariantType_Int64 instance;
  96. int toInt (const ValueUnion& data) const noexcept { return (int) data.int64Value; };
  97. int64 toInt64 (const ValueUnion& data) const noexcept { return data.int64Value; };
  98. double toDouble (const ValueUnion& data) const noexcept { return (double) data.int64Value; }
  99. String toString (const ValueUnion& data) const { return String (data.int64Value); }
  100. bool toBool (const ValueUnion& data) const noexcept { return data.int64Value != 0; }
  101. bool isInt64() const noexcept { return true; }
  102. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  103. {
  104. return otherType.toInt64 (otherData) == data.int64Value;
  105. }
  106. void writeToStream (const ValueUnion& data, OutputStream& output) const
  107. {
  108. output.writeCompressedInt (9);
  109. output.writeByte (varMarker_Int64);
  110. output.writeInt64 (data.int64Value);
  111. }
  112. };
  113. //==============================================================================
  114. class var::VariantType_Double : public var::VariantType
  115. {
  116. public:
  117. VariantType_Double() noexcept {}
  118. static const VariantType_Double instance;
  119. int toInt (const ValueUnion& data) const noexcept { return (int) data.doubleValue; };
  120. int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.doubleValue; };
  121. double toDouble (const ValueUnion& data) const noexcept { return data.doubleValue; }
  122. String toString (const ValueUnion& data) const { return String (data.doubleValue); }
  123. bool toBool (const ValueUnion& data) const noexcept { return data.doubleValue != 0; }
  124. bool isDouble() const noexcept { return true; }
  125. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  126. {
  127. return otherType.toDouble (otherData) == data.doubleValue;
  128. }
  129. void writeToStream (const ValueUnion& data, OutputStream& output) const
  130. {
  131. output.writeCompressedInt (9);
  132. output.writeByte (varMarker_Double);
  133. output.writeDouble (data.doubleValue);
  134. }
  135. };
  136. //==============================================================================
  137. class var::VariantType_Bool : public var::VariantType
  138. {
  139. public:
  140. VariantType_Bool() noexcept {}
  141. static const VariantType_Bool instance;
  142. int toInt (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
  143. int64 toInt64 (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
  144. double toDouble (const ValueUnion& data) const noexcept { return data.boolValue ? 1.0 : 0.0; }
  145. String toString (const ValueUnion& data) const { return String::charToString (data.boolValue ? '1' : '0'); }
  146. bool toBool (const ValueUnion& data) const noexcept { return data.boolValue; }
  147. bool isBool() const noexcept { return true; }
  148. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  149. {
  150. return otherType.toBool (otherData) == data.boolValue;
  151. }
  152. void writeToStream (const ValueUnion& data, OutputStream& output) const
  153. {
  154. output.writeCompressedInt (1);
  155. output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
  156. }
  157. };
  158. //==============================================================================
  159. class var::VariantType_String : public var::VariantType
  160. {
  161. public:
  162. VariantType_String() noexcept {}
  163. static const VariantType_String instance;
  164. void cleanUp (ValueUnion& data) const noexcept { getString (data)-> ~String(); }
  165. void createCopy (ValueUnion& dest, const ValueUnion& source) const { new (dest.stringValue) String (*getString (source)); }
  166. bool isString() const noexcept { return true; }
  167. int toInt (const ValueUnion& data) const noexcept { return getString (data)->getIntValue(); };
  168. int64 toInt64 (const ValueUnion& data) const noexcept { return getString (data)->getLargeIntValue(); };
  169. double toDouble (const ValueUnion& data) const noexcept { return getString (data)->getDoubleValue(); }
  170. String toString (const ValueUnion& data) const { return *getString (data); }
  171. bool toBool (const ValueUnion& data) const noexcept { return getString (data)->getIntValue() != 0
  172. || getString (data)->trim().equalsIgnoreCase ("true")
  173. || getString (data)->trim().equalsIgnoreCase ("yes"); }
  174. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  175. {
  176. return otherType.toString (otherData) == *getString (data);
  177. }
  178. void writeToStream (const ValueUnion& data, OutputStream& output) const
  179. {
  180. const String* const s = getString (data);
  181. const int len = s->getNumBytesAsUTF8() + 1;
  182. HeapBlock<char> temp (len);
  183. s->copyToUTF8 (temp, len);
  184. output.writeCompressedInt (len + 1);
  185. output.writeByte (varMarker_String);
  186. output.write (temp, len);
  187. }
  188. private:
  189. static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast <const String*> (data.stringValue); }
  190. static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast <String*> (data.stringValue); }
  191. };
  192. //==============================================================================
  193. class var::VariantType_Object : public var::VariantType
  194. {
  195. public:
  196. VariantType_Object() noexcept {}
  197. static const VariantType_Object instance;
  198. void cleanUp (ValueUnion& data) const noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
  199. void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.objectValue = source.objectValue; if (dest.objectValue != nullptr) dest.objectValue->incReferenceCount(); }
  200. String toString (const ValueUnion& data) const { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
  201. bool toBool (const ValueUnion& data) const noexcept { return data.objectValue != 0; }
  202. ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept { return data.objectValue; }
  203. bool isObject() const noexcept { return true; }
  204. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  205. {
  206. return otherType.toObject (otherData) == data.objectValue;
  207. }
  208. void writeToStream (const ValueUnion&, OutputStream& output) const
  209. {
  210. jassertfalse; // Can't write an object to a stream!
  211. output.writeCompressedInt (0);
  212. }
  213. };
  214. //==============================================================================
  215. class var::VariantType_Method : public var::VariantType
  216. {
  217. public:
  218. VariantType_Method() noexcept {}
  219. static const VariantType_Method instance;
  220. String toString (const ValueUnion&) const { return "Method"; }
  221. bool toBool (const ValueUnion& data) const noexcept { return data.methodValue != 0; }
  222. bool isMethod() const noexcept { return true; }
  223. bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
  224. {
  225. return otherType.isMethod() && otherData.methodValue == data.methodValue;
  226. }
  227. void writeToStream (const ValueUnion&, OutputStream& output) const
  228. {
  229. jassertfalse; // Can't write a method to a stream!
  230. output.writeCompressedInt (0);
  231. }
  232. };
  233. //==============================================================================
  234. const var::VariantType_Void var::VariantType_Void::instance;
  235. const var::VariantType_Int var::VariantType_Int::instance;
  236. const var::VariantType_Int64 var::VariantType_Int64::instance;
  237. const var::VariantType_Bool var::VariantType_Bool::instance;
  238. const var::VariantType_Double var::VariantType_Double::instance;
  239. const var::VariantType_String var::VariantType_String::instance;
  240. const var::VariantType_Object var::VariantType_Object::instance;
  241. const var::VariantType_Method var::VariantType_Method::instance;
  242. //==============================================================================
  243. var::var() noexcept : type (&VariantType_Void::instance)
  244. {
  245. }
  246. var::~var() noexcept
  247. {
  248. type->cleanUp (value);
  249. }
  250. const var var::null;
  251. //==============================================================================
  252. var::var (const var& valueToCopy) : type (valueToCopy.type)
  253. {
  254. type->createCopy (value, valueToCopy.value);
  255. }
  256. var::var (const int value_) noexcept : type (&VariantType_Int::instance)
  257. {
  258. value.intValue = value_;
  259. }
  260. var::var (const int64 value_) noexcept : type (&VariantType_Int64::instance)
  261. {
  262. value.int64Value = value_;
  263. }
  264. var::var (const bool value_) noexcept : type (&VariantType_Bool::instance)
  265. {
  266. value.boolValue = value_;
  267. }
  268. var::var (const double value_) noexcept : type (&VariantType_Double::instance)
  269. {
  270. value.doubleValue = value_;
  271. }
  272. var::var (const String& value_) : type (&VariantType_String::instance)
  273. {
  274. new (value.stringValue) String (value_);
  275. }
  276. var::var (const char* const value_) : type (&VariantType_String::instance)
  277. {
  278. new (value.stringValue) String (value_);
  279. }
  280. var::var (const wchar_t* const value_) : type (&VariantType_String::instance)
  281. {
  282. new (value.stringValue) String (value_);
  283. }
  284. var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance)
  285. {
  286. value.objectValue = object;
  287. if (object != nullptr)
  288. object->incReferenceCount();
  289. }
  290. var::var (MethodFunction method_) noexcept : type (&VariantType_Method::instance)
  291. {
  292. value.methodValue = method_;
  293. }
  294. //==============================================================================
  295. bool var::isVoid() const noexcept { return type->isVoid(); }
  296. bool var::isInt() const noexcept { return type->isInt(); }
  297. bool var::isInt64() const noexcept { return type->isInt64(); }
  298. bool var::isBool() const noexcept { return type->isBool(); }
  299. bool var::isDouble() const noexcept { return type->isDouble(); }
  300. bool var::isString() const noexcept { return type->isString(); }
  301. bool var::isObject() const noexcept { return type->isObject(); }
  302. bool var::isMethod() const noexcept { return type->isMethod(); }
  303. var::operator int() const noexcept { return type->toInt (value); }
  304. var::operator int64() const noexcept { return type->toInt64 (value); }
  305. var::operator bool() const noexcept { return type->toBool (value); }
  306. var::operator float() const noexcept { return (float) type->toDouble (value); }
  307. var::operator double() const noexcept { return type->toDouble (value); }
  308. String var::toString() const { return type->toString (value); }
  309. var::operator String() const { return type->toString (value); }
  310. ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
  311. DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); }
  312. //==============================================================================
  313. void var::swapWith (var& other) noexcept
  314. {
  315. std::swap (type, other.type);
  316. std::swap (value, other.value);
  317. }
  318. const var& var::operator= (const var& newValue) { type->cleanUp (value); type = newValue.type; type->createCopy (value, newValue.value); return *this; }
  319. const var& var::operator= (const int newValue) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = newValue; return *this; }
  320. const var& var::operator= (const int64 newValue) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = newValue; return *this; }
  321. const var& var::operator= (const bool newValue) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = newValue; return *this; }
  322. const var& var::operator= (const double newValue) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = newValue; return *this; }
  323. const var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; }
  324. const var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; }
  325. const var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; }
  326. const var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; }
  327. const var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; }
  328. //==============================================================================
  329. bool var::equals (const var& other) const noexcept
  330. {
  331. return type->equals (value, other.value, *other.type);
  332. }
  333. bool var::equalsWithSameType (const var& other) const noexcept
  334. {
  335. return type == other.type && equals (other);
  336. }
  337. bool operator== (const var& v1, const var& v2) noexcept { return v1.equals (v2); }
  338. bool operator!= (const var& v1, const var& v2) noexcept { return ! v1.equals (v2); }
  339. bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
  340. bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
  341. bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; }
  342. bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; }
  343. //==============================================================================
  344. void var::writeToStream (OutputStream& output) const
  345. {
  346. type->writeToStream (value, output);
  347. }
  348. var var::readFromStream (InputStream& input)
  349. {
  350. const int numBytes = input.readCompressedInt();
  351. if (numBytes > 0)
  352. {
  353. switch (input.readByte())
  354. {
  355. case varMarker_Int: return var (input.readInt());
  356. case varMarker_Int64: return var (input.readInt64());
  357. case varMarker_BoolTrue: return var (true);
  358. case varMarker_BoolFalse: return var (false);
  359. case varMarker_Double: return var (input.readDouble());
  360. case varMarker_String:
  361. {
  362. MemoryOutputStream mo;
  363. mo.writeFromInputStream (input, numBytes - 1);
  364. return var (mo.toUTF8());
  365. }
  366. default: input.skipNextBytes (numBytes - 1); break;
  367. }
  368. }
  369. return var::null;
  370. }
  371. var var::operator[] (const Identifier& propertyName) const
  372. {
  373. DynamicObject* const o = getDynamicObject();
  374. return o != nullptr ? o->getProperty (propertyName) : var::null;
  375. }
  376. var var::invoke (const Identifier& method, const var* arguments, int numArguments) const
  377. {
  378. DynamicObject* const o = getDynamicObject();
  379. return o != nullptr ? o->invokeMethod (method, arguments, numArguments) : var::null;
  380. }
  381. var var::invokeMethod (DynamicObject* const target, const var* const arguments, const int numArguments) const
  382. {
  383. jassert (target != nullptr);
  384. if (isMethod())
  385. return (target->*(value.methodValue)) (arguments, numArguments);
  386. return var::null;
  387. }
  388. var var::call (const Identifier& method) const
  389. {
  390. return invoke (method, nullptr, 0);
  391. }
  392. var var::call (const Identifier& method, const var& arg1) const
  393. {
  394. return invoke (method, &arg1, 1);
  395. }
  396. var var::call (const Identifier& method, const var& arg1, const var& arg2) const
  397. {
  398. var args[] = { arg1, arg2 };
  399. return invoke (method, args, 2);
  400. }
  401. var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3)
  402. {
  403. var args[] = { arg1, arg2, arg3 };
  404. return invoke (method, args, 3);
  405. }
  406. var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
  407. {
  408. var args[] = { arg1, arg2, arg3, arg4 };
  409. return invoke (method, args, 4);
  410. }
  411. var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
  412. {
  413. var args[] = { arg1, arg2, arg3, arg4, arg5 };
  414. return invoke (method, args, 5);
  415. }
  416. END_JUCE_NAMESPACE