Merge pull request #61087 from reduz/readonly-dictionary
Implement read-only dictionaries.
This commit is contained in:
commit
35004aea48
3 changed files with 71 additions and 5 deletions
|
@ -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,6 +80,16 @@ 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 (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 {
|
||||||
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[sn->operator String()];
|
return _p->variant_map[sn->operator String()];
|
||||||
|
@ -86,6 +97,7 @@ Variant &Dictionary::operator[](const Variant &p_key) {
|
||||||
return _p->variant_map[p_key];
|
return _p->variant_map[p_key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Variant &Dictionary::operator[](const Variant &p_key) const {
|
const Variant &Dictionary::operator[](const Variant &p_key) const {
|
||||||
if (p_key.get_type() == Variant::STRING_NAME) {
|
if (p_key.get_type() == Variant::STRING_NAME) {
|
||||||
|
@ -124,8 +136,13 @@ Variant *Dictionary::getptr(const Variant &p_key) {
|
||||||
if (!E) {
|
if (!E) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (unlikely(_p->read_only != nullptr)) {
|
||||||
|
*_p->read_only = E->value;
|
||||||
|
return _p->read_only;
|
||||||
|
} else {
|
||||||
return &E->value;
|
return &E->value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Variant Dictionary::get_valid(const Variant &p_key) const {
|
Variant Dictionary::get_valid(const Variant &p_key) const {
|
||||||
HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E;
|
HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,9 @@ public:
|
||||||
Dictionary duplicate(bool p_deep = false) const;
|
Dictionary duplicate(bool p_deep = false) const;
|
||||||
Dictionary recursive_duplicate(bool p_deep, int recursion_count) const;
|
Dictionary recursive_duplicate(bool p_deep, int recursion_count) const;
|
||||||
|
|
||||||
|
void set_read_only(bool p_enable);
|
||||||
|
bool is_read_only() const;
|
||||||
|
|
||||||
const void *id() const;
|
const void *id() const;
|
||||||
|
|
||||||
Dictionary(const Dictionary &p_from);
|
Dictionary(const Dictionary &p_from);
|
||||||
|
|
|
@ -766,11 +766,20 @@ struct VariantIndexedSetGet_String {
|
||||||
PtrToArg<Variant>::encode(*ptr, member); \
|
PtrToArg<Variant>::encode(*ptr, member); \
|
||||||
} \
|
} \
|
||||||
static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
|
static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
|
||||||
|
if (VariantGetInternalPtr<m_base_type>::get_ptr(base)->is_read_only()) { \
|
||||||
|
*valid = false; \
|
||||||
|
*oob = true; \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
|
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
|
||||||
*oob = false; \
|
*oob = false; \
|
||||||
*valid = true; \
|
*valid = true; \
|
||||||
} \
|
} \
|
||||||
static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
|
static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
|
||||||
|
if (VariantGetInternalPtr<m_base_type>::get_ptr(base)->is_read_only()) { \
|
||||||
|
*oob = true; \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
|
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
|
||||||
*oob = false; \
|
*oob = false; \
|
||||||
} \
|
} \
|
||||||
|
@ -946,6 +955,10 @@ struct VariantKeyedSetGetDictionary {
|
||||||
PtrToArg<Variant>::encode(*ptr, value);
|
PtrToArg<Variant>::encode(*ptr, value);
|
||||||
}
|
}
|
||||||
static void set(Variant *base, const Variant *key, const Variant *value, bool *r_valid) {
|
static void set(Variant *base, const Variant *key, const Variant *value, bool *r_valid) {
|
||||||
|
if (VariantGetInternalPtr<Dictionary>::get_ptr(base)->is_read_only()) {
|
||||||
|
*r_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
(*VariantGetInternalPtr<Dictionary>::get_ptr(base))[*key] = *value;
|
(*VariantGetInternalPtr<Dictionary>::get_ptr(base))[*key] = *value;
|
||||||
*r_valid = true;
|
*r_valid = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue