From a82bf83ea21b0539513b0b3817332deb61329245 Mon Sep 17 00:00:00 2001 From: William Tumeo Date: Fri, 16 Jun 2017 00:41:51 -0300 Subject: [PATCH 1/2] Add advanced string format Cherry-pick from #7010 --- core/ustring.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++ core/ustring.h | 1 + core/variant_call.cpp | 2 ++ 3 files changed, 75 insertions(+) diff --git a/core/ustring.cpp b/core/ustring.cpp index 394c68516ae..db9a711a7b1 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -2776,6 +2776,78 @@ bool String::matchn(const String &p_wildcard) const { return _wildcard_match(p_wildcard.c_str(), c_str(), false); } +String String::format(const Variant &values, String placeholder) const { + + String new_string = String(this->ptr()); + + if (values.get_type() == Variant::ARRAY) { + Array values_arr = values; + + for (int i = 0; i < values_arr.size(); i++) { + String i_as_str = String::num_int64(i); + + if (values_arr[i].get_type() == Variant::ARRAY) { //Array in Array structure [["name","RobotGuy"],[0,"godot"],["strength",9000.91]] + Array value_arr = values_arr[i]; + + if (value_arr.size() == 2) { + Variant v_key = value_arr[0]; + String key; + + key = v_key.get_construct_string(); + if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") { + key = key.substr(1, key.length() - 2); + } + + Variant v_val = value_arr[1]; + String val; + val = v_val.get_construct_string(); + + if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { + val = val.substr(1, val.length() - 2); + } + + new_string = new_string.replacen(placeholder.replace("_", key), val); + } else { + ERR_PRINT(String("STRING.format Inner Array size != 2 ").ascii().get_data()); + } + } else { //Array structure ["RobotGuy","Logis","rookie"] + Variant v_val = values_arr[i]; + String val; + val = v_val.get_construct_string(); + + if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { + val = val.substr(1, val.length() - 2); + } + + new_string = new_string.replacen(placeholder.replace("_", i_as_str), val); + } + } + } else if (values.get_type() == Variant::DICTIONARY) { + Dictionary d = values; + List keys; + d.get_key_list(&keys); + + for (List::Element *E = keys.front(); E; E = E->next()) { + String key = E->get().get_construct_string(); + String val = d[E->get()].get_construct_string(); + + if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") { + key = key.substr(1, key.length() - 2); + } + + if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { + val = val.substr(1, val.length() - 2); + } + + new_string = new_string.replacen(placeholder.replace("_", key), val); + } + } else { + ERR_PRINT(String("Invalid type: use Array or Dictionary.").ascii().get_data()); + } + + return new_string; +} + String String::replace(String p_key, String p_with) const { String new_string; diff --git a/core/ustring.h b/core/ustring.h index 5516675de17..c6b894143f4 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -120,6 +120,7 @@ public: bool is_subsequence_ofi(const String &p_string) const; Vector bigrams() const; float similarity(const String &p_string) const; + String format(const Variant& values, String placeholder = "{_}") const; String replace_first(String p_key, String p_with) const; String replace(String p_key, String p_with) const; String replacen(String p_key, String p_with) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 01a3b4a1b03..3d11f6577d9 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -241,6 +241,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(String, is_subsequence_ofi); VCALL_LOCALMEM0R(String, bigrams); VCALL_LOCALMEM1R(String, similarity); + VCALL_LOCALMEM2R(String, format); VCALL_LOCALMEM2R(String, replace); VCALL_LOCALMEM2R(String, replacen); VCALL_LOCALMEM2R(String, insert); @@ -1317,6 +1318,7 @@ void register_variant_methods() { ADDFUNC0(STRING, STRING_ARRAY, String, bigrams, varray()); ADDFUNC1(STRING, REAL, String, similarity, STRING, "text", varray()); + ADDFUNC2(STRING, STRING, String, format, NIL, "values", STRING, "placeholder", varray("{_}")); ADDFUNC2(STRING, STRING, String, replace, STRING, "what", STRING, "forwhat", varray()); ADDFUNC2(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray()); ADDFUNC2(STRING, STRING, String, insert, INT, "pos", STRING, "what", varray()); From b8a16fbd0e56a2f55d62d0de07c91e3c6f0b6dd4 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 8 Jan 2017 14:16:21 -0300 Subject: [PATCH 2/2] Dictionary keys are now sorted by insertion order - Cherry-pick from 0a59c3c3a6a8c13a5c82d59d9587fca31f900604 --- core/dictionary.cpp | 79 ++++++++++++++++++++++++++++++++++++++------- core/hash_map.h | 14 ++++++++ 2 files changed, 81 insertions(+), 12 deletions(-) diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 599224da14c..382129e4e7c 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -39,14 +39,40 @@ struct _DictionaryVariantHash { struct DictionaryPrivate { + struct Data { + Variant variant; + int order; + }; + SafeRefCount refcount; - HashMap variant_map; + HashMap variant_map; + int counter; bool shared; }; +struct DictionaryPrivateSort { + + bool operator()(const HashMap::Pair *A, const HashMap::Pair *B) const { + + return A->data.order < B->data.order; + } +}; + void Dictionary::get_key_list(List *p_keys) const { - _p->variant_map.get_key_list(p_keys); + if (_p->variant_map.empty()) + return; + + int count = _p->variant_map.size(); + const HashMap::Pair **pairs = (const HashMap::Pair **)alloca(count * sizeof(HashMap::Pair *)); + _p->variant_map.get_key_value_ptr_array(pairs); + + SortArray::Pair *, DictionaryPrivateSort> sort; + sort.sort(pairs, count); + + for (int i = 0; i < count; i++) { + p_keys->push_back(pairs[i]->key); + } } void Dictionary::_copy_on_write() const { @@ -67,29 +93,47 @@ Variant &Dictionary::operator[](const Variant &p_key) { _copy_on_write(); - return _p->variant_map[p_key]; + DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key); + + if (!v) { + + DictionaryPrivate::Data d; + d.order = _p->counter++; + _p->variant_map[p_key] = d; + v = _p->variant_map.getptr(p_key); + } + return v->variant; } const Variant &Dictionary::operator[](const Variant &p_key) const { - return _p->variant_map[p_key]; + return _p->variant_map[p_key].variant; } const Variant *Dictionary::getptr(const Variant &p_key) const { - return _p->variant_map.getptr(p_key); + const DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key); + if (!v) + return NULL; + else + return &v->variant; } Variant *Dictionary::getptr(const Variant &p_key) { _copy_on_write(); - return _p->variant_map.getptr(p_key); + DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key); + if (!v) + return NULL; + else + return &v->variant; } Variant Dictionary::get_valid(const Variant &p_key) const { - const Variant *v = getptr(p_key); + DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key); if (!v) return Variant(); - return *v; + else + return v->variant; } int Dictionary::size() const { @@ -145,6 +189,7 @@ void Dictionary::clear() { _copy_on_write(); _p->variant_map.clear(); + _p->counter = 0; } bool Dictionary::is_shared() const { @@ -192,11 +237,20 @@ Array Dictionary::values() const { Array varr; varr.resize(size()); - const Variant *key = NULL; - int i = 0; - while ((key = next(key))) { - varr[i++] = _p->variant_map[*key]; + if (_p->variant_map.empty()) + return varr; + + int count = _p->variant_map.size(); + const HashMap::Pair **pairs = (const HashMap::Pair **)alloca(count * sizeof(HashMap::Pair *)); + _p->variant_map.get_key_value_ptr_array(pairs); + + SortArray::Pair *, DictionaryPrivateSort> sort; + sort.sort(pairs, count); + + for (int i = 0; i < count; i++) { + varr[i] = pairs[i]->data.variant; } + return varr; } @@ -239,6 +293,7 @@ Dictionary::Dictionary(bool p_shared) { _p = memnew(DictionaryPrivate); _p->refcount.init(); + _p->counter = 0; _p->shared = p_shared; } Dictionary::~Dictionary() { diff --git a/core/hash_map.h b/core/hash_map.h index 1bbe6c1877f..1096269787e 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -570,6 +570,20 @@ public: hash_table_power = 0; } + void get_key_value_ptr_array(const Pair **p_pairs) const { + if (!hash_table) + return; + for (int i = 0; i < (1 << hash_table_power); i++) { + + Entry *e = hash_table[i]; + while (e) { + *p_pairs = &e->pair; + p_pairs++; + e = e->next; + } + } + } + void get_key_list(List *p_keys) const { if (!hash_table) return;