diff --git a/extras/browser plugin demo/src/AppConfig.h b/extras/browser plugin demo/src/AppConfig.h index a7b9dabea2..b03cd384ff 100644 --- a/extras/browser plugin demo/src/AppConfig.h +++ b/extras/browser plugin demo/src/AppConfig.h @@ -1,2 +1,5 @@ -#include "BrowserPluginCharacteristics.h" \ No newline at end of file +#define JUCE_MODULE_AVAILABLE_juce_core 1 + +#include "BrowserPluginCharacteristics.h" + diff --git a/extras/browser plugin demo/src/JuceBrowserPluginDemo.cpp b/extras/browser plugin demo/src/JuceBrowserPluginDemo.cpp index 76ce0bb547..861cb00b1a 100644 --- a/extras/browser plugin demo/src/JuceBrowserPluginDemo.cpp +++ b/extras/browser plugin demo/src/JuceBrowserPluginDemo.cpp @@ -87,13 +87,12 @@ public: class DemoBrowserObject : public DynamicObject { public: - DemoBrowserObject (JuceDemoBrowserPlugin* owner_) - : owner (owner_) + DemoBrowserObject (JuceDemoBrowserPlugin* bp) : owner (bp) { // Add a couple of methods to our object.. - setMethod ("printText", (var::MethodFunction) &DemoBrowserObject::printText); - setMethod ("popUpMessageBox", (var::MethodFunction) &DemoBrowserObject::popUpMessageBox); - setMethod ("registerCallbackObject", (var::MethodFunction) &DemoBrowserObject::registerCallbackObject); + setMethod ("printText", printText); + setMethod ("popUpMessageBox", popUpMessageBox); + setMethod ("registerCallbackObject", registerCallbackObject); // Add some value properties that the webpage can access setProperty ("property1", "testing testing..."); @@ -102,30 +101,33 @@ public: //============================================================================== // These methods are called by javascript in the webpage... - const var printText (const var* params, int numParams) + static var printText (const var::NativeFunctionArgs& args) { - if (numParams > 0) - owner->textBox.setText (owner->textBox.getText() + "\n" + params[0].toString()); + if (DemoBrowserObject* b = dynamic_cast (args.thisObject.getObject())) + if (args.numArguments > 0) + b->owner->textBox.setText (b->owner->textBox.getText() + "\n" + args.arguments[0].toString()); return "text was printed ok!"; } - const var popUpMessageBox (const var* params, int numParams) + static var popUpMessageBox (const var::NativeFunctionArgs& args) { - if (numParams > 0) - AlertWindow::showMessageBox (AlertWindow::InfoIcon, - "A message from the webpage", - params[0].toString(), - String::empty, owner); - return var::null; + if (DemoBrowserObject* b = dynamic_cast (args.thisObject.getObject())) + if (args.numArguments > 0) + AlertWindow::showMessageBox (AlertWindow::InfoIcon, + "A message from the webpage", + args.arguments[0].toString(), + String::empty, b->owner); + return var(); } - const var registerCallbackObject (const var* params, int numParams) + static var registerCallbackObject (const var::NativeFunctionArgs& args) { - if (numParams > 0) - owner->setJavascriptObjectFromBrowser (params[0]); + if (DemoBrowserObject* b = dynamic_cast (args.thisObject.getObject())) + if (args.numArguments > 0) + b->owner->setJavascriptObjectFromBrowser (args.arguments[0]); - return var::null; + return var(); } //============================================================================== diff --git a/extras/browser plugin demo/src/JuceHeader.h b/extras/browser plugin demo/src/JuceHeader.h index 2c5b1a0bdd..ad1c714a06 100644 --- a/extras/browser plugin demo/src/JuceHeader.h +++ b/extras/browser plugin demo/src/JuceHeader.h @@ -8,7 +8,7 @@ #include "AppConfig.h" -#include "../../../modules/juce_browser_plugin/juce_browser_plugin.h" +#include "../../../modules/juce_browser_plugin_client/juce_browser_plugin.h" #if ! DONT_SET_USING_JUCE_NAMESPACE /* If you're not mixing JUCE with other libraries, then this will obviously save diff --git a/extras/browser plugin demo/src/juce_browser_plugin_wrapper.mm b/extras/browser plugin demo/src/juce_browser_plugin_wrapper.mm index 1aab92ffeb..a08f09349e 100644 --- a/extras/browser plugin demo/src/juce_browser_plugin_wrapper.mm +++ b/extras/browser plugin demo/src/juce_browser_plugin_wrapper.mm @@ -1,3 +1,3 @@ #include "AppConfig.h" -#include "../../../modules/juce_browser_plugin/juce_browser_plugin.cpp" +#include "../../../modules/juce_browser_plugin_client/juce_browser_plugin.cpp" diff --git a/modules/juce_browser_plugin_client/wrapper/juce_ActiveX_GlueCode.cpp b/modules/juce_browser_plugin_client/wrapper/juce_ActiveX_GlueCode.cpp index 9fa365d2f7..4cf2f7ab19 100644 --- a/modules/juce_browser_plugin_client/wrapper/juce_ActiveX_GlueCode.cpp +++ b/modules/juce_browser_plugin_client/wrapper/juce_ActiveX_GlueCode.cpp @@ -229,7 +229,7 @@ public: log ("num IDispatch wrapper objs: " + String (--numDOWID)); } - var getProperty (const Identifier& propertyName) const + var getProperty (const Identifier& propertyName) const override { const String nameCopy (propertyName.toString()); LPCOLESTR name = nameCopy.toUTF16(); @@ -255,7 +255,7 @@ public: return var::null; } - bool hasProperty (const Identifier& propertyName) const + bool hasProperty (const Identifier& propertyName) const override { const String nameCopy (propertyName.toString()); LPCOLESTR name = nameCopy.toUTF16(); @@ -263,7 +263,7 @@ public: return source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK; } - void setProperty (const Identifier& propertyName, const var& newValue) + void setProperty (const Identifier& propertyName, const var& newValue) override { const String nameCopy (propertyName.toString()); LPCOLESTR name = nameCopy.toUTF16(); @@ -295,12 +295,12 @@ public: } } - void removeProperty (const Identifier& propertyName) + void removeProperty (const Identifier& propertyName) override { setProperty (propertyName, var::null); } - bool hasMethod (const Identifier& methodName) const + bool hasMethod (const Identifier& methodName) const override { const String nameCopy (methodName.toString()); LPCOLESTR name = nameCopy.toUTF16(); @@ -308,7 +308,7 @@ public: return source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK; } - var invokeMethod (const Identifier& methodName, const var* parameters, int numParameters) + var invokeMethod (Identifier methodName, const var::NativeFunctionArgs& args) override { var returnValue; const String nameCopy (methodName.toString()); @@ -317,14 +317,14 @@ public: if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK) { HeapBlock params; - params.calloc (numParameters + 1); + params.calloc (args.numArguments + 1); - for (int i = 0; i < numParameters; ++i) - juceVarToVariant (parameters[(numParameters - 1) - i], params[i]); + for (int i = 0; i < args.numArguments; ++i) + juceVarToVariant (args.arguments[(args.numArguments - 1) - i], params[i]); DISPPARAMS dispParams; zerostruct (dispParams); - dispParams.cArgs = numParameters; + dispParams.cArgs = args.numArguments; dispParams.rgvarg = params; EXCEPINFO excepInfo; diff --git a/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp b/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp index 8074f52901..41210fb468 100644 --- a/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp +++ b/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp @@ -616,7 +616,7 @@ public: DBG ("num NP wrapper objs: " + String (--numDOWNP)); } - var getProperty (const var::identifier& propertyName) const + var getProperty (const var::identifier& propertyName) const override { NPVariant result; VOID_TO_NPVARIANT (result); @@ -626,7 +626,7 @@ public: return v; } - bool hasProperty (const var::identifier& propertyName) const + bool hasProperty (const var::identifier& propertyName) const override { NPVariant result; VOID_TO_NPVARIANT (result); @@ -635,7 +635,7 @@ public: return hasProp; } - void setProperty (const var::identifier& propertyName, const var& newValue) + void setProperty (const var::identifier& propertyName, const var& newValue) override { NPVariant value; createNPVariantFromValue (npp, value, newValue); @@ -644,40 +644,38 @@ public: browser.releasevariantvalue (&value); } - void removeProperty (const var::identifier& propertyName) + void removeProperty (const var::identifier& propertyName) override { browser.removeproperty (npp, source, getIdentifierFromString (propertyName)); } - bool hasMethod (const var::identifier& methodName) const + bool hasMethod (const var::identifier& methodName) const override { return browser.hasmethod (npp, source, getIdentifierFromString (methodName)); } - var invokeMethod (const var::identifier& methodName, - const var* parameters, - int numParameters) + var invokeMethod (Identifier methodName, const var::NativeFunctionArgs& args) override { var returnVal; NPVariant result; VOID_TO_NPVARIANT (result); - if (numParameters > 0) + if (args.numArguments > 0) { - HeapBlock params (numParameters); + HeapBlock params (args.numArguments); - for (int i = 0; i < numParameters; ++i) - createNPVariantFromValue (npp, params[i], parameters[i]); + for (int i = 0; i < args.numArguments; ++i) + createNPVariantFromValue (npp, params[i], args.arguments[i]); if (browser.invoke (npp, source, getIdentifierFromString (methodName), - params, numParameters, &result)) + params, args.numArguments, &result)) { returnVal = createValueFromNPVariant (npp, result); browser.releasevariantvalue (&result); } - for (int i = 0; i < numParameters; ++i) + for (int i = 0; i < args.numArguments; ++i) browser.releasevariantvalue (¶ms[i]); } else @@ -705,15 +703,14 @@ public: } private: - NPObjectWrappingDynamicObject (NPP npp_) - : npp (npp_) + NPObjectWrappingDynamicObject (NPP n) : npp (n) { DBG ("num Juce wrapper objs: " + String (++numJuceWDO)); } //============================================================================== bool construct (const NPVariant *args, uint32_t argCount, NPVariant *result); - void invalidate() {} + void invalidate() {} bool hasMethod (NPIdentifier name) { @@ -742,7 +739,9 @@ private: for (uint32_t i = 0; i < argCount; ++i) params.params[i] = createValueFromNPVariant (npp, args[i]); - const var result (o->invokeMethod (methodName, params.params, argCount)); + + const var::NativeFunctionArgs argStruct = { object, params.params, (int) argCount }; + const var result (o->invokeMethod (methodName, argStruct)); if (out != nullptr) createNPVariantFromValue (npp, *out, result); diff --git a/modules/juce_core/containers/juce_DynamicObject.cpp b/modules/juce_core/containers/juce_DynamicObject.cpp index 69e587febb..3a019c11ee 100644 --- a/modules/juce_core/containers/juce_DynamicObject.cpp +++ b/modules/juce_core/containers/juce_DynamicObject.cpp @@ -60,17 +60,17 @@ bool DynamicObject::hasMethod (const Identifier& methodName) const return getProperty (methodName).isMethod(); } -var DynamicObject::invokeMethod (const Identifier& methodName, - const var* parameters, - int numParameters) +var DynamicObject::invokeMethod (Identifier method, const var::NativeFunctionArgs& args) { - return properties [methodName].invokeMethod (this, parameters, numParameters); + if (var::NativeFunction function = properties [method].getNativeFunction()) + return function (args); + + return var(); } -void DynamicObject::setMethod (const Identifier& name, - var::MethodFunction methodFunction) +void DynamicObject::setMethod (Identifier name, var::NativeFunction function) { - properties.set (name, var (methodFunction)); + properties.set (name, var (function)); } void DynamicObject::clear() diff --git a/modules/juce_core/containers/juce_DynamicObject.h b/modules/juce_core/containers/juce_DynamicObject.h index 38bc227e9d..e59c26ff3f 100644 --- a/modules/juce_core/containers/juce_DynamicObject.h +++ b/modules/juce_core/containers/juce_DynamicObject.h @@ -86,23 +86,16 @@ public: This method is virtual to allow more dynamic invocation to used for objects where the methods may not already be set as properies. */ - virtual var invokeMethod (const Identifier& methodName, - const var* parameters, - int numParameters); + virtual var invokeMethod (Identifier methodName, + const var::NativeFunctionArgs& args); - /** Sets up a method. + /** Adds a method to the class. - This is basically the same as calling setProperty (methodName, (var::MethodFunction) myFunction), but + This is basically the same as calling setProperty (methodName, (var::NativeFunction) myFunction), but helps to avoid accidentally invoking the wrong type of var constructor. It also makes the code easier to read, - - The compiler will probably force you to use an explicit cast your method to a (var::MethodFunction), e.g. - @code - setMethod ("doSomething", (var::MethodFunction) &MyClass::doSomething); - @endcode */ - void setMethod (const Identifier& methodName, - var::MethodFunction methodFunction); + void setMethod (Identifier methodName, var::NativeFunction function); //============================================================================== /** Removes all properties and methods from the object. */ @@ -115,6 +108,11 @@ private: //============================================================================== NamedValueSet properties; + #if JUCE_CATCH_DEPRECATED_CODE_MISUSE + // These methods have been deprecated - use var::invoke instead + virtual void invokeMethod (const Identifier&, const var*, int) {} + #endif + JUCE_LEAK_DETECTOR (DynamicObject) }; diff --git a/modules/juce_core/containers/juce_Variant.cpp b/modules/juce_core/containers/juce_Variant.cpp index 806b1a758e..b2493235d8 100644 --- a/modules/juce_core/containers/juce_Variant.cpp +++ b/modules/juce_core/containers/juce_Variant.cpp @@ -35,7 +35,8 @@ enum VariantStreamMarkers varMarker_String = 5, varMarker_Int64 = 6, varMarker_Array = 7, - varMarker_Binary = 8 + varMarker_Binary = 8, + varMarker_Undefined = 9 }; //============================================================================== @@ -55,6 +56,7 @@ public: virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; } virtual bool isVoid() const noexcept { return false; } + virtual bool isUndefined() const noexcept { return false; } virtual bool isInt() const noexcept { return false; } virtual bool isInt64() const noexcept { return false; } virtual bool isBool() const noexcept { return false; } @@ -79,10 +81,28 @@ public: static const VariantType_Void instance; bool isVoid() const noexcept { return true; } - bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept { return otherType.isVoid(); } + bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept { return otherType.isVoid() || otherType.isUndefined(); } void writeToStream (const ValueUnion&, OutputStream& output) const { output.writeCompressedInt (0); } }; +//============================================================================== +class var::VariantType_Undefined : public var::VariantType +{ +public: + VariantType_Undefined() noexcept {} + static const VariantType_Undefined instance; + + bool isUndefined() const noexcept { return true; } + String toString (const ValueUnion&) const { return "undefined"; } + bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept { return otherType.isVoid() || otherType.isUndefined(); } + + void writeToStream (const ValueUnion&, OutputStream& output) const + { + output.writeCompressedInt (1); + output.writeByte (varMarker_Undefined); + } +}; + //============================================================================== class var::VariantType_Int : public var::VariantType { @@ -264,38 +284,56 @@ public: }; //============================================================================== -class var::VariantType_Array : public var::VariantType +class var::VariantType_Array : public var::VariantType_Object { public: VariantType_Array() noexcept {} static const VariantType_Array instance; - void cleanUp (ValueUnion& data) const noexcept { delete data.arrayValue; } - void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.arrayValue = new Array (*(source.arrayValue)); } - String toString (const ValueUnion&) const { return "[Array]"; } + ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; } bool isArray() const noexcept { return true; } - Array* toArray (const ValueUnion& data) const noexcept { return data.arrayValue; } + + Array* toArray (const ValueUnion& data) const noexcept + { + if (RefCountedArray* a = dynamic_cast (data.objectValue)) + return &(a->array); + + return nullptr; + } bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept { + const Array* const thisArray = toArray (data); const Array* const otherArray = otherType.toArray (otherData); - return otherArray != nullptr && *otherArray == *(data.arrayValue); + return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray); } void writeToStream (const ValueUnion& data, OutputStream& output) const { - MemoryOutputStream buffer (512); - const int numItems = data.arrayValue->size(); - buffer.writeCompressedInt (numItems); + if (const Array* array = toArray (data)) + { + MemoryOutputStream buffer (512); + const int numItems = array->size(); + buffer.writeCompressedInt (numItems); - for (int i = 0; i < numItems; ++i) - data.arrayValue->getReference(i).writeToStream (buffer); + for (int i = 0; i < numItems; ++i) + array->getReference(i).writeToStream (buffer); - output.writeCompressedInt (1 + (int) buffer.getDataSize()); - output.writeByte (varMarker_Array); - output << buffer; + output.writeCompressedInt (1 + (int) buffer.getDataSize()); + output.writeByte (varMarker_Array); + output << buffer; + } } + + struct RefCountedArray : public ReferenceCountedObject + { + RefCountedArray (const Array& a) : array (a) { incReferenceCount(); } + #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS + RefCountedArray (Array&& a) : array (static_cast&&> (a)) { incReferenceCount(); } + #endif + Array array; + }; }; //============================================================================== @@ -351,27 +389,23 @@ public: }; //============================================================================== -const var::VariantType_Void var::VariantType_Void::instance; -const var::VariantType_Int var::VariantType_Int::instance; -const var::VariantType_Int64 var::VariantType_Int64::instance; -const var::VariantType_Bool var::VariantType_Bool::instance; -const var::VariantType_Double var::VariantType_Double::instance; -const var::VariantType_String var::VariantType_String::instance; -const var::VariantType_Object var::VariantType_Object::instance; -const var::VariantType_Array var::VariantType_Array::instance; -const var::VariantType_Binary var::VariantType_Binary::instance; -const var::VariantType_Method var::VariantType_Method::instance; +const var::VariantType_Void var::VariantType_Void::instance; +const var::VariantType_Undefined var::VariantType_Undefined::instance; +const var::VariantType_Int var::VariantType_Int::instance; +const var::VariantType_Int64 var::VariantType_Int64::instance; +const var::VariantType_Bool var::VariantType_Bool::instance; +const var::VariantType_Double var::VariantType_Double::instance; +const var::VariantType_String var::VariantType_String::instance; +const var::VariantType_Object var::VariantType_Object::instance; +const var::VariantType_Array var::VariantType_Array::instance; +const var::VariantType_Binary var::VariantType_Binary::instance; +const var::VariantType_Method var::VariantType_Method::instance; //============================================================================== -var::var() noexcept : type (&VariantType_Void::instance) -{ -} - -var::~var() noexcept -{ - type->cleanUp (value); -} +var::var() noexcept : type (&VariantType_Void::instance) {} +var::var (const VariantType& t) noexcept : type (&t) {} +var::~var() noexcept { type->cleanUp (value); } const var var::null; @@ -385,8 +419,8 @@ var::var (const int v) noexcept : type (&VariantType_Int::instance) { v var::var (const int64 v) noexcept : type (&VariantType_Int64::instance) { value.int64Value = v; } var::var (const bool v) noexcept : type (&VariantType_Bool::instance) { value.boolValue = v; } var::var (const double v) noexcept : type (&VariantType_Double::instance) { value.doubleValue = v; } -var::var (MethodFunction m) noexcept : type (&VariantType_Method::instance) { value.methodValue = m; } -var::var (const Array& v) : type (&VariantType_Array::instance) { value.arrayValue = new Array (v); } +var::var (NativeFunction m) noexcept : type (&VariantType_Method::instance) { value.methodValue = m; } +var::var (const Array& v) : type (&VariantType_Array::instance) { value.objectValue = new VariantType_Array::RefCountedArray(v); } var::var (const String& v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); } var::var (const char* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); } var::var (const wchar_t* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); } @@ -401,9 +435,11 @@ var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::in object->incReferenceCount(); } +var var::undefined() noexcept { return var (VariantType_Undefined::instance); } //============================================================================== bool var::isVoid() const noexcept { return type->isVoid(); } +bool var::isUndefined() const noexcept { return type->isUndefined(); } bool var::isInt() const noexcept { return type->isInt(); } bool var::isInt64() const noexcept { return type->isInt64(); } bool var::isBool() const noexcept { return type->isBool(); } @@ -443,7 +479,7 @@ var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = var& var::operator= (const String& v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; } var& var::operator= (const Array& v) { var v2 (v); swapWith (v2); return *this; } var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; } -var& var::operator= (MethodFunction v) { var v2 (v); swapWith (v2); return *this; } +var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; } #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS var::var (var&& other) noexcept @@ -469,6 +505,11 @@ var::var (MemoryBlock&& v) : type (&VariantType_Binary::instance) value.binaryValue = new MemoryBlock (static_cast (v)); } +var::var (Array&& v) : type (&VariantType_Array::instance) +{ + value.objectValue = new VariantType_Array::RefCountedArray (static_cast&&> (v)); +} + var& var::operator= (String&& v) { type->cleanUp (value); @@ -508,7 +549,7 @@ var var::operator[] (const Identifier propertyName) const if (DynamicObject* const o = getDynamicObject()) return o->getProperty (propertyName); - return var::null; + return var(); } var var::operator[] (const char* const propertyName) const @@ -524,22 +565,20 @@ var var::getProperty (const Identifier propertyName, const var& defaultReturnVal return defaultReturnValue; } -var var::invoke (const Identifier method, const var* arguments, int numArguments) const +var::NativeFunction var::getNativeFunction() const { - if (DynamicObject* const o = getDynamicObject()) - return o->invokeMethod (method, arguments, numArguments); - - return var::null; + return isMethod() ? value.methodValue : nullptr; } -var var::invokeMethod (DynamicObject* const target, const var* const arguments, const int numArguments) const +var var::invoke (Identifier method, const var* arguments, int numArguments) const { - jassert (target != nullptr); + if (DynamicObject* const o = getDynamicObject()) + { + const var::NativeFunctionArgs args = { *this, arguments, numArguments }; + return o->invokeMethod (method, args); + } - if (isMethod()) - return (target->*(value.methodValue)) (arguments, numArguments); - - return var::null; + return var(); } var var::call (const Identifier method) const @@ -609,21 +648,15 @@ var& var::operator[] (int arrayIndex) Array* var::convertToArray() { - Array* array = getArray(); + if (Array* array = getArray()) + return array; - if (array == nullptr) - { - const Array tempVar; - var v (tempVar); - array = v.value.arrayValue; + Array tempVar; + if (! isVoid()) + tempVar.add (*this); - if (! isVoid()) - array->add (*this); - - swapWith (v); - } - - return array; + *this = tempVar; + return getArray(); } void var::append (const var& n) @@ -710,5 +743,5 @@ var var::readFromStream (InputStream& input) } } - return var::null; + return var(); } diff --git a/modules/juce_core/containers/juce_Variant.h b/modules/juce_core/containers/juce_Variant.h index 9ad94c37a4..d9ffb9b02f 100644 --- a/modules/juce_core/containers/juce_Variant.h +++ b/modules/juce_core/containers/juce_Variant.h @@ -47,7 +47,17 @@ class JUCE_API var { public: //============================================================================== - typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments); + /** This structure is passed to a NativeFunction callback, and contains invocation + details about the function's arguments and context. + */ + struct NativeFunctionArgs + { + const var& thisObject; + const var* arguments; + int numArguments; + }; + + typedef var (*NativeFunction) (const NativeFunctionArgs&); typedef Identifier identifier; //============================================================================== @@ -70,7 +80,7 @@ public: var (const String& value); var (const Array& value); var (ReferenceCountedObject* object); - var (MethodFunction method) noexcept; + var (NativeFunction method) noexcept; var (const void* binaryData, size_t dataSize); var (const MemoryBlock& binaryData); @@ -84,18 +94,22 @@ public: var& operator= (const String& value); var& operator= (const Array& value); var& operator= (ReferenceCountedObject* object); - var& operator= (MethodFunction method); + var& operator= (NativeFunction method); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS var (var&& other) noexcept; var (String&& value); var (MemoryBlock&& binaryData); + var (Array&& value); var& operator= (var&& other) noexcept; var& operator= (String&& value); #endif void swapWith (var& other) noexcept; + /** Returns a var object that can be used where you need the javascript "undefined" value. */ + static var undefined() noexcept; + //============================================================================== operator int() const noexcept; operator int64() const noexcept; @@ -126,6 +140,7 @@ public: //============================================================================== bool isVoid() const noexcept; + bool isUndefined() const noexcept; bool isInt() const noexcept; bool isInt64() const noexcept; bool isBool() const noexcept; @@ -217,27 +232,29 @@ public: //============================================================================== /** If this variant is an object, this returns one of its properties. */ - var operator[] (const Identifier propertyName) const; + var operator[] (Identifier propertyName) const; /** If this variant is an object, this returns one of its properties. */ var operator[] (const char* propertyName) const; /** If this variant is an object, this returns one of its properties, or a default fallback value if the property is not set. */ - var getProperty (const Identifier propertyName, const var& defaultReturnValue) const; + var getProperty (Identifier propertyName, const var& defaultReturnValue) const; - /** If this variant is an object, this invokes one of its methods with no arguments. */ - var call (const Identifier method) const; - /** If this variant is an object, this invokes one of its methods with one argument. */ - var call (const Identifier method, const var& arg1) const; - /** If this variant is an object, this invokes one of its methods with 2 arguments. */ - var call (const Identifier method, const var& arg1, const var& arg2) const; - /** If this variant is an object, this invokes one of its methods with 3 arguments. */ - var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3); - /** If this variant is an object, this invokes one of its methods with 4 arguments. */ - var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; - /** If this variant is an object, this invokes one of its methods with 5 arguments. */ - var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; - /** If this variant is an object, this invokes one of its methods with a list of arguments. */ - var invoke (const Identifier method, const var* arguments, int numArguments) const; + /** Invokes a named method call with no arguments. */ + var call (Identifier method) const; + /** Invokes a named method call with one argument. */ + var call (Identifier method, const var& arg1) const; + /** Invokes a named method call with 2 arguments. */ + var call (Identifier method, const var& arg1, const var& arg2) const; + /** Invokes a named method call with 3 arguments. */ + var call (Identifier method, const var& arg1, const var& arg2, const var& arg3); + /** Invokes a named method call with 4 arguments. */ + var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; + /** Invokes a named method call with 5 arguments. */ + var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; + /** Invokes a named method call with a list of arguments. */ + var invoke (Identifier method, const var* arguments, int numArguments) const; + /** If this object is a method, this returns the function pointer. */ + NativeFunction getNativeFunction() const; //============================================================================== /** Writes a binary representation of this value to a stream. @@ -255,17 +272,18 @@ public: private: //============================================================================== - class VariantType; friend class VariantType; - class VariantType_Void; friend class VariantType_Void; - class VariantType_Int; friend class VariantType_Int; - class VariantType_Int64; friend class VariantType_Int64; - class VariantType_Double; friend class VariantType_Double; - class VariantType_Bool; friend class VariantType_Bool; - class VariantType_String; friend class VariantType_String; - class VariantType_Object; friend class VariantType_Object; - class VariantType_Array; friend class VariantType_Array; - class VariantType_Binary; friend class VariantType_Binary; - class VariantType_Method; friend class VariantType_Method; + class VariantType; friend class VariantType; + class VariantType_Void; friend class VariantType_Void; + class VariantType_Undefined; friend class VariantType_Undefined; + class VariantType_Int; friend class VariantType_Int; + class VariantType_Int64; friend class VariantType_Int64; + class VariantType_Double; friend class VariantType_Double; + class VariantType_Bool; friend class VariantType_Bool; + class VariantType_String; friend class VariantType_String; + class VariantType_Object; friend class VariantType_Object; + class VariantType_Array; friend class VariantType_Array; + class VariantType_Binary; friend class VariantType_Binary; + class VariantType_Method; friend class VariantType_Method; union ValueUnion { @@ -275,17 +293,15 @@ private: double doubleValue; char stringValue [sizeof (String)]; ReferenceCountedObject* objectValue; - Array* arrayValue; MemoryBlock* binaryValue; - MethodFunction methodValue; + NativeFunction methodValue; }; const VariantType* type; ValueUnion value; Array* convertToArray(); - friend class DynamicObject; - var invokeMethod (DynamicObject*, const var*, int) const; + var (const VariantType&) noexcept; }; /** Compares the values of two var objects, using the var::equals() comparison. */ diff --git a/modules/juce_core/json/juce_JSON.cpp b/modules/juce_core/json/juce_JSON.cpp index 59dfdade25..d54cf3405b 100644 --- a/modules/juce_core/json/juce_JSON.cpp +++ b/modules/juce_core/json/juce_JSON.cpp @@ -338,6 +338,10 @@ public: { out << "null"; } + else if (v.isUndefined()) + { + out << "undefined"; + } else if (v.isBool()) { out << (static_cast (v) ? "true" : "false"); @@ -421,29 +425,33 @@ public: const int indentLevel, const bool allOnOneLine) { out << '['; - if (! allOnOneLine) - out << newLine; - for (int i = 0; i < array.size(); ++i) + if (array.size() > 0) { if (! allOnOneLine) - writeSpaces (out, indentLevel + indentSize); - - write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine); - - if (i < array.size() - 1) - { - if (allOnOneLine) - out << ", "; - else - out << ',' << newLine; - } - else if (! allOnOneLine) out << newLine; - } - if (! allOnOneLine) - writeSpaces (out, indentLevel); + for (int i = 0; i < array.size(); ++i) + { + if (! allOnOneLine) + writeSpaces (out, indentLevel + indentSize); + + write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine); + + if (i < array.size() - 1) + { + if (allOnOneLine) + out << ", "; + else + out << ',' << newLine; + } + else if (! allOnOneLine) + out << newLine; + } + + if (! allOnOneLine) + writeSpaces (out, indentLevel); + } out << ']'; }