|
@@ -41,6 +41,7 @@
|
|
|
|
|
|
struct DictionaryPrivate {
|
|
struct DictionaryPrivate {
|
|
SafeRefCount refcount;
|
|
SafeRefCount refcount;
|
|
|
|
+ Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
|
|
HashMap<Variant, Variant, VariantHasher, VariantComparator> variant_map;
|
|
HashMap<Variant, Variant, VariantHasher, VariantComparator> variant_map;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -79,11 +80,22 @@ Variant Dictionary::get_value_at_index(int p_index) const {
|
|
}
|
|
}
|
|
|
|
|
|
Variant &Dictionary::operator[](const Variant &p_key) {
|
|
Variant &Dictionary::operator[](const Variant &p_key) {
|
|
- if (p_key.get_type() == Variant::STRING_NAME) {
|
|
|
|
- const StringName *sn = VariantInternal::get_string_name(&p_key);
|
|
|
|
- return _p->variant_map[sn->operator String()];
|
|
|
|
|
|
+ if (unlikely(_p->read_only)) {
|
|
|
|
+ if (p_key.get_type() == Variant::STRING_NAME) {
|
|
|
|
+ const StringName *sn = VariantInternal::get_string_name(&p_key);
|
|
|
|
+ *_p->read_only = _p->variant_map[sn->operator String()];
|
|
|
|
+ } else {
|
|
|
|
+ *_p->read_only = _p->variant_map[p_key];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return *_p->read_only;
|
|
} else {
|
|
} else {
|
|
- return _p->variant_map[p_key];
|
|
|
|
|
|
+ if (p_key.get_type() == Variant::STRING_NAME) {
|
|
|
|
+ const StringName *sn = VariantInternal::get_string_name(&p_key);
|
|
|
|
+ return _p->variant_map[sn->operator String()];
|
|
|
|
+ } else {
|
|
|
|
+ return _p->variant_map[p_key];
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -124,7 +136,12 @@ Variant *Dictionary::getptr(const Variant &p_key) {
|
|
if (!E) {
|
|
if (!E) {
|
|
return nullptr;
|
|
return nullptr;
|
|
}
|
|
}
|
|
- return &E->value;
|
|
|
|
|
|
+ if (unlikely(_p->read_only != nullptr)) {
|
|
|
|
+ *_p->read_only = E->value;
|
|
|
|
+ return _p->read_only;
|
|
|
|
+ } else {
|
|
|
|
+ return &E->value;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
Variant Dictionary::get_valid(const Variant &p_key) const {
|
|
Variant Dictionary::get_valid(const Variant &p_key) const {
|
|
@@ -179,6 +196,7 @@ bool Dictionary::has_all(const Array &p_keys) const {
|
|
}
|
|
}
|
|
|
|
|
|
bool Dictionary::erase(const Variant &p_key) {
|
|
bool Dictionary::erase(const Variant &p_key) {
|
|
|
|
+ ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
|
|
if (p_key.get_type() == Variant::STRING_NAME) {
|
|
if (p_key.get_type() == Variant::STRING_NAME) {
|
|
const StringName *sn = VariantInternal::get_string_name(&p_key);
|
|
const StringName *sn = VariantInternal::get_string_name(&p_key);
|
|
return _p->variant_map.erase(sn->operator String());
|
|
return _p->variant_map.erase(sn->operator String());
|
|
@@ -220,6 +238,16 @@ bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_c
|
|
}
|
|
}
|
|
|
|
|
|
void Dictionary::_ref(const Dictionary &p_from) const {
|
|
void Dictionary::_ref(const Dictionary &p_from) const {
|
|
|
|
+ if (unlikely(p_from._p->read_only != nullptr)) {
|
|
|
|
+ // If p_from is a read-only dictionary, just copy the contents to avoid further modification.
|
|
|
|
+ if (_p) {
|
|
|
|
+ _unref();
|
|
|
|
+ }
|
|
|
|
+ _p = memnew(DictionaryPrivate);
|
|
|
|
+ _p->refcount.init();
|
|
|
|
+ _p->variant_map = p_from._p->variant_map;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
//make a copy first (thread safe)
|
|
//make a copy first (thread safe)
|
|
if (!p_from._p->refcount.ref()) {
|
|
if (!p_from._p->refcount.ref()) {
|
|
return; // couldn't copy
|
|
return; // couldn't copy
|
|
@@ -237,12 +265,16 @@ void Dictionary::_ref(const Dictionary &p_from) const {
|
|
}
|
|
}
|
|
|
|
|
|
void Dictionary::clear() {
|
|
void Dictionary::clear() {
|
|
|
|
+ ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state.");
|
|
_p->variant_map.clear();
|
|
_p->variant_map.clear();
|
|
}
|
|
}
|
|
|
|
|
|
void Dictionary::_unref() const {
|
|
void Dictionary::_unref() const {
|
|
ERR_FAIL_COND(!_p);
|
|
ERR_FAIL_COND(!_p);
|
|
if (_p->refcount.unref()) {
|
|
if (_p->refcount.unref()) {
|
|
|
|
+ if (_p->read_only) {
|
|
|
|
+ memdelete(_p->read_only);
|
|
|
|
+ }
|
|
memdelete(_p);
|
|
memdelete(_p);
|
|
}
|
|
}
|
|
_p = nullptr;
|
|
_p = nullptr;
|
|
@@ -330,6 +362,21 @@ Dictionary Dictionary::duplicate(bool p_deep) const {
|
|
return recursive_duplicate(p_deep, 0);
|
|
return recursive_duplicate(p_deep, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void Dictionary::set_read_only(bool p_enable) {
|
|
|
|
+ if (p_enable == bool(_p->read_only != nullptr)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (p_enable) {
|
|
|
|
+ _p->read_only = memnew(Variant);
|
|
|
|
+ } else {
|
|
|
|
+ memdelete(_p->read_only);
|
|
|
|
+ _p->read_only = nullptr;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+bool Dictionary::is_read_only() const {
|
|
|
|
+ return _p->read_only != nullptr;
|
|
|
|
+}
|
|
|
|
+
|
|
Dictionary Dictionary::recursive_duplicate(bool p_deep, int recursion_count) const {
|
|
Dictionary Dictionary::recursive_duplicate(bool p_deep, int recursion_count) const {
|
|
Dictionary n;
|
|
Dictionary n;
|
|
|
|
|
|
@@ -353,6 +400,9 @@ Dictionary Dictionary::recursive_duplicate(bool p_deep, int recursion_count) con
|
|
}
|
|
}
|
|
|
|
|
|
void Dictionary::operator=(const Dictionary &p_dictionary) {
|
|
void Dictionary::operator=(const Dictionary &p_dictionary) {
|
|
|
|
+ if (this == &p_dictionary) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
_ref(p_dictionary);
|
|
_ref(p_dictionary);
|
|
}
|
|
}
|
|
|
|
|