Merge pull request #6044 from gunnarbeutner/feature/frozen-dict-and-array

Implement support for frozen arrays and dictionaries
This commit is contained in:
Noah Hilverling 2018-01-31 09:34:17 +01:00 committed by GitHub
commit b83aaaf1db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 98 additions and 2 deletions

View File

@ -1260,6 +1260,14 @@ Signature:
Returns true if the array contains the specified value, false otherwise. Returns true if the array contains the specified value, false otherwise.
### Array#freeze <a id="array-freeze"></a>
Signature:
function freeze()
Disallows further modifications to this array. Trying to modify the array will result in an exception.
### Array#len <a id="array-len"></a> ### Array#len <a id="array-len"></a>
Signature: Signature:
@ -1395,6 +1403,14 @@ Signature:
Returns true if a dictionary item with the specified `key` exists, false otherwise. Returns true if a dictionary item with the specified `key` exists, false otherwise.
### Dictionary#freeze <a id="dictionary-freeze"></a>
Signature:
function freeze()
Disallows further modifications to this dictionary. Trying to modify the dictionary will result in an exception.
### Dictionary#len <a id="dictionary-len"></a> ### Dictionary#len <a id="dictionary-len"></a>
Signature: Signature:

View File

@ -245,6 +245,13 @@ static Array::Ptr ArrayUnique()
return Array::FromSet(result); return Array::FromSet(result);
} }
static void ArrayFreeze()
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
self->Freeze();
}
Object::Ptr Array::GetPrototype() Object::Ptr Array::GetPrototype()
{ {
static Dictionary::Ptr prototype = new Dictionary({ static Dictionary::Ptr prototype = new Dictionary({
@ -264,7 +271,8 @@ Object::Ptr Array::GetPrototype()
{ "filter", new Function("Array#filter", ArrayFilter, { "func" }, true) }, { "filter", new Function("Array#filter", ArrayFilter, { "func" }, true) },
{ "any", new Function("Array#any", ArrayAny, { "func" }, true) }, { "any", new Function("Array#any", ArrayAny, { "func" }, true) },
{ "all", new Function("Array#all", ArrayAll, { "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; return prototype;

View File

@ -67,6 +67,9 @@ void Array::Set(SizeType index, const Value& value)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.at(index) = value; m_Data.at(index) = value;
} }
@ -80,6 +83,9 @@ void Array::Set(SizeType index, Value&& value)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.at(index).Swap(value); m_Data.at(index).Swap(value);
} }
@ -92,6 +98,9 @@ void Array::Add(Value value)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.push_back(std::move(value)); m_Data.push_back(std::move(value));
} }
@ -160,6 +169,9 @@ void Array::Insert(SizeType index, Value value)
ASSERT(index <= m_Data.size()); 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)); m_Data.insert(m_Data.begin() + index, std::move(value));
} }
@ -172,6 +184,9 @@ void Array::Remove(SizeType index)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.erase(m_Data.begin() + index); m_Data.erase(m_Data.begin() + index);
} }
@ -184,6 +199,9 @@ void Array::Remove(Array::Iterator it)
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.erase(it); m_Data.erase(it);
} }
@ -191,6 +209,9 @@ void Array::Resize(SizeType newSize)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.resize(newSize); m_Data.resize(newSize);
} }
@ -198,6 +219,9 @@ void Array::Clear()
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.clear(); m_Data.clear();
} }
@ -205,6 +229,9 @@ void Array::Reserve(SizeType newSize)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.reserve(newSize); m_Data.reserve(newSize);
} }
@ -213,6 +240,9 @@ void Array::CopyTo(const Array::Ptr& dest) const
ObjectLock olock(this); ObjectLock olock(this);
ObjectLock xlock(dest); 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)); 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() void Array::Sort()
{ {
ObjectLock olock(this); 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()); std::sort(m_Data.begin(), m_Data.end());
} }
@ -271,6 +305,12 @@ String Array::ToString() const
return msgbuf.str(); return msgbuf.str();
} }
void Array::Freeze()
{
ObjectLock olock(this);
m_Frozen = true;
}
Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const
{ {
int index; int index;

View File

@ -112,11 +112,14 @@ public:
String ToString() const override; String ToString() const override;
void Freeze();
Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override;
private: private:
std::vector<Value> m_Data; /**< The data for the array. */ std::vector<Value> m_Data; /**< The data for the array. */
bool m_Frozen{false};
}; };
Array::Iterator begin(const Array::Ptr& x); Array::Iterator begin(const Array::Ptr& x);

View File

@ -91,6 +91,13 @@ static Array::Ptr DictionaryValues()
return new Array(std::move(values)); return new Array(std::move(values));
} }
static void DictionaryFreeze()
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
self->Freeze();
}
Object::Ptr Dictionary::GetPrototype() Object::Ptr Dictionary::GetPrototype()
{ {
static Dictionary::Ptr prototype = new Dictionary({ static Dictionary::Ptr prototype = new Dictionary({
@ -101,7 +108,8 @@ Object::Ptr Dictionary::GetPrototype()
{ "contains", new Function("Dictionary#contains", DictionaryContains, { "key" }, true) }, { "contains", new Function("Dictionary#contains", DictionaryContains, { "key" }, true) },
{ "shallow_clone", new Function("Dictionary#shallow_clone", DictionaryShallowClone, {}, true) }, { "shallow_clone", new Function("Dictionary#shallow_clone", DictionaryShallowClone, {}, true) },
{ "keys", new Function("Dictionary#keys", DictionaryKeys, {}, 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; return prototype;

View File

@ -94,6 +94,9 @@ void Dictionary::Set(const String& key, Value value)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
m_Data[key] = std::move(value); m_Data[key] = std::move(value);
} }
@ -159,6 +162,9 @@ void Dictionary::Remove(Dictionary::Iterator it)
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
m_Data.erase(it); m_Data.erase(it);
} }
@ -171,6 +177,9 @@ void Dictionary::Remove(const String& key)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
Dictionary::Iterator it; Dictionary::Iterator it;
it = m_Data.find(key); it = m_Data.find(key);
@ -187,6 +196,9 @@ void Dictionary::Clear()
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
m_Data.clear(); m_Data.clear();
} }
@ -260,6 +272,12 @@ String Dictionary::ToString() const
return msgbuf.str(); return msgbuf.str();
} }
void Dictionary::Freeze()
{
ObjectLock olock(this);
m_Frozen = true;
}
Value Dictionary::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const Value Dictionary::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const
{ {
Value value; Value value;

View File

@ -83,6 +83,8 @@ public:
String ToString() const override; String ToString() const override;
void Freeze();
Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override;
bool HasOwnField(const String& field) const override; bool HasOwnField(const String& field) const override;
@ -90,6 +92,7 @@ public:
private: private:
std::map<String, Value> m_Data; /**< The data for the dictionary. */ std::map<String, Value> m_Data; /**< The data for the dictionary. */
bool m_Frozen{false};
}; };
Dictionary::Iterator begin(const Dictionary::Ptr& x); Dictionary::Iterator begin(const Dictionary::Ptr& x);