diff options
Diffstat (limited to 'core/variant')
-rw-r--r-- | core/variant/array.cpp | 96 | ||||
-rw-r--r-- | core/variant/container_type_validate.h | 23 | ||||
-rw-r--r-- | core/variant/dictionary.cpp | 56 | ||||
-rw-r--r-- | core/variant/variant.cpp | 15 | ||||
-rw-r--r-- | core/variant/variant.h | 4 | ||||
-rw-r--r-- | core/variant/variant_call.cpp | 341 | ||||
-rw-r--r-- | core/variant/variant_op.cpp | 117 | ||||
-rw-r--r-- | core/variant/variant_op.h | 89 | ||||
-rw-r--r-- | core/variant/variant_parser.cpp | 73 | ||||
-rw-r--r-- | core/variant/variant_parser.h | 32 |
10 files changed, 558 insertions, 288 deletions
diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 6c4e8ba450..53891a9823 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -38,6 +38,7 @@ #include "core/templates/search_array.h" #include "core/templates/vector.h" #include "core/variant/callable.h" +#include "core/variant/dictionary.h" #include "core/variant/variant.h" class ArrayPrivate { @@ -201,16 +202,21 @@ uint32_t Array::recursive_hash(int recursion_count) const { } bool Array::_assign(const Array &p_array) { + bool can_convert = p_array._p->typed.type == Variant::NIL; + can_convert |= _p->typed.type == Variant::STRING && p_array._p->typed.type == Variant::STRING_NAME; + can_convert |= _p->typed.type == Variant::STRING_NAME && p_array._p->typed.type == Variant::STRING; + if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) { //same type or untyped, just reference, should be fine _ref(p_array); } else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway _p->array = p_array._p->array; - } else if (p_array._p->typed.type == Variant::NIL) { //from untyped to typed, must try to check if they are all valid + } else if (can_convert) { //from untyped to typed, must try to check if they are all valid if (_p->typed.type == Variant::OBJECT) { //for objects, it needs full validation, either can be converted or fail for (int i = 0; i < p_array._p->array.size(); i++) { - if (!_p->typed.validate(p_array._p->array[i], "assign")) { + const Variant &element = p_array._p->array[i]; + if (element.get_type() != Variant::OBJECT || !_p->typed.validate_object(element, "assign")) { return false; } } @@ -255,16 +261,20 @@ void Array::operator=(const Array &p_array) { void Array::push_back(const Variant &p_value) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - ERR_FAIL_COND(!_p->typed.validate(p_value, "push_back")); - _p->array.push_back(p_value); + Variant value = p_value; + ERR_FAIL_COND(!_p->typed.validate(value, "push_back")); + _p->array.push_back(value); } void Array::append_array(const Array &p_array) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - for (int i = 0; i < p_array.size(); ++i) { - ERR_FAIL_COND(!_p->typed.validate(p_array[i], "append_array")); + + Vector<Variant> validated_array = p_array._p->array; + for (int i = 0; i < validated_array.size(); ++i) { + ERR_FAIL_COND(!_p->typed.validate(validated_array.write[i], "append_array")); } - _p->array.append_array(p_array._p->array); + + _p->array.append_array(validated_array); } Error Array::resize(int p_new_size) { @@ -274,20 +284,23 @@ Error Array::resize(int p_new_size) { Error Array::insert(int p_pos, const Variant &p_value) { ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state."); - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "insert"), ERR_INVALID_PARAMETER); - return _p->array.insert(p_pos, p_value); + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "insert"), ERR_INVALID_PARAMETER); + return _p->array.insert(p_pos, value); } void Array::fill(const Variant &p_value) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - ERR_FAIL_COND(!_p->typed.validate(p_value, "fill")); - _p->array.fill(p_value); + Variant value = p_value; + ERR_FAIL_COND(!_p->typed.validate(value, "fill")); + _p->array.fill(value); } void Array::erase(const Variant &p_value) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - ERR_FAIL_COND(!_p->typed.validate(p_value, "erase")); - _p->array.erase(p_value); + Variant value = p_value; + ERR_FAIL_COND(!_p->typed.validate(value, "erase")); + _p->array.erase(value); } Variant Array::front() const { @@ -306,15 +319,34 @@ Variant Array::pick_random() const { } int Array::find(const Variant &p_value, int p_from) const { - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1); - return _p->array.find(p_value, p_from); + if (_p->array.size() == 0) { + return -1; + } + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "find"), -1); + + int ret = -1; + + if (p_from < 0 || size() == 0) { + return ret; + } + + for (int i = p_from; i < size(); i++) { + if (StringLikeVariantComparator::compare(_p->array[i], value)) { + ret = i; + break; + } + } + + return ret; } int Array::rfind(const Variant &p_value, int p_from) const { if (_p->array.size() == 0) { return -1; } - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "rfind"), -1); + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "rfind"), -1); if (p_from < 0) { // Relative offset from the end @@ -326,7 +358,7 @@ int Array::rfind(const Variant &p_value, int p_from) const { } for (int i = p_from; i >= 0; i--) { - if (_p->array[i] == p_value) { + if (StringLikeVariantComparator::compare(_p->array[i], value)) { return i; } } @@ -335,14 +367,15 @@ int Array::rfind(const Variant &p_value, int p_from) const { } int Array::count(const Variant &p_value) const { - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "count"), 0); + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0); if (_p->array.size() == 0) { return 0; } int amount = 0; for (int i = 0; i < _p->array.size(); i++) { - if (_p->array[i] == p_value) { + if (StringLikeVariantComparator::compare(_p->array[i], value)) { amount++; } } @@ -351,9 +384,10 @@ int Array::count(const Variant &p_value) const { } bool Array::has(const Variant &p_value) const { - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "use 'has'"), false); + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "use 'has'"), false); - return _p->array.find(p_value, 0) != -1; + return find(value) != -1; } void Array::remove_at(int p_pos) { @@ -363,9 +397,10 @@ void Array::remove_at(int p_pos) { void Array::set(int p_idx, const Variant &p_value) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - ERR_FAIL_COND(!_p->typed.validate(p_value, "set")); + Variant value = p_value; + ERR_FAIL_COND(!_p->typed.validate(value, "set")); - operator[](p_idx) = p_value; + operator[](p_idx) = value; } const Variant &Array::get(int p_idx) const { @@ -588,15 +623,17 @@ void Array::shuffle() { } int Array::bsearch(const Variant &p_value, bool p_before) { - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "binary search"), -1); + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "binary search"), -1); SearchArray<Variant, _ArrayVariantSort> avs; - return avs.bisect(_p->array.ptrw(), _p->array.size(), p_value, p_before); + return avs.bisect(_p->array.ptrw(), _p->array.size(), value, p_before); } int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) { - ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1); + Variant value = p_value; + ERR_FAIL_COND_V(!_p->typed.validate(value, "custom binary search"), -1); - return _p->array.bsearch_custom<CallableComparator>(p_value, p_before, p_callable); + return _p->array.bsearch_custom<CallableComparator>(value, p_before, p_callable); } void Array::reverse() { @@ -606,8 +643,9 @@ void Array::reverse() { void Array::push_front(const Variant &p_value) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - ERR_FAIL_COND(!_p->typed.validate(p_value, "push_front")); - _p->array.insert(0, p_value); + Variant value = p_value; + ERR_FAIL_COND(!_p->typed.validate(value, "push_front")); + _p->array.insert(0, value); } Variant Array::pop_back() { diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h index 427a337aab..9976fce47f 100644 --- a/core/variant/container_type_validate.h +++ b/core/variant/container_type_validate.h @@ -74,22 +74,37 @@ struct ContainerTypeValidate { return true; } - _FORCE_INLINE_ bool validate(const Variant &p_variant, const char *p_operation = "use") { + // Coerces String and StringName into each other when needed. + _FORCE_INLINE_ bool validate(Variant &inout_variant, const char *p_operation = "use") { if (type == Variant::NIL) { return true; } - if (type != p_variant.get_type()) { - if (p_variant.get_type() == Variant::NIL && type == Variant::OBJECT) { + if (type != inout_variant.get_type()) { + if (inout_variant.get_type() == Variant::NIL && type == Variant::OBJECT) { + return true; + } + if (type == Variant::STRING && inout_variant.get_type() == Variant::STRING_NAME) { + inout_variant = String(inout_variant); + return true; + } else if (type == Variant::STRING_NAME && inout_variant.get_type() == Variant::STRING) { + inout_variant = StringName(inout_variant); return true; } - ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'."); + ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(inout_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'."); } if (type != Variant::OBJECT) { return true; } + + return validate_object(inout_variant, p_operation); + } + + _FORCE_INLINE_ bool validate_object(const Variant &p_variant, const char *p_operation = "use") { + ERR_FAIL_COND_V(p_variant.get_type() != Variant::OBJECT, false); + #ifdef DEBUG_ENABLED ObjectID object_id = p_variant; if (object_id == ObjectID()) { diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index c1cb782a57..77d9fb0bc2 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -42,7 +42,7 @@ struct DictionaryPrivate { 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, StringLikeVariantComparator> variant_map; }; void Dictionary::get_key_list(List<Variant> *p_keys) const { @@ -100,24 +100,12 @@ Variant &Dictionary::operator[](const Variant &p_key) { } const Variant &Dictionary::operator[](const Variant &p_key) const { - 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]; - } + // Will not insert key, so no conversion is necessary. + return _p->variant_map[p_key]; } const Variant *Dictionary::getptr(const Variant &p_key) const { - HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E; - - if (p_key.get_type() == Variant::STRING_NAME) { - const StringName *sn = VariantInternal::get_string_name(&p_key); - E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); - } else { - E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); - } - + HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(p_key)); if (!E) { return nullptr; } @@ -125,14 +113,7 @@ const Variant *Dictionary::getptr(const Variant &p_key) const { } Variant *Dictionary::getptr(const Variant &p_key) { - HashMap<Variant, Variant, VariantHasher, VariantComparator>::Iterator E; - - if (p_key.get_type() == Variant::STRING_NAME) { - const StringName *sn = VariantInternal::get_string_name(&p_key); - E = ((HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); - } else { - E = ((HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); - } + HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E(_p->variant_map.find(p_key)); if (!E) { return nullptr; } @@ -145,14 +126,7 @@ Variant *Dictionary::getptr(const Variant &p_key) { } Variant Dictionary::get_valid(const Variant &p_key) const { - HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E; - - if (p_key.get_type() == Variant::STRING_NAME) { - const StringName *sn = VariantInternal::get_string_name(&p_key); - E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); - } else { - E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); - } + HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(p_key)); if (!E) { return Variant(); @@ -178,12 +152,7 @@ bool Dictionary::is_empty() const { } bool Dictionary::has(const Variant &p_key) const { - if (p_key.get_type() == Variant::STRING_NAME) { - const StringName *sn = VariantInternal::get_string_name(&p_key); - return _p->variant_map.has(sn->operator String()); - } else { - return _p->variant_map.has(p_key); - } + return _p->variant_map.has(p_key); } bool Dictionary::has_all(const Array &p_keys) const { @@ -206,12 +175,7 @@ Variant Dictionary::find_key(const Variant &p_value) const { 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) { - const StringName *sn = VariantInternal::get_string_name(&p_key); - return _p->variant_map.erase(sn->operator String()); - } else { - return _p->variant_map.erase(p_key); - } + return _p->variant_map.erase(p_key); } bool Dictionary::operator==(const Dictionary &p_dictionary) const { @@ -238,7 +202,7 @@ bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_c } recursion_count++; for (const KeyValue<Variant, Variant> &this_E : _p->variant_map) { - HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator other_E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&p_dictionary._p->variant_map)->find(this_E.key); + HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator other_E(p_dictionary._p->variant_map.find(this_E.key)); if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count)) { return false; } @@ -360,7 +324,7 @@ const Variant *Dictionary::next(const Variant *p_key) const { } return nullptr; } - HashMap<Variant, Variant, VariantHasher, VariantComparator>::Iterator E = _p->variant_map.find(*p_key); + HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E = _p->variant_map.find(*p_key); if (!E) { return nullptr; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index c1166a0a14..39b7cbee0d 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -940,7 +940,7 @@ bool Variant::is_zero() const { return reinterpret_cast<const Signal *>(_data._mem)->is_null(); } case STRING_NAME: { - return *reinterpret_cast<const StringName *>(_data._mem) != StringName(); + return *reinterpret_cast<const StringName *>(_data._mem) == StringName(); } case NODE_PATH: { return reinterpret_cast<const NodePath *>(_data._mem)->is_empty(); @@ -3491,6 +3491,19 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const } } +bool StringLikeVariantComparator::compare(const Variant &p_lhs, const Variant &p_rhs) { + if (p_lhs.hash_compare(p_rhs)) { + return true; + } + if (p_lhs.get_type() == Variant::STRING && p_rhs.get_type() == Variant::STRING_NAME) { + return *VariantInternal::get_string(&p_lhs) == *VariantInternal::get_string_name(&p_rhs); + } + if (p_lhs.get_type() == Variant::STRING_NAME && p_rhs.get_type() == Variant::STRING) { + return *VariantInternal::get_string_name(&p_lhs) == *VariantInternal::get_string(&p_rhs); + } + return false; +} + bool Variant::is_ref_counted() const { return type == OBJECT && _get_obj().id.is_ref_counted(); } diff --git a/core/variant/variant.h b/core/variant/variant.h index c5be609184..f7221e206f 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -797,6 +797,10 @@ struct VariantComparator { static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); } }; +struct StringLikeVariantComparator { + static bool compare(const Variant &p_lhs, const Variant &p_rhs); +}; + Variant::ObjData &Variant::_get_obj() { return *reinterpret_cast<ObjData *>(&_data._mem[0]); } diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 2cb80dcab4..ac569941bf 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -73,6 +73,30 @@ static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals); } +template <class From, class R, class T, class... P> +static _FORCE_INLINE_ void vc_convert_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_variant_args_ret_dv(&converted, method, p_args, p_argcount, r_ret, r_error, p_defvals); +} + +template <class From, class R, class T, class... P> +static _FORCE_INLINE_ void vc_convert_method_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_variant_args_retc_dv(&converted, method, p_args, p_argcount, r_ret, r_error, p_defvals); +} + +template <class From, class T, class... P> +static _FORCE_INLINE_ void vc_convert_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_variant_args_dv(&converted, method, p_args, p_argcount, r_error, p_defvals); +} + +template <class From, class T, class... P> +static _FORCE_INLINE_ void vc_convert_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_variant_argsc_dv(&converted, method, p_args, p_argcount, r_error, p_defvals); +} + template <class R, class T, class... P> static _FORCE_INLINE_ void vc_method_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, p_defvals, r_error); @@ -102,6 +126,29 @@ static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Vari call_with_validated_variant_argsc(base, method, p_args); } +template <class From, class R, class T, class... P> +static _FORCE_INLINE_ void vc_convert_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_validated_variant_args_ret_helper<T, R, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); +} + +template <class From, class R, class T, class... P> +static _FORCE_INLINE_ void vc_convert_validated_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_validated_variant_args_retc_helper<T, R, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); +} +template <class From, class T, class... P> +static _FORCE_INLINE_ void vc_convert_validated_call(void (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_validated_variant_args_helper<T, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); +} + +template <class From, class T, class... P> +static _FORCE_INLINE_ void vc_convert_validated_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) { + T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base))); + call_with_validated_variant_argsc_helper<T, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); +} + template <class R, class T, class... P> static _FORCE_INLINE_ void vc_validated_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) { call_with_validated_variant_args_static_retc(base, method, p_args, r_ret); @@ -142,6 +189,30 @@ static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_bas call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args); } +template <class From, class R, class T, class... P> +static _FORCE_INLINE_ void vc_convert_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) { + T converted(*reinterpret_cast<From *>(p_base)); + call_with_ptr_args_ret(&converted, method, p_args, r_ret); +} + +template <class From, class R, class T, class... P> +static _FORCE_INLINE_ void vc_convert_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) { + T converted(*reinterpret_cast<From *>(p_base)); + call_with_ptr_args_retc(&converted, method, p_args, r_ret); +} + +template <class From, class T, class... P> +static _FORCE_INLINE_ void vc_convert_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) { + T converted(*reinterpret_cast<From *>(p_base)); + call_with_ptr_args(&converted, method, p_args); +} + +template <class From, class T, class... P> +static _FORCE_INLINE_ void vc_convert_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) { + T converted(*reinterpret_cast<From *>(p_base)); + call_with_ptr_argsc(&converted, method, p_args); +} + template <class R, class T, class... P> static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...)) { return sizeof...(P); @@ -337,6 +408,46 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con } \ }; +#define CONVERT_METHOD_CLASS(m_class, m_method_name, m_method_ptr) \ + struct Method_##m_class##_##m_method_name { \ + static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \ + vc_convert_method_call<m_class>(m_method_ptr, base, p_args, p_argcount, r_ret, p_defvals, r_error); \ + } \ + static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \ + vc_convert_validated_call<m_class>(m_method_ptr, base, p_args, r_ret); \ + } \ + static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \ + vc_convert_ptrcall<m_class>(m_method_ptr, p_base, p_args, r_ret); \ + } \ + static int get_argument_count() { \ + return vc_get_argument_count(m_method_ptr); \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return vc_get_argument_type(m_method_ptr, p_arg); \ + } \ + static Variant::Type get_return_type() { \ + return vc_get_return_type(m_method_ptr); \ + } \ + static bool has_return_type() { \ + return vc_has_return_type(m_method_ptr); \ + } \ + static bool is_const() { \ + return vc_is_const(m_method_ptr); \ + } \ + static bool is_static() { \ + return false; \ + } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::Type get_base_type() { \ + return GetTypeInfo<m_class>::VARIANT_TYPE; \ + } \ + static StringName get_name() { \ + return #m_method_name; \ + } \ + }; + template <class R, class... P> static _FORCE_INLINE_ void vc_static_ptrcall(R (*method)(P...), const void **p_args, void *r_ret) { call_with_ptr_args_static_method_ret<R, P...>(method, p_args, r_ret); @@ -1422,6 +1533,16 @@ int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, String #endif #ifdef DEBUG_METHODS_ENABLED +#define bind_convert_method(m_type_from, m_type_to, m_method, m_arg_names, m_default_args) \ + CONVERT_METHOD_CLASS(m_type_from, m_method, &m_type_to::m_method); \ + register_builtin_method<Method_##m_type_from##_##m_method>(m_arg_names, m_default_args); +#else +#define bind_convert_method(m_type_from, m_type_to, m_method, m_arg_names, m_default_args) \ + CONVERT_METHOD_CLASS(m_type_from, m_method, &m_type_to ::m_method); \ + register_builtin_method<Method_##m_type_from##_##m_method>(sarray(), m_default_args); +#endif + +#ifdef DEBUG_METHODS_ENABLED #define bind_static_method(m_type, m_method, m_arg_names, m_default_args) \ STATIC_METHOD_CLASS(m_type, m_method, m_type::m_method); \ register_builtin_method<Method_##m_type##_##m_method>(m_arg_names, m_default_args); @@ -1442,6 +1563,16 @@ int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, String #endif #ifdef DEBUG_METHODS_ENABLED +#define bind_convert_methodv(m_type_from, m_type_to, m_name, m_method, m_arg_names, m_default_args) \ + CONVERT_METHOD_CLASS(m_type_from, m_name, m_method); \ + register_builtin_method<Method_##m_type_from##_##m_name>(m_arg_names, m_default_args); +#else +#define bind_convert_methodv(m_type_from, m_type_to, m_name, m_method, m_arg_names, m_default_args) \ + CONVERT_METHOD_CLASS(m_type_from, m_name, m_method); \ + register_builtin_method<Method_##m_type_from##_##m_name>(sarray(), m_default_args); +#endif + +#ifdef DEBUG_METHODS_ENABLED #define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \ FUNCTION_CLASS(m_type, m_name, m_method, true); \ register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args); @@ -1461,6 +1592,14 @@ int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, String register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args); #endif +#define bind_string_method(m_method, m_arg_names, m_default_args) \ + bind_method(String, m_method, m_arg_names, m_default_args); \ + bind_convert_method(StringName, String, m_method, m_arg_names, m_default_args); + +#define bind_string_methodv(m_name, m_method, m_arg_names, m_default_args) \ + bind_methodv(String, m_name, m_method, m_arg_names, m_default_args); \ + bind_convert_methodv(StringName, String, m_name, m_method, m_arg_names, m_default_args); + #define bind_custom(m_type, m_name, m_method, m_has_return, m_ret_type) \ VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \ register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>()); @@ -1477,108 +1616,108 @@ static void _register_variant_builtin_methods() { /* String */ - bind_method(String, casecmp_to, sarray("to"), varray()); - bind_method(String, nocasecmp_to, sarray("to"), varray()); - bind_method(String, naturalnocasecmp_to, sarray("to"), varray()); - bind_method(String, length, sarray(), varray()); - bind_method(String, substr, sarray("from", "len"), varray(-1)); - bind_method(String, get_slice, sarray("delimiter", "slice"), varray()); - bind_method(String, get_slicec, sarray("delimiter", "slice"), varray()); - bind_method(String, get_slice_count, sarray("delimiter"), varray()); - bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0)); - bind_method(String, count, sarray("what", "from", "to"), varray(0, 0)); - bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0)); - bind_method(String, findn, sarray("what", "from"), varray(0)); - bind_method(String, rfind, sarray("what", "from"), varray(-1)); - bind_method(String, rfindn, sarray("what", "from"), varray(-1)); - bind_method(String, match, sarray("expr"), varray()); - bind_method(String, matchn, sarray("expr"), varray()); - bind_methodv(String, begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray()); - bind_method(String, ends_with, sarray("text"), varray()); - bind_method(String, is_subsequence_of, sarray("text"), varray()); - bind_method(String, is_subsequence_ofn, sarray("text"), varray()); - bind_method(String, bigrams, sarray(), varray()); - bind_method(String, similarity, sarray("text"), varray()); - - bind_method(String, format, sarray("values", "placeholder"), varray("{_}")); - bind_methodv(String, replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray()); - bind_method(String, replacen, sarray("what", "forwhat"), varray()); - bind_method(String, repeat, sarray("count"), varray()); - bind_method(String, insert, sarray("position", "what"), varray()); - bind_method(String, capitalize, sarray(), varray()); - bind_method(String, to_camel_case, sarray(), varray()); - bind_method(String, to_pascal_case, sarray(), varray()); - bind_method(String, to_snake_case, sarray(), varray()); - bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); - bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); - bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true)); - bind_method(String, join, sarray("parts"), varray()); - - bind_method(String, to_upper, sarray(), varray()); - bind_method(String, to_lower, sarray(), varray()); - - bind_method(String, left, sarray("length"), varray()); - bind_method(String, right, sarray("length"), varray()); - - bind_method(String, strip_edges, sarray("left", "right"), varray(true, true)); - bind_method(String, strip_escapes, sarray(), varray()); - bind_method(String, lstrip, sarray("chars"), varray()); - bind_method(String, rstrip, sarray("chars"), varray()); - bind_method(String, get_extension, sarray(), varray()); - bind_method(String, get_basename, sarray(), varray()); - bind_method(String, path_join, sarray("file"), varray()); - bind_method(String, unicode_at, sarray("at"), varray()); - bind_method(String, indent, sarray("prefix"), varray()); - bind_method(String, dedent, sarray(), varray()); + bind_string_method(casecmp_to, sarray("to"), varray()); + bind_string_method(nocasecmp_to, sarray("to"), varray()); + bind_string_method(naturalnocasecmp_to, sarray("to"), varray()); + bind_string_method(length, sarray(), varray()); + bind_string_method(substr, sarray("from", "len"), varray(-1)); + bind_string_method(get_slice, sarray("delimiter", "slice"), varray()); + bind_string_method(get_slicec, sarray("delimiter", "slice"), varray()); + bind_string_method(get_slice_count, sarray("delimiter"), varray()); + bind_string_methodv(find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0)); + bind_string_method(count, sarray("what", "from", "to"), varray(0, 0)); + bind_string_method(countn, sarray("what", "from", "to"), varray(0, 0)); + bind_string_method(findn, sarray("what", "from"), varray(0)); + bind_string_method(rfind, sarray("what", "from"), varray(-1)); + bind_string_method(rfindn, sarray("what", "from"), varray(-1)); + bind_string_method(match, sarray("expr"), varray()); + bind_string_method(matchn, sarray("expr"), varray()); + bind_string_methodv(begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray()); + bind_string_method(ends_with, sarray("text"), varray()); + bind_string_method(is_subsequence_of, sarray("text"), varray()); + bind_string_method(is_subsequence_ofn, sarray("text"), varray()); + bind_string_method(bigrams, sarray(), varray()); + bind_string_method(similarity, sarray("text"), varray()); + + bind_string_method(format, sarray("values", "placeholder"), varray("{_}")); + bind_string_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray()); + bind_string_method(replacen, sarray("what", "forwhat"), varray()); + bind_string_method(repeat, sarray("count"), varray()); + bind_string_method(insert, sarray("position", "what"), varray()); + bind_string_method(capitalize, sarray(), varray()); + bind_string_method(to_camel_case, sarray(), varray()); + bind_string_method(to_pascal_case, sarray(), varray()); + bind_string_method(to_snake_case, sarray(), varray()); + bind_string_method(split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); + bind_string_method(rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); + bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true)); + bind_string_method(join, sarray("parts"), varray()); + + bind_string_method(to_upper, sarray(), varray()); + bind_string_method(to_lower, sarray(), varray()); + + bind_string_method(left, sarray("length"), varray()); + bind_string_method(right, sarray("length"), varray()); + + bind_string_method(strip_edges, sarray("left", "right"), varray(true, true)); + bind_string_method(strip_escapes, sarray(), varray()); + bind_string_method(lstrip, sarray("chars"), varray()); + bind_string_method(rstrip, sarray("chars"), varray()); + bind_string_method(get_extension, sarray(), varray()); + bind_string_method(get_basename, sarray(), varray()); + bind_string_method(path_join, sarray("file"), varray()); + bind_string_method(unicode_at, sarray("at"), varray()); + bind_string_method(indent, sarray("prefix"), varray()); + bind_string_method(dedent, sarray(), varray()); bind_method(String, hash, sarray(), varray()); - bind_method(String, md5_text, sarray(), varray()); - bind_method(String, sha1_text, sarray(), varray()); - bind_method(String, sha256_text, sarray(), varray()); - bind_method(String, md5_buffer, sarray(), varray()); - bind_method(String, sha1_buffer, sarray(), varray()); - bind_method(String, sha256_buffer, sarray(), varray()); - bind_method(String, is_empty, sarray(), varray()); - bind_methodv(String, contains, static_cast<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray()); - - bind_method(String, is_absolute_path, sarray(), varray()); - bind_method(String, is_relative_path, sarray(), varray()); - bind_method(String, simplify_path, sarray(), varray()); - bind_method(String, get_base_dir, sarray(), varray()); - bind_method(String, get_file, sarray(), varray()); - bind_method(String, xml_escape, sarray("escape_quotes"), varray(false)); - bind_method(String, xml_unescape, sarray(), varray()); - bind_method(String, uri_encode, sarray(), varray()); - bind_method(String, uri_decode, sarray(), varray()); - bind_method(String, c_escape, sarray(), varray()); - bind_method(String, c_unescape, sarray(), varray()); - bind_method(String, json_escape, sarray(), varray()); - - bind_method(String, validate_node_name, sarray(), varray()); - - bind_method(String, is_valid_identifier, sarray(), varray()); - bind_method(String, is_valid_int, sarray(), varray()); - bind_method(String, is_valid_float, sarray(), varray()); - bind_method(String, is_valid_hex_number, sarray("with_prefix"), varray(false)); - bind_method(String, is_valid_html_color, sarray(), varray()); - bind_method(String, is_valid_ip_address, sarray(), varray()); - bind_method(String, is_valid_filename, sarray(), varray()); - - bind_method(String, to_int, sarray(), varray()); - bind_method(String, to_float, sarray(), varray()); - bind_method(String, hex_to_int, sarray(), varray()); - bind_method(String, bin_to_int, sarray(), varray()); - - bind_method(String, lpad, sarray("min_length", "character"), varray(" ")); - bind_method(String, rpad, sarray("min_length", "character"), varray(" ")); - bind_method(String, pad_decimals, sarray("digits"), varray()); - bind_method(String, pad_zeros, sarray("digits"), varray()); - bind_method(String, trim_prefix, sarray("prefix"), varray()); - bind_method(String, trim_suffix, sarray("suffix"), varray()); - - bind_method(String, to_ascii_buffer, sarray(), varray()); - bind_method(String, to_utf8_buffer, sarray(), varray()); - bind_method(String, to_utf16_buffer, sarray(), varray()); - bind_method(String, to_utf32_buffer, sarray(), varray()); + bind_string_method(md5_text, sarray(), varray()); + bind_string_method(sha1_text, sarray(), varray()); + bind_string_method(sha256_text, sarray(), varray()); + bind_string_method(md5_buffer, sarray(), varray()); + bind_string_method(sha1_buffer, sarray(), varray()); + bind_string_method(sha256_buffer, sarray(), varray()); + bind_string_method(is_empty, sarray(), varray()); + bind_string_methodv(contains, static_cast<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray()); + + bind_string_method(is_absolute_path, sarray(), varray()); + bind_string_method(is_relative_path, sarray(), varray()); + bind_string_method(simplify_path, sarray(), varray()); + bind_string_method(get_base_dir, sarray(), varray()); + bind_string_method(get_file, sarray(), varray()); + bind_string_method(xml_escape, sarray("escape_quotes"), varray(false)); + bind_string_method(xml_unescape, sarray(), varray()); + bind_string_method(uri_encode, sarray(), varray()); + bind_string_method(uri_decode, sarray(), varray()); + bind_string_method(c_escape, sarray(), varray()); + bind_string_method(c_unescape, sarray(), varray()); + bind_string_method(json_escape, sarray(), varray()); + + bind_string_method(validate_node_name, sarray(), varray()); + + bind_string_method(is_valid_identifier, sarray(), varray()); + bind_string_method(is_valid_int, sarray(), varray()); + bind_string_method(is_valid_float, sarray(), varray()); + bind_string_method(is_valid_hex_number, sarray("with_prefix"), varray(false)); + bind_string_method(is_valid_html_color, sarray(), varray()); + bind_string_method(is_valid_ip_address, sarray(), varray()); + bind_string_method(is_valid_filename, sarray(), varray()); + + bind_string_method(to_int, sarray(), varray()); + bind_string_method(to_float, sarray(), varray()); + bind_string_method(hex_to_int, sarray(), varray()); + bind_string_method(bin_to_int, sarray(), varray()); + + bind_string_method(lpad, sarray("min_length", "character"), varray(" ")); + bind_string_method(rpad, sarray("min_length", "character"), varray(" ")); + bind_string_method(pad_decimals, sarray("digits"), varray()); + bind_string_method(pad_zeros, sarray("digits"), varray()); + bind_string_method(trim_prefix, sarray("prefix"), varray()); + bind_string_method(trim_suffix, sarray("suffix"), varray()); + + bind_string_method(to_ascii_buffer, sarray(), varray()); + bind_string_method(to_utf8_buffer, sarray(), varray()); + bind_string_method(to_utf16_buffer, sarray(), varray()); + bind_string_method(to_utf32_buffer, sarray(), varray()); bind_static_method(String, num_scientific, sarray("number"), varray()); bind_static_method(String, num, sarray("number", "decimals"), varray(-1)); diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 25bc241e9b..d4e6dfb4d1 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -229,6 +229,20 @@ public: static Variant::Type get_return_type() { return GetTypeInfo<Vector4>::VARIANT_TYPE; } }; +#define register_string_op(m_op_type, m_op_code) \ + do { \ + register_op<m_op_type<String, String>>(m_op_code, Variant::STRING, Variant::STRING); \ + register_op<m_op_type<String, StringName>>(m_op_code, Variant::STRING, Variant::STRING_NAME); \ + register_op<m_op_type<StringName, String>>(m_op_code, Variant::STRING_NAME, Variant::STRING); \ + register_op<m_op_type<StringName, StringName>>(m_op_code, Variant::STRING_NAME, Variant::STRING_NAME); \ + } while (false) + +#define register_string_modulo_op(m_class, m_type) \ + do { \ + register_op<OperatorEvaluatorStringFormat<String, m_class>>(Variant::OP_MODULE, Variant::STRING, m_type); \ + register_op<OperatorEvaluatorStringFormat<StringName, m_class>>(Variant::OP_MODULE, Variant::STRING_NAME, m_type); \ + } while (false) + void Variant::_register_variant_operators() { memset(operator_return_type_table, 0, sizeof(operator_return_type_table)); memset(operator_evaluator_table, 0, sizeof(operator_evaluator_table)); @@ -239,7 +253,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorAdd<double, int64_t, double>>(Variant::OP_ADD, Variant::INT, Variant::FLOAT); register_op<OperatorEvaluatorAdd<double, double, int64_t>>(Variant::OP_ADD, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT); - register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING); + register_string_op(OperatorEvaluatorStringConcat, Variant::OP_ADD); register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3); @@ -415,46 +429,46 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorModNZ<Vector4i, Vector4i, Vector4i>>(Variant::OP_MODULE, Variant::VECTOR4I, Variant::VECTOR4I); register_op<OperatorEvaluatorModNZ<Vector4i, Vector4i, int64_t>>(Variant::OP_MODULE, Variant::VECTOR4I, Variant::INT); - register_op<OperatorEvaluatorStringModNil>(Variant::OP_MODULE, Variant::STRING, Variant::NIL); - - register_op<OperatorEvaluatorStringModT<bool>>(Variant::OP_MODULE, Variant::STRING, Variant::BOOL); - register_op<OperatorEvaluatorStringModT<int64_t>>(Variant::OP_MODULE, Variant::STRING, Variant::INT); - register_op<OperatorEvaluatorStringModT<double>>(Variant::OP_MODULE, Variant::STRING, Variant::FLOAT); - register_op<OperatorEvaluatorStringModT<String>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING); - register_op<OperatorEvaluatorStringModT<Vector2>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2); - register_op<OperatorEvaluatorStringModT<Vector2i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2I); - register_op<OperatorEvaluatorStringModT<Rect2>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2); - register_op<OperatorEvaluatorStringModT<Rect2i>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2I); - register_op<OperatorEvaluatorStringModT<Vector3>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3); - register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I); - register_op<OperatorEvaluatorStringModT<Vector4>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR4); - register_op<OperatorEvaluatorStringModT<Vector4i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR4I); - register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D); - register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE); - register_op<OperatorEvaluatorStringModT<Quaternion>>(Variant::OP_MODULE, Variant::STRING, Variant::QUATERNION); - register_op<OperatorEvaluatorStringModT<::AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB); - register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS); - register_op<OperatorEvaluatorStringModT<Transform3D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM3D); - register_op<OperatorEvaluatorStringModT<Projection>>(Variant::OP_MODULE, Variant::STRING, Variant::PROJECTION); - - register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR); - register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME); - register_op<OperatorEvaluatorStringModT<NodePath>>(Variant::OP_MODULE, Variant::STRING, Variant::NODE_PATH); - register_op<OperatorEvaluatorStringModObject>(Variant::OP_MODULE, Variant::STRING, Variant::OBJECT); - register_op<OperatorEvaluatorStringModT<Callable>>(Variant::OP_MODULE, Variant::STRING, Variant::CALLABLE); - register_op<OperatorEvaluatorStringModT<Signal>>(Variant::OP_MODULE, Variant::STRING, Variant::SIGNAL); - register_op<OperatorEvaluatorStringModT<Dictionary>>(Variant::OP_MODULE, Variant::STRING, Variant::DICTIONARY); - register_op<OperatorEvaluatorStringModArray>(Variant::OP_MODULE, Variant::STRING, Variant::ARRAY); - - register_op<OperatorEvaluatorStringModT<PackedByteArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_BYTE_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedInt32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT32_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedInt64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT64_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedFloat32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT32_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedFloat64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT64_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedStringArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_STRING_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedVector2Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR2_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedVector3Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR3_ARRAY); - register_op<OperatorEvaluatorStringModT<PackedColorArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_COLOR_ARRAY); + register_string_modulo_op(void, Variant::NIL); + + register_string_modulo_op(bool, Variant::BOOL); + register_string_modulo_op(int64_t, Variant::INT); + register_string_modulo_op(double, Variant::FLOAT); + register_string_modulo_op(String, Variant::STRING); + register_string_modulo_op(Vector2, Variant::VECTOR2); + register_string_modulo_op(Vector2i, Variant::VECTOR2I); + register_string_modulo_op(Rect2, Variant::RECT2); + register_string_modulo_op(Rect2i, Variant::RECT2I); + register_string_modulo_op(Vector3, Variant::VECTOR3); + register_string_modulo_op(Vector3i, Variant::VECTOR3I); + register_string_modulo_op(Vector4, Variant::VECTOR4); + register_string_modulo_op(Vector4i, Variant::VECTOR4I); + register_string_modulo_op(Transform2D, Variant::TRANSFORM2D); + register_string_modulo_op(Plane, Variant::PLANE); + register_string_modulo_op(Quaternion, Variant::QUATERNION); + register_string_modulo_op(::AABB, Variant::AABB); + register_string_modulo_op(Basis, Variant::BASIS); + register_string_modulo_op(Transform3D, Variant::TRANSFORM3D); + register_string_modulo_op(Projection, Variant::PROJECTION); + + register_string_modulo_op(Color, Variant::COLOR); + register_string_modulo_op(StringName, Variant::STRING_NAME); + register_string_modulo_op(NodePath, Variant::NODE_PATH); + register_string_modulo_op(Object, Variant::OBJECT); + register_string_modulo_op(Callable, Variant::CALLABLE); + register_string_modulo_op(Signal, Variant::SIGNAL); + register_string_modulo_op(Dictionary, Variant::DICTIONARY); + register_string_modulo_op(Array, Variant::ARRAY); + + register_string_modulo_op(PackedByteArray, Variant::PACKED_BYTE_ARRAY); + register_string_modulo_op(PackedInt32Array, Variant::PACKED_INT32_ARRAY); + register_string_modulo_op(PackedInt64Array, Variant::PACKED_INT64_ARRAY); + register_string_modulo_op(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY); + register_string_modulo_op(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY); + register_string_modulo_op(PackedStringArray, Variant::PACKED_STRING_ARRAY); + register_string_modulo_op(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY); + register_string_modulo_op(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY); + register_string_modulo_op(PackedColorArray, Variant::PACKED_COLOR_ARRAY); register_op<OperatorEvaluatorPow<int64_t, int64_t, int64_t>>(Variant::OP_POWER, Variant::INT, Variant::INT); register_op<OperatorEvaluatorPow<double, int64_t, double>>(Variant::OP_POWER, Variant::INT, Variant::FLOAT); @@ -498,7 +512,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorEqual<int64_t, double>>(Variant::OP_EQUAL, Variant::INT, Variant::FLOAT); register_op<OperatorEvaluatorEqual<double, int64_t>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorEqual<double, double>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::FLOAT); - register_op<OperatorEvaluatorEqual<String, String>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING); + register_string_op(OperatorEvaluatorEqual, Variant::OP_EQUAL); register_op<OperatorEvaluatorEqual<Vector2, Vector2>>(Variant::OP_EQUAL, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorEqual<Vector2i, Vector2i>>(Variant::OP_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorEqual<Rect2, Rect2>>(Variant::OP_EQUAL, Variant::RECT2, Variant::RECT2); @@ -516,10 +530,6 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorEqual<Projection, Projection>>(Variant::OP_EQUAL, Variant::PROJECTION, Variant::PROJECTION); register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR); - register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING); - register_op<OperatorEvaluatorEqual<String, StringName>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING_NAME); - register_op<OperatorEvaluatorEqual<StringName, StringName>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME); - register_op<OperatorEvaluatorEqual<NodePath, NodePath>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH); register_op<OperatorEvaluatorEqual<::RID, ::RID>>(Variant::OP_EQUAL, Variant::RID, Variant::RID); @@ -621,7 +631,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotEqual<int64_t, double>>(Variant::OP_NOT_EQUAL, Variant::INT, Variant::FLOAT); register_op<OperatorEvaluatorNotEqual<double, int64_t>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorNotEqual<double, double>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::FLOAT); - register_op<OperatorEvaluatorNotEqual<String, String>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING); + register_string_op(OperatorEvaluatorNotEqual, Variant::OP_NOT_EQUAL); register_op<OperatorEvaluatorNotEqual<Vector2, Vector2>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorNotEqual<Vector2i, Vector2i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorNotEqual<Rect2, Rect2>>(Variant::OP_NOT_EQUAL, Variant::RECT2, Variant::RECT2); @@ -639,10 +649,6 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotEqual<Projection, Projection>>(Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::PROJECTION); register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR); - register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING); - register_op<OperatorEvaluatorNotEqual<String, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING_NAME); - register_op<OperatorEvaluatorNotEqual<StringName, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME); - register_op<OperatorEvaluatorNotEqual<NodePath, NodePath>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH); register_op<OperatorEvaluatorNotEqual<::RID, ::RID>>(Variant::OP_NOT_EQUAL, Variant::RID, Variant::RID); @@ -895,10 +901,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL); register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL); - register_op<OperatorEvaluatorInStringFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING); - register_op<OperatorEvaluatorInStringFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING); - register_op<OperatorEvaluatorInStringNameFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING_NAME); - register_op<OperatorEvaluatorInStringNameFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING_NAME); + register_string_op(OperatorEvaluatorInStringFind, Variant::OP_IN); register_op<OperatorEvaluatorInDictionaryHasNil>(Variant::OP_IN, Variant::NIL, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<bool>>(Variant::OP_IN, Variant::BOOL, Variant::DICTIONARY); @@ -996,6 +999,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInArrayFind<float, PackedFloat64Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_FLOAT64_ARRAY); register_op<OperatorEvaluatorInArrayFind<String, PackedStringArray>>(Variant::OP_IN, Variant::STRING, Variant::PACKED_STRING_ARRAY); + register_op<OperatorEvaluatorInArrayFind<StringName, PackedStringArray>>(Variant::OP_IN, Variant::STRING_NAME, Variant::PACKED_STRING_ARRAY); register_op<OperatorEvaluatorInArrayFind<Vector2, PackedVector2Array>>(Variant::OP_IN, Variant::VECTOR2, Variant::PACKED_VECTOR2_ARRAY); register_op<OperatorEvaluatorInArrayFind<Vector3, PackedVector3Array>>(Variant::OP_IN, Variant::VECTOR3, Variant::PACKED_VECTOR3_ARRAY); @@ -1006,6 +1010,9 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorObjectHasPropertyStringName>(Variant::OP_IN, Variant::STRING_NAME, Variant::OBJECT); } +#undef register_string_op +#undef register_string_modulo_op + void Variant::_unregister_variant_operators() { } diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index ec1ce67445..ea4216322c 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -875,7 +875,33 @@ public: static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; } }; -class OperatorEvaluatorStringModNil { +template <class Left, class Right> +class OperatorEvaluatorStringConcat { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String a(*VariantGetInternalPtr<Left>::get_ptr(&p_left)); + const String b(*VariantGetInternalPtr<Right>::get_ptr(&p_right)); + *r_ret = a + b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const String a(*VariantGetInternalPtr<Left>::get_ptr(left)); + const String b(*VariantGetInternalPtr<Right>::get_ptr(right)); + *VariantGetInternalPtr<String>::get_ptr(r_ret) = a + b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + const String a(PtrToArg<Left>::convert(left)); + const String b(PtrToArg<Right>::convert(right)); + PtrToArg<String>::encode(a + b, r_ret); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +template <class S, class T> +class OperatorEvaluatorStringFormat; + +template <class S> +class OperatorEvaluatorStringFormat<S, void> { public: _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) { Array values; @@ -888,20 +914,22 @@ public: return a; } static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, &r_valid); - r_valid = true; + *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), &r_valid); } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr); + bool valid = true; + String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), &valid); + ERR_FAIL_COND_MSG(!valid, result); + *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), nullptr), r_ret); + PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), nullptr), r_ret); } static Variant::Type get_return_type() { return Variant::STRING; } }; -class OperatorEvaluatorStringModArray { +template <class S> +class OperatorEvaluatorStringFormat<S, Array> { public: _FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) { String a = s.sprintf(p_values, r_valid); @@ -911,20 +939,22 @@ public: return a; } static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid); - r_valid = true; + *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid); } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr); + bool valid = true; + String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), &valid); + ERR_FAIL_COND_MSG(!valid, result); + *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret); + PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret); } static Variant::Type get_return_type() { return Variant::STRING; } }; -class OperatorEvaluatorStringModObject { +template <class S> +class OperatorEvaluatorStringFormat<S, Object> { public: _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) { Array values; @@ -937,21 +967,22 @@ public: return a; } static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, p_right.get_validated_object(), &r_valid); - r_valid = true; + *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), p_right.get_validated_object(), &r_valid); } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr); + bool valid = true; + String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), right->get_validated_object(), &valid); + ERR_FAIL_COND_MSG(!valid, result); + *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret); + PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret); } static Variant::Type get_return_type() { return Variant::STRING; } }; -template <class T> -class OperatorEvaluatorStringModT { +template <class S, class T> +class OperatorEvaluatorStringFormat { public: _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) { Array values; @@ -963,15 +994,16 @@ public: return a; } static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid); - r_valid = true; + *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid); } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr); + bool valid = true; + String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), &valid); + ERR_FAIL_COND_MSG(!valid, result); + *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret); + PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret); } static Variant::Type get_return_type() { return Variant::STRING; } }; @@ -1280,8 +1312,11 @@ public: //// +template <class Left, class Right> +class OperatorEvaluatorInStringFind; + template <class Left> -class OperatorEvaluatorInStringFind { +class OperatorEvaluatorInStringFind<Left, String> { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left); @@ -1302,7 +1337,7 @@ public: }; template <class Left> -class OperatorEvaluatorInStringNameFind { +class OperatorEvaluatorInStringFind<Left, StringName> { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left); diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index 17d41ca95e..9f500dbf5e 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -35,37 +35,76 @@ #include "core/os/keyboard.h" #include "core/string/string_buffer.h" -char32_t VariantParser::StreamFile::get_char() { - return f->get_8(); +char32_t VariantParser::Stream::get_char() { + // is within buffer? + if (readahead_pointer < readahead_filled) { + return readahead_buffer[readahead_pointer++]; + } + + // attempt to readahead + readahead_filled = _read_buffer(readahead_buffer, READAHEAD_SIZE); + if (readahead_filled) { + readahead_pointer = 0; + } else { + // EOF + readahead_pointer = 1; + eof = true; + return 0; + } + return get_char(); } bool VariantParser::StreamFile::is_utf8() const { return true; } -bool VariantParser::StreamFile::is_eof() const { - return f->eof_reached(); -} +uint32_t VariantParser::StreamFile::_read_buffer(char32_t *p_buffer, uint32_t p_num_chars) { + // The buffer is assumed to include at least one character (for null terminator) + ERR_FAIL_COND_V(!p_num_chars, 0); -char32_t VariantParser::StreamString::get_char() { - if (pos > s.length()) { - return 0; - } else if (pos == s.length()) { - // You need to try to read again when you have reached the end for EOF to be reported, - // so this works the same as files (like StreamFile does) - pos++; - return 0; - } else { - return s[pos++]; + uint8_t *temp = (uint8_t *)alloca(p_num_chars); + uint64_t num_read = f->get_buffer(temp, p_num_chars); + ERR_FAIL_COND_V(num_read == UINT64_MAX, 0); + + // translate to wchar + for (uint32_t n = 0; n < num_read; n++) { + p_buffer[n] = temp[n]; } + + // could be less than p_num_chars, or zero + return num_read; } bool VariantParser::StreamString::is_utf8() const { return false; } -bool VariantParser::StreamString::is_eof() const { - return pos > s.length(); +uint32_t VariantParser::StreamString::_read_buffer(char32_t *p_buffer, uint32_t p_num_chars) { + // The buffer is assumed to include at least one character (for null terminator) + ERR_FAIL_COND_V(!p_num_chars, 0); + + int available = MAX(s.length() - pos, 0); + if (available >= (int)p_num_chars) { + const char32_t *src = s.ptr(); + src += pos; + memcpy(p_buffer, src, p_num_chars * sizeof(char32_t)); + pos += p_num_chars; + + return p_num_chars; + } + + // going to reach EOF + if (available) { + const char32_t *src = s.ptr(); + src += pos; + memcpy(p_buffer, src, available * sizeof(char32_t)); + pos += available; + } + + // add a zero + p_buffer[available] = 0; + + return available; } ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 56b484c8bc..6b1d095ab5 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -38,34 +38,50 @@ class VariantParser { public: struct Stream { - virtual char32_t get_char() = 0; - virtual bool is_utf8() const = 0; - virtual bool is_eof() const = 0; + private: + enum { READAHEAD_SIZE = 2048 }; + char32_t readahead_buffer[READAHEAD_SIZE]; + uint32_t readahead_pointer = 0; + uint32_t readahead_filled = 0; + bool eof = false; + + protected: + virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) = 0; + public: char32_t saved = 0; + char32_t get_char(); + virtual bool is_utf8() const = 0; + bool is_eof() const { return eof; } + Stream() {} virtual ~Stream() {} }; struct StreamFile : public Stream { + protected: + virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) override; + + public: Ref<FileAccess> f; - virtual char32_t get_char() override; virtual bool is_utf8() const override; - virtual bool is_eof() const override; StreamFile() {} }; struct StreamString : public Stream { String s; + + private: int pos = 0; - virtual char32_t get_char() override; - virtual bool is_utf8() const override; - virtual bool is_eof() const override; + protected: + virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) override; + public: + virtual bool is_utf8() const override; StreamString() {} }; |