From e361b3c4276261017652a5bb28919f79059ebec3 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 30 Jan 2018 12:19:34 +0100 Subject: [PATCH] Implement support for frozen arrays and dictionaries --- doc/18-library-reference.md | 16 ++++++++++++++ lib/base/array-script.cpp | 10 ++++++++- lib/base/array.cpp | 40 ++++++++++++++++++++++++++++++++++ lib/base/array.hpp | 3 +++ lib/base/dictionary-script.cpp | 10 ++++++++- lib/base/dictionary.cpp | 18 +++++++++++++++ lib/base/dictionary.hpp | 3 +++ 7 files changed, 98 insertions(+), 2 deletions(-) diff --git a/doc/18-library-reference.md b/doc/18-library-reference.md index 758e40407..fcef4597b 100644 --- a/doc/18-library-reference.md +++ b/doc/18-library-reference.md @@ -1260,6 +1260,14 @@ Signature: Returns true if the array contains the specified value, false otherwise. +### Array#freeze + +Signature: + + function freeze() + +Disallows further modifications to this array. Trying to modify the array will result in an exception. + ### Array#len Signature: @@ -1395,6 +1403,14 @@ Signature: Returns true if a dictionary item with the specified `key` exists, false otherwise. +### Dictionary#freeze + +Signature: + + function freeze() + +Disallows further modifications to this dictionary. Trying to modify the dictionary will result in an exception. + ### Dictionary#len Signature: diff --git a/lib/base/array-script.cpp b/lib/base/array-script.cpp index 3f7278ff6..3a59b7fb8 100644 --- a/lib/base/array-script.cpp +++ b/lib/base/array-script.cpp @@ -245,6 +245,13 @@ static Array::Ptr ArrayUnique() return Array::FromSet(result); } +static void ArrayFreeze() +{ + ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + self->Freeze(); +} + Object::Ptr Array::GetPrototype() { static Dictionary::Ptr prototype = new Dictionary({ @@ -264,7 +271,8 @@ Object::Ptr Array::GetPrototype() { "filter", new Function("Array#filter", ArrayFilter, { "func" }, true) }, { "any", new Function("Array#any", ArrayAny, { "func" }, true) }, { "all", new Function("Array#all", ArrayAll, { "func" }, true) }, - { "unique", new Function("Array#unique", ArrayUnique, {}, true) } + { "unique", new Function("Array#unique", ArrayUnique, {}, true) }, + { "freeze", new Function("Array#freeze", ArrayFreeze, {}) } }); return prototype; diff --git a/lib/base/array.cpp b/lib/base/array.cpp index d6e8ee03e..ac2ade93e 100644 --- a/lib/base/array.cpp +++ b/lib/base/array.cpp @@ -67,6 +67,9 @@ void Array::Set(SizeType index, const Value& value) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.at(index) = value; } @@ -80,6 +83,9 @@ void Array::Set(SizeType index, Value&& value) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.at(index).Swap(value); } @@ -92,6 +98,9 @@ void Array::Add(Value value) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.push_back(std::move(value)); } @@ -160,6 +169,9 @@ void Array::Insert(SizeType index, Value value) ASSERT(index <= m_Data.size()); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.insert(m_Data.begin() + index, std::move(value)); } @@ -172,6 +184,9 @@ void Array::Remove(SizeType index) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.erase(m_Data.begin() + index); } @@ -184,6 +199,9 @@ void Array::Remove(Array::Iterator it) { ASSERT(OwnsLock()); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.erase(it); } @@ -191,6 +209,9 @@ void Array::Resize(SizeType newSize) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.resize(newSize); } @@ -198,6 +219,9 @@ void Array::Clear() { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.clear(); } @@ -205,6 +229,9 @@ void Array::Reserve(SizeType newSize) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + m_Data.reserve(newSize); } @@ -213,6 +240,9 @@ void Array::CopyTo(const Array::Ptr& dest) const ObjectLock olock(this); ObjectLock xlock(dest); + if (dest->m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + std::copy(m_Data.begin(), m_Data.end(), std::back_inserter(dest->m_Data)); } @@ -261,6 +291,10 @@ Array::Ptr Array::Reverse() const void Array::Sort() { ObjectLock olock(this); + + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + std::sort(m_Data.begin(), m_Data.end()); } @@ -271,6 +305,12 @@ String Array::ToString() const return msgbuf.str(); } +void Array::Freeze() +{ + ObjectLock olock(this); + m_Frozen = true; +} + Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const { int index; diff --git a/lib/base/array.hpp b/lib/base/array.hpp index 6fd1abae5..768cee131 100644 --- a/lib/base/array.hpp +++ b/lib/base/array.hpp @@ -112,11 +112,14 @@ public: String ToString() const override; + void Freeze(); + Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; private: std::vector m_Data; /**< The data for the array. */ + bool m_Frozen{false}; }; Array::Iterator begin(const Array::Ptr& x); diff --git a/lib/base/dictionary-script.cpp b/lib/base/dictionary-script.cpp index a45afa826..547f814b1 100644 --- a/lib/base/dictionary-script.cpp +++ b/lib/base/dictionary-script.cpp @@ -91,6 +91,13 @@ static Array::Ptr DictionaryValues() return new Array(std::move(values)); } +static void DictionaryFreeze() +{ + ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); + Dictionary::Ptr self = static_cast(vframe->Self); + self->Freeze(); +} + Object::Ptr Dictionary::GetPrototype() { static Dictionary::Ptr prototype = new Dictionary({ @@ -101,7 +108,8 @@ Object::Ptr Dictionary::GetPrototype() { "contains", new Function("Dictionary#contains", DictionaryContains, { "key" }, true) }, { "shallow_clone", new Function("Dictionary#shallow_clone", DictionaryShallowClone, {}, true) }, { "keys", new Function("Dictionary#keys", DictionaryKeys, {}, true) }, - { "values", new Function("Dictionary#values", DictionaryValues, {}, true) } + { "values", new Function("Dictionary#values", DictionaryValues, {}, true) }, + { "freeze", new Function("Dictionary#freeze", DictionaryFreeze, {}) } }); return prototype; diff --git a/lib/base/dictionary.cpp b/lib/base/dictionary.cpp index 50fb5d750..a64540404 100644 --- a/lib/base/dictionary.cpp +++ b/lib/base/dictionary.cpp @@ -94,6 +94,9 @@ void Dictionary::Set(const String& key, Value value) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); + m_Data[key] = std::move(value); } @@ -159,6 +162,9 @@ void Dictionary::Remove(Dictionary::Iterator it) { ASSERT(OwnsLock()); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); + m_Data.erase(it); } @@ -171,6 +177,9 @@ void Dictionary::Remove(const String& key) { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); + Dictionary::Iterator it; it = m_Data.find(key); @@ -187,6 +196,9 @@ void Dictionary::Clear() { ObjectLock olock(this); + if (m_Frozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); + m_Data.clear(); } @@ -260,6 +272,12 @@ String Dictionary::ToString() const return msgbuf.str(); } +void Dictionary::Freeze() +{ + ObjectLock olock(this); + m_Frozen = true; +} + Value Dictionary::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const { Value value; diff --git a/lib/base/dictionary.hpp b/lib/base/dictionary.hpp index 7854573a6..97ca81b78 100644 --- a/lib/base/dictionary.hpp +++ b/lib/base/dictionary.hpp @@ -83,6 +83,8 @@ public: String ToString() const override; + void Freeze(); + Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; bool HasOwnField(const String& field) const override; @@ -90,6 +92,7 @@ public: private: std::map m_Data; /**< The data for the dictionary. */ + bool m_Frozen{false}; }; Dictionary::Iterator begin(const Dictionary::Ptr& x);