String[size()] should return a default constructed CharType
As per the C++ standard 21.3.4.1 for std::string: Returns: If pos < size(), returns data()[pos]. Otherwise, if pos == size(), the const version returns charT(). Otherwise, the behavior is undefined. Since the behavior is undefined Godot now does the same thing for const and non-const versions of operator[]. This fixes #21242 and fixes #22221.
This commit is contained in:
parent
1504c96112
commit
ac99ed3cda
3 changed files with 49 additions and 2 deletions
|
@ -58,6 +58,9 @@
|
||||||
#define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9')
|
#define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9')
|
||||||
#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
|
#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
|
||||||
|
|
||||||
|
const char CharString::_null = 0;
|
||||||
|
const CharType String::_null = 0;
|
||||||
|
|
||||||
bool is_symbol(CharType c) {
|
bool is_symbol(CharType c) {
|
||||||
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
|
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ class CharProxy {
|
||||||
|
|
||||||
const int _index;
|
const int _index;
|
||||||
CowData<T> &_cowdata;
|
CowData<T> &_cowdata;
|
||||||
|
static const T _null = 0;
|
||||||
|
|
||||||
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &cowdata) :
|
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &cowdata) :
|
||||||
_index(p_index),
|
_index(p_index),
|
||||||
|
@ -54,6 +55,9 @@ class CharProxy {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
_FORCE_INLINE_ operator T() const {
|
_FORCE_INLINE_ operator T() const {
|
||||||
|
if (unlikely(_index == _cowdata.size()))
|
||||||
|
return _null;
|
||||||
|
|
||||||
return _cowdata.get(_index);
|
return _cowdata.get(_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +77,7 @@ public:
|
||||||
class CharString {
|
class CharString {
|
||||||
|
|
||||||
CowData<char> _cowdata;
|
CowData<char> _cowdata;
|
||||||
|
static const char _null;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
_FORCE_INLINE_ char *ptrw() { return _cowdata.ptrw(); }
|
_FORCE_INLINE_ char *ptrw() { return _cowdata.ptrw(); }
|
||||||
|
@ -83,7 +88,12 @@ 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_ const char &operator[](int p_index) const { return _cowdata.get(p_index); }
|
_FORCE_INLINE_ const char &operator[](int p_index) const {
|
||||||
|
if (unlikely(p_index == _cowdata.size()))
|
||||||
|
return _null;
|
||||||
|
|
||||||
|
return _cowdata.get(p_index);
|
||||||
|
}
|
||||||
_FORCE_INLINE_ CharProxy<char> operator[](int p_index) { return CharProxy<char>(p_index, _cowdata); }
|
_FORCE_INLINE_ CharProxy<char> operator[](int p_index) { return CharProxy<char>(p_index, _cowdata); }
|
||||||
|
|
||||||
_FORCE_INLINE_ CharString() {}
|
_FORCE_INLINE_ CharString() {}
|
||||||
|
@ -112,6 +122,7 @@ struct StrRange {
|
||||||
class String {
|
class String {
|
||||||
|
|
||||||
CowData<CharType> _cowdata;
|
CowData<CharType> _cowdata;
|
||||||
|
static const CharType _null;
|
||||||
|
|
||||||
void copy_from(const char *p_cstr);
|
void copy_from(const char *p_cstr);
|
||||||
void copy_from(const CharType *p_cstr, const int p_clip_to = -1);
|
void copy_from(const CharType *p_cstr, const int p_clip_to = -1);
|
||||||
|
@ -138,7 +149,12 @@ public:
|
||||||
_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_ const CharType &operator[](int p_index) const { return _cowdata.get(p_index); }
|
_FORCE_INLINE_ const CharType &operator[](int p_index) const {
|
||||||
|
if (unlikely(p_index == _cowdata.size()))
|
||||||
|
return _null;
|
||||||
|
|
||||||
|
return _cowdata.get(p_index);
|
||||||
|
}
|
||||||
_FORCE_INLINE_ CharProxy<CharType> operator[](int p_index) { return CharProxy<CharType>(p_index, _cowdata); }
|
_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;
|
||||||
|
|
|
@ -941,6 +941,33 @@ bool test_30() {
|
||||||
state = state && success;
|
state = state && success;
|
||||||
OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_31() {
|
||||||
|
bool state = true;
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
String a = "";
|
||||||
|
success = a[0] == 0;
|
||||||
|
OS::get_singleton()->print("Is 0 String[0]:, %s\n", success ? "OK" : "FAIL");
|
||||||
|
if (!success) state = false;
|
||||||
|
|
||||||
|
String b = "Godot";
|
||||||
|
success = b[b.size()] == 0;
|
||||||
|
OS::get_singleton()->print("Is 0 String[size()]:, %s\n", success ? "OK" : "FAIL");
|
||||||
|
if (!success) state = false;
|
||||||
|
|
||||||
|
const String c = "";
|
||||||
|
success = c[0] == 0;
|
||||||
|
OS::get_singleton()->print("Is 0 const String[0]:, %s\n", success ? "OK" : "FAIL");
|
||||||
|
if (!success) state = false;
|
||||||
|
|
||||||
|
const String d = "Godot";
|
||||||
|
success = d[d.size()] == 0;
|
||||||
|
OS::get_singleton()->print("Is 0 const String[size()]:, %s\n", success ? "OK" : "FAIL");
|
||||||
|
if (!success) state = false;
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -978,6 +1005,7 @@ TestFunc test_funcs[] = {
|
||||||
test_28,
|
test_28,
|
||||||
test_29,
|
test_29,
|
||||||
test_30,
|
test_30,
|
||||||
|
test_31,
|
||||||
0
|
0
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue