Implement Object#clone and rename Array/Dictionary#clone to shallow_clone

fixes #9931
This commit is contained in:
Michael Friedrich 2015-08-17 13:59:49 +02:00
parent 7d6a920b3d
commit 428be72bab
12 changed files with 73 additions and 8 deletions

View File

@ -514,9 +514,9 @@ Signature:
Removes all elements from the array. Removes all elements from the array.
### <a id="array-clone"></a> Array#clone ### <a id="array-shallow-clone"></a> Array#shallow_clone
function clone(); function shallow_clone();
Returns a copy of the array. Note that for elements which are reference values (e.g. objects such Returns a copy of the array. Note that for elements which are reference values (e.g. objects such
as arrays and dictionaries) only the references are copied. as arrays and dictionaries) only the references are copied.
@ -582,11 +582,11 @@ Joins all elements of the array using the specified separator.
## <a id="dictionary-type"></a> Dictionary type ## <a id="dictionary-type"></a> Dictionary type
### <a id="dictionary-clone"></a> Dictionary#clone ### <a id="dictionary-shallow-clone"></a> Dictionary#shallow_clone
Signature: Signature:
function clone(); function shallow_clone();
Returns a copy of the dictionary. Note that for elements which are reference values (e.g. objects such Returns a copy of the dictionary. Note that for elements which are reference values (e.g. objects such
as arrays and dictionaries) only the references are copied. as arrays and dictionaries) only the references are copied.

View File

@ -101,7 +101,7 @@ static Array::Ptr ArraySort(const std::vector<Value>& args)
return arr; return arr;
} }
static Array::Ptr ArrayClone(void) static Array::Ptr ArrayShallowClone(void)
{ {
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self); Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
@ -144,7 +144,7 @@ Object::Ptr Array::GetPrototype(void)
prototype->Set("contains", new Function(WrapFunction(ArrayContains), true)); prototype->Set("contains", new Function(WrapFunction(ArrayContains), true));
prototype->Set("clear", new Function(WrapFunction(ArrayClear))); prototype->Set("clear", new Function(WrapFunction(ArrayClear)));
prototype->Set("sort", new Function(WrapFunction(ArraySort), true)); prototype->Set("sort", new Function(WrapFunction(ArraySort), true));
prototype->Set("clone", new Function(WrapFunction(ArrayClone), true)); prototype->Set("shallow_clone", new Function(WrapFunction(ArrayShallowClone), true));
prototype->Set("join", new Function(WrapFunction(ArrayJoin), true)); prototype->Set("join", new Function(WrapFunction(ArrayJoin), true));
} }

View File

@ -182,3 +182,21 @@ Array::Ptr Array::ShallowClone(void) const
return clone; return clone;
} }
/**
* Makes a deep clone of an array
* and its elements.
*
* @returns a copy of the array.
*/
Object::Ptr Array::Clone(void) const
{
Array::Ptr arr = new Array();
ObjectLock olock(this);
BOOST_FOREACH(const Value& val, m_Data) {
arr->Add(val.Clone());
}
return arr;
}

View File

@ -109,6 +109,8 @@ public:
std::copy(v.begin(), v.end(), std::back_inserter(result->m_Data)); std::copy(v.begin(), v.end(), std::back_inserter(result->m_Data));
return result; return result;
} }
virtual Object::Ptr Clone(void) const;
private: private:
std::vector<Value> m_Data; /**< The data for the array. */ std::vector<Value> m_Data; /**< The data for the array. */

View File

@ -61,7 +61,7 @@ static bool DictionaryContains(const String& key)
return self->Contains(key); return self->Contains(key);
} }
static Dictionary::Ptr DictionaryClone(void) static Dictionary::Ptr DictionaryShallowClone(void)
{ {
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self); Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
@ -91,7 +91,7 @@ Object::Ptr Dictionary::GetPrototype(void)
prototype->Set("get", new Function(WrapFunction(DictionaryGet))); prototype->Set("get", new Function(WrapFunction(DictionaryGet)));
prototype->Set("remove", new Function(WrapFunction(DictionaryRemove))); prototype->Set("remove", new Function(WrapFunction(DictionaryRemove)));
prototype->Set("contains", new Function(WrapFunction(DictionaryContains), true)); prototype->Set("contains", new Function(WrapFunction(DictionaryContains), true));
prototype->Set("clone", new Function(WrapFunction(DictionaryClone), true)); prototype->Set("shallow_clone", new Function(WrapFunction(DictionaryShallowClone), true));
prototype->Set("keys", new Function(WrapFunction(DictionaryKeys), true)); prototype->Set("keys", new Function(WrapFunction(DictionaryKeys), true));
} }

View File

@ -164,6 +164,24 @@ Dictionary::Ptr Dictionary::ShallowClone(void) const
return clone; return clone;
} }
/**
* Makes a deep clone of a dictionary
* and its elements.
*
* @returns a copy of the dictionary.
*/
Object::Ptr Dictionary::Clone(void) const
{
Dictionary::Ptr dict = new Dictionary();
ObjectLock olock(this);
BOOST_FOREACH(const Dictionary::Pair& kv, m_Data) {
dict->Set(kv.first, kv.second.Clone());
}
return dict;
}
/** /**
* Returns an array containing all keys * Returns an array containing all keys
* which are currently set in this directory. * which are currently set in this directory.

View File

@ -112,6 +112,8 @@ public:
std::vector<String> GetKeys(void) const; std::vector<String> GetKeys(void) const;
static Object::Ptr GetPrototype(void); static Object::Ptr GetPrototype(void);
virtual Object::Ptr Clone(void) const;
private: private:
std::map<String, Value> m_Data; /**< The data for the dictionary. */ std::map<String, Value> m_Data; /**< The data for the dictionary. */

View File

@ -39,6 +39,13 @@ static void ObjectNotifyAttribute(const String& attribute)
self->NotifyField(self->GetReflectionType()->GetFieldId(attribute)); self->NotifyField(self->GetReflectionType()->GetFieldId(attribute));
} }
static Object::Ptr ObjectClone(void)
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Object::Ptr self = static_cast<Object::Ptr>(vframe->Self);
return self->Clone();
}
Object::Ptr Object::GetPrototype(void) Object::Ptr Object::GetPrototype(void)
{ {
static Dictionary::Ptr prototype; static Dictionary::Ptr prototype;
@ -47,6 +54,7 @@ Object::Ptr Object::GetPrototype(void)
prototype = new Dictionary(); prototype = new Dictionary();
prototype->Set("to_string", new Function(WrapFunction(ObjectToString), true)); prototype->Set("to_string", new Function(WrapFunction(ObjectToString), true));
prototype->Set("notify_attribute", new Function(WrapFunction(ObjectNotifyAttribute), false)); prototype->Set("notify_attribute", new Function(WrapFunction(ObjectNotifyAttribute), false));
prototype->Set("clone", new Function(WrapFunction(ObjectClone), true));
} }
return prototype; return prototype;

View File

@ -101,3 +101,8 @@ void Object::NotifyField(int id, const Value& cookie)
{ {
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID."));
} }
Object::Ptr Object::Clone(void) const
{
BOOST_THROW_EXCEPTION(std::runtime_error("Object cannot be cloned."));
}

View File

@ -111,6 +111,8 @@ public:
void InflateMutex(void); void InflateMutex(void);
static Object::Ptr GetPrototype(void); static Object::Ptr GetPrototype(void);
virtual Object::Ptr Clone(void) const;
private: private:
Object(const Object& other); Object(const Object& other);

View File

@ -104,3 +104,11 @@ Type::Ptr Value::GetReflectionType(void) const
} }
} }
Value Value::Clone(void) const
{
if (IsObject())
return static_cast<Object::Ptr>(*this)->Clone();
else
return *this;
}

View File

@ -234,6 +234,8 @@ public:
String GetTypeName(void) const; String GetTypeName(void) const;
Type::Ptr GetReflectionType(void) const; Type::Ptr GetReflectionType(void) const;
Value Clone(void) const;
private: private:
boost::variant<boost::blank, double, bool, String, Object::Ptr> m_Value; boost::variant<boost::blank, double, bool, String, Object::Ptr> m_Value;