Reduce String CoW

By introducing an intermediate proxy class for the array subscript
operator for String and CharString we can control better when CowData
will actually CoW.

This should improve performance of String usage for most cases.
This commit is contained in:
Hein-Pieter van Braam 2018-12-16 00:44:18 +00:00
parent 7ac67bfec1
commit 4e25e5066b
8 changed files with 44 additions and 13 deletions

View file

@ -83,7 +83,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
if (ps.orig_len != 0) { if (ps.orig_len != 0) {
CharString dst_s; CharString dst_s;
dst_s.resize(src_s.size()); dst_s.resize(src_s.size());
int ret = smaz_compress(src_s.get_data(), src_s.size(), &dst_s[0], src_s.size()); int ret = smaz_compress(src_s.get_data(), src_s.size(), dst_s.ptrw(), src_s.size());
if (ret >= src_s.size()) { if (ret >= src_s.size()) {
//if compressed is larger than original, just use original //if compressed is larger than original, just use original
ps.orig_len = src_s.size(); ps.orig_len = src_s.size();

View file

@ -179,7 +179,7 @@ void String::copy_from_unchecked(const CharType *p_char, const int p_length) {
resize(p_length + 1); resize(p_length + 1);
set(p_length, 0); set(p_length, 0);
CharType *dst = &operator[](0); CharType *dst = ptrw();
for (int i = 0; i < p_length; i++) { for (int i = 0; i < p_length; i++) {
dst[i] = p_char[i]; dst[i] = p_char[i];
@ -250,7 +250,7 @@ String &String::operator+=(const String &p_str) {
resize(length() + p_str.size()); resize(length() + p_str.size());
const CharType *src = p_str.c_str(); const CharType *src = p_str.c_str();
CharType *dst = &operator[](0); CharType *dst = ptrw();
set(length(), 0); set(length(), 0);
@ -289,7 +289,7 @@ String &String::operator+=(const char *p_str) {
resize(from + src_len + 1); resize(from + src_len + 1);
CharType *dst = &operator[](0); CharType *dst = ptrw();
set(length(), 0); set(length(), 0);
@ -1431,7 +1431,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
} }
resize(str_size + 1); resize(str_size + 1);
CharType *dst = &operator[](0); CharType *dst = ptrw();
dst[str_size] = 0; dst[str_size] = 0;
while (cstr_size) { while (cstr_size) {
@ -3476,7 +3476,7 @@ String String::xml_unescape() const {
if (len == 0) if (len == 0)
return String(); return String();
str.resize(len + 1); str.resize(len + 1);
_xml_unescape(c_str(), l, &str[0]); _xml_unescape(c_str(), l, str.ptrw());
str[len] = 0; str[len] = 0;
return str; return str;
} }

View file

@ -40,6 +40,36 @@
@author Juan Linietsky <reduzio@gmail.com> @author Juan Linietsky <reduzio@gmail.com>
*/ */
template <class T>
class CharProxy {
friend class CharString;
friend class String;
const int _index;
CowData<T> &_cowdata;
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &cowdata) :
_index(p_index),
_cowdata(cowdata) {}
public:
_FORCE_INLINE_ operator T() const {
return _cowdata.get(_index);
}
_FORCE_INLINE_ const T *operator&() const {
return _cowdata.ptr() + _index;
}
_FORCE_INLINE_ void operator=(const T &other) const {
_cowdata.set(_index, other);
}
_FORCE_INLINE_ void operator=(const CharProxy<T> &other) const {
_cowdata.set(_index, other.operator T());
}
};
class CharString { class CharString {
CowData<char> _cowdata; CowData<char> _cowdata;
@ -53,8 +83,8 @@ public:
_FORCE_INLINE_ char get(int p_index) { return _cowdata.get(p_index); } _FORCE_INLINE_ char get(int p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const char get(int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ const char get(int p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const char &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ void set(int p_index, const char &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ char &operator[](int p_index) { return _cowdata.get_m(p_index); }
_FORCE_INLINE_ const char &operator[](int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ const char &operator[](int p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ CharProxy<char> operator[](int p_index) { return CharProxy<char>(p_index, _cowdata); }
_FORCE_INLINE_ CharString() {} _FORCE_INLINE_ CharString() {}
_FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); } _FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); }
@ -107,8 +137,9 @@ public:
_FORCE_INLINE_ void set(int p_index, const CharType &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ void set(int p_index, const CharType &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); } _FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); } Error resize(int p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ CharType &operator[](int p_index) { return _cowdata.get_m(p_index); }
_FORCE_INLINE_ const CharType &operator[](int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ const CharType &operator[](int p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ CharProxy<CharType> operator[](int p_index) { return CharProxy<CharType>(p_index, _cowdata); }
bool operator==(const String &p_str) const; bool operator==(const String &p_str) const;
bool operator!=(const String &p_str) const; bool operator!=(const String &p_str) const;

View file

@ -74,7 +74,7 @@ void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t
memnew_placement(dest, String(p_contents, p_size)); memnew_placement(dest, String(p_contents, p_size));
} }
wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx) { const wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx) {
String *self = (String *)p_self; String *self = (String *)p_self;
return &(self->operator[](p_idx)); return &(self->operator[](p_idx));
} }

View file

@ -4755,7 +4755,7 @@
}, },
{ {
"name": "godot_string_operator_index", "name": "godot_string_operator_index",
"return_type": "wchar_t *", "return_type": "const wchar_t *",
"arguments": [ "arguments": [
["godot_string *", "p_self"], ["godot_string *", "p_self"],
["const godot_int", "p_idx"] ["const godot_int", "p_idx"]

View file

@ -79,7 +79,7 @@ void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src); void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t *p_contents, const int p_size); void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t *p_contents, const int p_size);
wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx); const wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx);
wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx); wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx);
const wchar_t GDAPI *godot_string_wide_str(const godot_string *p_self); const wchar_t GDAPI *godot_string_wide_str(const godot_string *p_self);

View file

@ -216,7 +216,7 @@ String mono_to_utf16_string(MonoString *p_mono_string) {
ret.set(len, 0); ret.set(len, 0);
CharType *src = (CharType *)mono_string_chars(p_mono_string); CharType *src = (CharType *)mono_string_chars(p_mono_string);
CharType *dst = &(ret.operator[](0)); CharType *dst = ret.ptrw();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
dst[i] = src[i]; dst[i] = src[i];

View file

@ -583,7 +583,7 @@ static void clear_touches() {
character.parse_utf8([p_text UTF8String]); character.parse_utf8([p_text UTF8String]);
keyboard_text = keyboard_text + character; keyboard_text = keyboard_text + character;
OSIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0], true); OSIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0], true);
printf("inserting text with character %i\n", character[0]); printf("inserting text with character %lc\n", (CharType)character[0]);
}; };
- (void)audioRouteChangeListenerCallback:(NSNotification *)notification { - (void)audioRouteChangeListenerCallback:(NSNotification *)notification {