Browse Source

Added methods var::clone() and DynamicObject::clone() for deep-copying objects.

tags/2021-05-28
jules 12 years ago
parent
commit
a7df25f860
5 changed files with 139 additions and 79 deletions
  1. +19
    -0
      modules/juce_core/containers/juce_DynamicObject.cpp
  2. +9
    -0
      modules/juce_core/containers/juce_DynamicObject.h
  3. +103
    -77
      modules/juce_core/containers/juce_Variant.cpp
  4. +6
    -0
      modules/juce_core/containers/juce_Variant.h
  5. +2
    -2
      modules/juce_core/text/juce_Identifier.h

+ 19
- 0
modules/juce_core/containers/juce_DynamicObject.cpp View File

@@ -78,6 +78,25 @@ void DynamicObject::clear()
properties.clear(); properties.clear();
} }
DynamicObject::Ptr DynamicObject::clone()
{
DynamicObject* newCopy = new DynamicObject();
newCopy->properties = properties;
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(newCopy->properties.values);;)
{
if (NamedValueSet::NamedValue* const v = i->get())
{
v->value = v->value.clone();
i = &(v->nextListItem);
}
else
break;
}
return newCopy;
}
void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine) void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine)
{ {
out << '{'; out << '{';


+ 9
- 0
modules/juce_core/containers/juce_DynamicObject.h View File

@@ -104,6 +104,15 @@ public:
/** Returns the NamedValueSet that holds the object's properties. */ /** Returns the NamedValueSet that holds the object's properties. */
NamedValueSet& getProperties() noexcept { return properties; } NamedValueSet& getProperties() noexcept { return properties; }
//==============================================================================
/** Returns a clone of this object.
The default implementation of this method just returns a new DynamicObject
with a (deep) copy of all of its properties. Subclasses can override this to
implement their own custom copy routines.
*/
virtual Ptr clone();
//==============================================================================
/** Writes this object to a text stream in JSON format. /** Writes this object to a text stream in JSON format.
This method is used by JSON::toString and JSON::writeToStream, and you should This method is used by JSON::toString and JSON::writeToStream, and you should
never need to call it directly, but it's virtual so that custom object types never need to call it directly, but it's virtual so that custom object types


+ 103
- 77
modules/juce_core/containers/juce_Variant.cpp View File

@@ -54,6 +54,7 @@ public:
virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; } virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; } virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; }
virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; } virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; }
virtual var clone (const var& original) const { return original; }
virtual bool isVoid() const noexcept { return false; } virtual bool isVoid() const noexcept { return false; }
virtual bool isUndefined() const noexcept { return false; } virtual bool isUndefined() const noexcept { return false; }
@@ -80,9 +81,9 @@ public:
VariantType_Void() noexcept {} VariantType_Void() noexcept {}
static const VariantType_Void instance; 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() || otherType.isUndefined(); }
void writeToStream (const ValueUnion&, OutputStream& output) const { output.writeCompressedInt (0); }
bool isVoid() const noexcept override { return true; }
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
void writeToStream (const ValueUnion&, OutputStream& output) const override { output.writeCompressedInt (0); }
}; };
//============================================================================== //==============================================================================
@@ -92,11 +93,11 @@ public:
VariantType_Undefined() noexcept {} VariantType_Undefined() noexcept {}
static const VariantType_Undefined instance; 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(); }
bool isUndefined() const noexcept override { return true; }
String toString (const ValueUnion&) const override { return "undefined"; }
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
void writeToStream (const ValueUnion&, OutputStream& output) const
void writeToStream (const ValueUnion&, OutputStream& output) const override
{ {
output.writeCompressedInt (1); output.writeCompressedInt (1);
output.writeByte (varMarker_Undefined); output.writeByte (varMarker_Undefined);
@@ -110,19 +111,19 @@ public:
VariantType_Int() noexcept {} VariantType_Int() noexcept {}
static const VariantType_Int instance; static const VariantType_Int instance;
int toInt (const ValueUnion& data) const noexcept { return data.intValue; };
int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.intValue; };
double toDouble (const ValueUnion& data) const noexcept { return (double) data.intValue; }
String toString (const ValueUnion& data) const { return String (data.intValue); }
bool toBool (const ValueUnion& data) const noexcept { return data.intValue != 0; }
bool isInt() const noexcept { return true; }
int toInt (const ValueUnion& data) const noexcept override { return data.intValue; };
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.intValue; };
double toDouble (const ValueUnion& data) const noexcept override { return (double) data.intValue; }
String toString (const ValueUnion& data) const override { return String (data.intValue); }
bool toBool (const ValueUnion& data) const noexcept override { return data.intValue != 0; }
bool isInt() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return otherType.toInt (otherData) == data.intValue; return otherType.toInt (otherData) == data.intValue;
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
output.writeCompressedInt (5); output.writeCompressedInt (5);
output.writeByte (varMarker_Int); output.writeByte (varMarker_Int);
@@ -137,19 +138,19 @@ public:
VariantType_Int64() noexcept {} VariantType_Int64() noexcept {}
static const VariantType_Int64 instance; static const VariantType_Int64 instance;
int toInt (const ValueUnion& data) const noexcept { return (int) data.int64Value; };
int64 toInt64 (const ValueUnion& data) const noexcept { return data.int64Value; };
double toDouble (const ValueUnion& data) const noexcept { return (double) data.int64Value; }
String toString (const ValueUnion& data) const { return String (data.int64Value); }
bool toBool (const ValueUnion& data) const noexcept { return data.int64Value != 0; }
bool isInt64() const noexcept { return true; }
int toInt (const ValueUnion& data) const noexcept override { return (int) data.int64Value; };
int64 toInt64 (const ValueUnion& data) const noexcept override { return data.int64Value; };
double toDouble (const ValueUnion& data) const noexcept override { return (double) data.int64Value; }
String toString (const ValueUnion& data) const override { return String (data.int64Value); }
bool toBool (const ValueUnion& data) const noexcept override { return data.int64Value != 0; }
bool isInt64() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return otherType.toInt64 (otherData) == data.int64Value; return otherType.toInt64 (otherData) == data.int64Value;
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
output.writeCompressedInt (9); output.writeCompressedInt (9);
output.writeByte (varMarker_Int64); output.writeByte (varMarker_Int64);
@@ -164,19 +165,19 @@ public:
VariantType_Double() noexcept {} VariantType_Double() noexcept {}
static const VariantType_Double instance; static const VariantType_Double instance;
int toInt (const ValueUnion& data) const noexcept { return (int) data.doubleValue; };
int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.doubleValue; };
double toDouble (const ValueUnion& data) const noexcept { return data.doubleValue; }
String toString (const ValueUnion& data) const { return String (data.doubleValue); }
bool toBool (const ValueUnion& data) const noexcept { return data.doubleValue != 0; }
bool isDouble() const noexcept { return true; }
int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; };
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; };
double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; }
String toString (const ValueUnion& data) const override { return String (data.doubleValue); }
bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0; }
bool isDouble() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon(); return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
output.writeCompressedInt (9); output.writeCompressedInt (9);
output.writeByte (varMarker_Double); output.writeByte (varMarker_Double);
@@ -191,19 +192,19 @@ public:
VariantType_Bool() noexcept {} VariantType_Bool() noexcept {}
static const VariantType_Bool instance; static const VariantType_Bool instance;
int toInt (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
int64 toInt64 (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
double toDouble (const ValueUnion& data) const noexcept { return data.boolValue ? 1.0 : 0.0; }
String toString (const ValueUnion& data) const { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
bool toBool (const ValueUnion& data) const noexcept { return data.boolValue; }
bool isBool() const noexcept { return true; }
int toInt (const ValueUnion& data) const noexcept override { return data.boolValue ? 1 : 0; };
int64 toInt64 (const ValueUnion& data) const noexcept override { return data.boolValue ? 1 : 0; };
double toDouble (const ValueUnion& data) const noexcept override { return data.boolValue ? 1.0 : 0.0; }
String toString (const ValueUnion& data) const override { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
bool toBool (const ValueUnion& data) const noexcept override { return data.boolValue; }
bool isBool() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return otherType.toBool (otherData) == data.boolValue; return otherType.toBool (otherData) == data.boolValue;
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
output.writeCompressedInt (1); output.writeCompressedInt (1);
output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse); output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
@@ -217,24 +218,24 @@ public:
VariantType_String() noexcept {} VariantType_String() noexcept {}
static const VariantType_String instance; static const VariantType_String instance;
void cleanUp (ValueUnion& data) const noexcept { getString (data)-> ~String(); }
void createCopy (ValueUnion& dest, const ValueUnion& source) const { new (dest.stringValue) String (*getString (source)); }
void cleanUp (ValueUnion& data) const noexcept override { getString (data)-> ~String(); }
void createCopy (ValueUnion& dest, const ValueUnion& source) const override { new (dest.stringValue) String (*getString (source)); }
bool isString() const noexcept { return true; }
int toInt (const ValueUnion& data) const noexcept { return getString (data)->getIntValue(); };
int64 toInt64 (const ValueUnion& data) const noexcept { return getString (data)->getLargeIntValue(); };
double toDouble (const ValueUnion& data) const noexcept { return getString (data)->getDoubleValue(); }
String toString (const ValueUnion& data) const { return *getString (data); }
bool toBool (const ValueUnion& data) const noexcept { return getString (data)->getIntValue() != 0
|| getString (data)->trim().equalsIgnoreCase ("true")
|| getString (data)->trim().equalsIgnoreCase ("yes"); }
bool isString() const noexcept override { return true; }
int toInt (const ValueUnion& data) const noexcept override { return getString (data)->getIntValue(); };
int64 toInt64 (const ValueUnion& data) const noexcept override { return getString (data)->getLargeIntValue(); };
double toDouble (const ValueUnion& data) const noexcept override { return getString (data)->getDoubleValue(); }
String toString (const ValueUnion& data) const override { return *getString (data); }
bool toBool (const ValueUnion& data) const noexcept override { return getString (data)->getIntValue() != 0
|| getString (data)->trim().equalsIgnoreCase ("true")
|| getString (data)->trim().equalsIgnoreCase ("yes"); }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return otherType.toString (otherData) == *getString (data); return otherType.toString (otherData) == *getString (data);
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
const String* const s = getString (data); const String* const s = getString (data);
const size_t len = s->getNumBytesAsUTF8() + 1; const size_t len = s->getNumBytesAsUTF8() + 1;
@@ -257,26 +258,35 @@ public:
VariantType_Object() noexcept {} VariantType_Object() noexcept {}
static const VariantType_Object instance; static const VariantType_Object instance;
void cleanUp (ValueUnion& data) const noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
void cleanUp (ValueUnion& data) const noexcept override { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
void createCopy (ValueUnion& dest, const ValueUnion& source) const
void createCopy (ValueUnion& dest, const ValueUnion& source) const override
{ {
dest.objectValue = source.objectValue; dest.objectValue = source.objectValue;
if (dest.objectValue != nullptr) if (dest.objectValue != nullptr)
dest.objectValue->incReferenceCount(); dest.objectValue->incReferenceCount();
} }
String toString (const ValueUnion& data) const { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
bool toBool (const ValueUnion& data) const noexcept { return data.objectValue != 0; }
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept { return data.objectValue; }
bool isObject() const noexcept { return true; }
String toString (const ValueUnion& data) const override { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
bool toBool (const ValueUnion& data) const noexcept override { return data.objectValue != 0; }
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept override { return data.objectValue; }
bool isObject() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return otherType.toObject (otherData) == data.objectValue; return otherType.toObject (otherData) == data.objectValue;
} }
void writeToStream (const ValueUnion&, OutputStream& output) const
var clone (const var& original) const override
{
if (DynamicObject* d = original.getDynamicObject())
return d->clone().get();
jassertfalse; // can only clone DynamicObjects!
return var();
}
void writeToStream (const ValueUnion&, OutputStream& output) const override
{ {
jassertfalse; // Can't write an object to a stream! jassertfalse; // Can't write an object to a stream!
output.writeCompressedInt (0); output.writeCompressedInt (0);
@@ -290,11 +300,11 @@ public:
VariantType_Array() noexcept {} VariantType_Array() noexcept {}
static const VariantType_Array instance; static const VariantType_Array instance;
String toString (const ValueUnion&) const { return "[Array]"; }
ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
bool isArray() const noexcept { return true; }
String toString (const ValueUnion&) const override { return "[Array]"; }
ReferenceCountedObject* toObject (const ValueUnion&) const noexcept override { return nullptr; }
bool isArray() const noexcept override { return true; }
Array<var>* toArray (const ValueUnion& data) const noexcept
Array<var>* toArray (const ValueUnion& data) const noexcept override
{ {
if (RefCountedArray* a = dynamic_cast<RefCountedArray*> (data.objectValue)) if (RefCountedArray* a = dynamic_cast<RefCountedArray*> (data.objectValue))
return &(a->array); return &(a->array);
@@ -302,14 +312,25 @@ public:
return nullptr; return nullptr;
} }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
const Array<var>* const thisArray = toArray (data); const Array<var>* const thisArray = toArray (data);
const Array<var>* const otherArray = otherType.toArray (otherData); const Array<var>* const otherArray = otherType.toArray (otherData);
return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray); return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
var clone (const var& original) const override
{
Array<var> arrayCopy;
if (const Array<var>* array = toArray (original.value))
for (int i = 0; i < array->size(); ++i)
arrayCopy.add (array->getReference(i).clone());
return var (arrayCopy);
}
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
if (const Array<var>* array = toArray (data)) if (const Array<var>* array = toArray (data))
{ {
@@ -344,20 +365,20 @@ public:
static const VariantType_Binary instance; static const VariantType_Binary instance;
void cleanUp (ValueUnion& data) const noexcept { delete data.binaryValue; }
void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
void cleanUp (ValueUnion& data) const noexcept override { delete data.binaryValue; }
void createCopy (ValueUnion& dest, const ValueUnion& source) const override { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
String toString (const ValueUnion& data) const { return data.binaryValue->toBase64Encoding(); }
bool isBinary() const noexcept { return true; }
MemoryBlock* toBinary (const ValueUnion& data) const noexcept { return data.binaryValue; }
String toString (const ValueUnion& data) const override { return data.binaryValue->toBase64Encoding(); }
bool isBinary() const noexcept override { return true; }
MemoryBlock* toBinary (const ValueUnion& data) const noexcept override { return data.binaryValue; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
const MemoryBlock* const otherBlock = otherType.toBinary (otherData); const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
return otherBlock != nullptr && *otherBlock == *data.binaryValue; return otherBlock != nullptr && *otherBlock == *data.binaryValue;
} }
void writeToStream (const ValueUnion& data, OutputStream& output) const
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{ {
output.writeCompressedInt (1 + (int) data.binaryValue->getSize()); output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
output.writeByte (varMarker_Binary); output.writeByte (varMarker_Binary);
@@ -372,16 +393,16 @@ public:
VariantType_Method() noexcept {} VariantType_Method() noexcept {}
static const VariantType_Method instance; static const VariantType_Method instance;
String toString (const ValueUnion&) const { return "Method"; }
bool toBool (const ValueUnion& data) const noexcept { return data.methodValue != nullptr; }
bool isMethod() const noexcept { return true; }
String toString (const ValueUnion&) const override { return "Method"; }
bool toBool (const ValueUnion& data) const noexcept override { return data.methodValue != nullptr; }
bool isMethod() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{ {
return otherType.isMethod() && otherData.methodValue == data.methodValue; return otherType.isMethod() && otherData.methodValue == data.methodValue;
} }
void writeToStream (const ValueUnion&, OutputStream& output) const
void writeToStream (const ValueUnion&, OutputStream& output) const override
{ {
jassertfalse; // Can't write a method to a stream! jassertfalse; // Can't write a method to a stream!
output.writeCompressedInt (0); output.writeCompressedInt (0);
@@ -542,6 +563,11 @@ bool operator!= (const var& v1, const String& v2) { return v1.toString
bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; } bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; }
bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; } bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; }
//==============================================================================
var var::clone() const noexcept
{
return type->clone (*this);
}
//============================================================================== //==============================================================================
var var::operator[] (const Identifier propertyName) const var var::operator[] (const Identifier propertyName) const


+ 6
- 0
modules/juce_core/containers/juce_Variant.h View File

@@ -171,6 +171,12 @@ public:
/** Returns true if this var has the same type as the one supplied. */ /** Returns true if this var has the same type as the one supplied. */
bool hasSameTypeAs (const var& other) const noexcept; bool hasSameTypeAs (const var& other) const noexcept;
/** Returns a deep copy of this object.
For simple types this just returns a copy, but if the object contains any arrays
or DynamicObjects, they will be cloned (recursively).
*/
var clone() const noexcept;
//============================================================================== //==============================================================================
/** If the var is an array, this returns the number of elements. /** If the var is an array, this returns the number of elements.
If the var isn't actually an array, this will return 0. If the var isn't actually an array, this will return 0.


+ 2
- 2
modules/juce_core/text/juce_Identifier.h View File

@@ -77,10 +77,10 @@ public:
String toString() const { return name; } String toString() const { return name; }
/** Returns this identifier's raw string pointer. */ /** Returns this identifier's raw string pointer. */
operator const String::CharPointerType() const noexcept { return name; }
operator String::CharPointerType() const noexcept { return name; }
/** Returns this identifier's raw string pointer. */ /** Returns this identifier's raw string pointer. */
const String::CharPointerType getCharPointer() const noexcept { return name; }
String::CharPointerType getCharPointer() const noexcept { return name; }
/** Returns this identifier as a StringRef. */ /** Returns this identifier as a StringRef. */
operator StringRef() const noexcept { return name; } operator StringRef() const noexcept { return name; }


Loading…
Cancel
Save