From dae144ed0dab2dbbfde18d8659ee5396f8c24e4f Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 31 Dec 2023 14:12:08 +0100 Subject: [PATCH] Added Variant from Pandemonium. --- sfw/object/array.cpp | 479 ++++ sfw/object/array.h | 87 + sfw/object/dictionary.cpp | 297 +++ sfw/object/dictionary.h | 70 + sfw/object/old/variant.cpp | 624 +++++ sfw/object/old/variant.h | 120 + sfw/object/variant.cpp | 4526 +++++++++++++++++++++++++++++++----- sfw/object/variant.h | 580 ++++- 8 files changed, 6102 insertions(+), 681 deletions(-) create mode 100644 sfw/object/array.cpp create mode 100644 sfw/object/array.h create mode 100644 sfw/object/dictionary.cpp create mode 100644 sfw/object/dictionary.h create mode 100644 sfw/object/old/variant.cpp create mode 100644 sfw/object/old/variant.h diff --git a/sfw/object/array.cpp b/sfw/object/array.cpp new file mode 100644 index 0000000..cec04af --- /dev/null +++ b/sfw/object/array.cpp @@ -0,0 +1,479 @@ +/*************************************************************************/ +/* array.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +#include "array.h" + +#include "core/containers/hashfuncs.h" +#include "core/containers/vector.h" +#include "core/object/object.h" +#include "core/variant/variant.h" + +class ArrayPrivate { +public: + SafeRefCount refcount; + Vector array; +}; + +void Array::_ref(const Array &p_from) const { + ArrayPrivate *_fp = p_from._p; + + ERR_FAIL_COND(!_fp); // should NOT happen. + + if (_fp == _p) { + return; // whatever it is, nothing to do here move along + } + + bool success = _fp->refcount.ref(); + + ERR_FAIL_COND(!success); // should really not happen either + + _unref(); + + _p = p_from._p; +} + +void Array::_unref() const { + if (!_p) { + return; + } + + if (_p->refcount.unref()) { + memdelete(_p); + } + _p = nullptr; +} + +Variant &Array::operator[](int p_idx) { + return _p->array.write[p_idx]; +} + +const Variant &Array::operator[](int p_idx) const { + return _p->array[p_idx]; +} + +int Array::size() const { + return _p->array.size(); +} +bool Array::empty() const { + return _p->array.empty(); +} +void Array::clear() { + _p->array.clear(); +} + +bool Array::deep_equal(const Array &p_array, int p_recursion_count) const { + // Cheap checks + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, true, "Max recursion reached"); + if (_p == p_array._p) { + return true; + } + const Vector &a1 = _p->array; + const Vector &a2 = p_array._p->array; + const int size = a1.size(); + if (size != a2.size()) { + return false; + } + + // Heavy O(n) check + p_recursion_count++; + for (int i = 0; i < size; i++) { + if (!a1[i].deep_equal(a2[i], p_recursion_count)) { + return false; + } + } + + return true; +} + +bool Array::operator==(const Array &p_array) const { + return _p == p_array._p; +} + +uint32_t Array::hash() const { + return recursive_hash(0); +} + +uint32_t Array::recursive_hash(int p_recursion_count) const { + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, 0, "Max recursion reached"); + p_recursion_count++; + + uint32_t h = hash_murmur3_one_32(0); + + for (int i = 0; i < _p->array.size(); i++) { + h = hash_murmur3_one_32(_p->array[i].recursive_hash(p_recursion_count), h); + } + return hash_fmix32(h); +} + +void Array::operator=(const Array &p_array) { + _ref(p_array); +} + +void Array::push_back(const Variant &p_value) { + _p->array.push_back(p_value); +} + +void Array::append_array(const Array &p_array) { + _p->array.append_array(p_array._p->array); +} + +Error Array::resize(int p_new_size) { + return _p->array.resize(p_new_size); +} + +void Array::insert(int p_pos, const Variant &p_value) { + _p->array.insert(p_pos, p_value); +} + +void Array::fill(const Variant &p_value) { + _p->array.fill(p_value); +} + +void Array::erase(const Variant &p_value) { + _p->array.erase(p_value); +} + +Variant Array::front() const { + ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array."); + return operator[](0); +} + +Variant Array::back() const { + ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array."); + return operator[](_p->array.size() - 1); +} + +int Array::find(const Variant &p_value, int p_from) const { + return _p->array.find(p_value, p_from); +} + +int Array::rfind(const Variant &p_value, int p_from) const { + if (_p->array.size() == 0) { + return -1; + } + + if (p_from < 0) { + // Relative offset from the end + p_from = _p->array.size() + p_from; + } + if (p_from < 0 || p_from >= _p->array.size()) { + // Limit to array boundaries + p_from = _p->array.size() - 1; + } + + for (int i = p_from; i >= 0; i--) { + if (_p->array[i] == p_value) { + return i; + } + } + + return -1; +} + +int Array::find_last(const Variant &p_value) const { + return rfind(p_value); +} + +int Array::count(const Variant &p_value) const { + 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) { + amount++; + } + } + + return amount; +} + +bool Array::has(const Variant &p_value) const { + return _p->array.find(p_value, 0) != -1; +} + +void Array::remove(int p_pos) { + _p->array.remove(p_pos); +} + +void Array::set(int p_idx, const Variant &p_value) { + operator[](p_idx) = p_value; +} + +const Variant &Array::get(int p_idx) const { + return operator[](p_idx); +} + +Array Array::duplicate(bool p_deep) const { + Array new_arr; + int element_count = size(); + new_arr.resize(element_count); + for (int i = 0; i < element_count; i++) { + new_arr[i] = p_deep ? get(i).duplicate(p_deep) : get(i); + } + + return new_arr; +} + +int Array::_clamp_slice_index(int p_index) const { + int arr_size = size(); + int fixed_index = CLAMP(p_index, -arr_size, arr_size - 1); + if (fixed_index < 0) { + fixed_index = arr_size + fixed_index; + } + return fixed_index; +} + +Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { // like python, but inclusive on upper bound + + Array new_arr; + + ERR_FAIL_COND_V_MSG(p_step == 0, new_arr, "Array slice step size cannot be zero."); + + if (empty()) { // Don't try to slice empty arrays. + return new_arr; + } + if (p_step > 0) { + if (p_begin >= size() || p_end < -size()) { + return new_arr; + } + } else { // p_step < 0 + if (p_begin < -size() || p_end >= size()) { + return new_arr; + } + } + + int begin = _clamp_slice_index(p_begin); + int end = _clamp_slice_index(p_end); + + int new_arr_size = MAX(((end - begin + p_step) / p_step), 0); + new_arr.resize(new_arr_size); + + if (p_step > 0) { + int dest_idx = 0; + for (int idx = begin; idx <= end; idx += p_step) { + ERR_FAIL_COND_V_MSG(dest_idx < 0 || dest_idx >= new_arr_size, Array(), "Bug in Array slice()"); + new_arr[dest_idx++] = p_deep ? get(idx).duplicate(p_deep) : get(idx); + } + } else { // p_step < 0 + int dest_idx = 0; + for (int idx = begin; idx >= end; idx += p_step) { + ERR_FAIL_COND_V_MSG(dest_idx < 0 || dest_idx >= new_arr_size, Array(), "Bug in Array slice()"); + new_arr[dest_idx++] = p_deep ? get(idx).duplicate(p_deep) : get(idx); + } + } + + return new_arr; +} + +struct _ArrayVariantSort { + _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const { + bool valid = false; + Variant res; + Variant::evaluate(Variant::OP_LESS, p_l, p_r, res, valid); + if (!valid) { + res = false; + } + return res; + } +}; + +Array &Array::sort() { + _p->array.sort_custom<_ArrayVariantSort>(); + return *this; +} + +struct _ArrayVariantSortCustom { + Object *obj; + StringName func; + + _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const { + const Variant *args[2] = { &p_l, &p_r }; + Variant::CallError err; + bool res = obj->call(func, args, 2, err); + if (err.error != Variant::CallError::CALL_OK) { + res = false; + } + return res; + } +}; +Array &Array::sort_custom(Object *p_obj, const StringName &p_function) { + ERR_FAIL_NULL_V(p_obj, *this); + + SortArray avs; + avs.compare.obj = p_obj; + avs.compare.func = p_function; + avs.sort(_p->array.ptrw(), _p->array.size()); + return *this; +} + +void Array::shuffle() { + const int n = _p->array.size(); + if (n < 2) { + return; + } + Variant *data = _p->array.ptrw(); + for (int i = n - 1; i >= 1; i--) { + const int j = Math::rand() % (i + 1); + const Variant tmp = data[j]; + data[j] = data[i]; + data[i] = tmp; + } +} + +template +_FORCE_INLINE_ int bisect(const Vector &p_array, const Variant &p_value, bool p_before, const Less &p_less) { + int lo = 0; + int hi = p_array.size(); + if (p_before) { + while (lo < hi) { + const int mid = (lo + hi) / 2; + if (p_less(p_array.get(mid), p_value)) { + lo = mid + 1; + } else { + hi = mid; + } + } + } else { + while (lo < hi) { + const int mid = (lo + hi) / 2; + if (p_less(p_value, p_array.get(mid))) { + hi = mid; + } else { + lo = mid + 1; + } + } + } + return lo; +} + +int Array::bsearch(const Variant &p_value, bool p_before) { + return bisect(_p->array, p_value, p_before, _ArrayVariantSort()); +} + +int Array::bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before) { + ERR_FAIL_NULL_V(p_obj, 0); + + _ArrayVariantSortCustom less; + less.obj = p_obj; + less.func = p_function; + + return bisect(_p->array, p_value, p_before, less); +} + +Array &Array::invert() { + _p->array.invert(); + return *this; +} + +void Array::push_front(const Variant &p_value) { + _p->array.insert(0, p_value); +} + +Variant Array::pop_back() { + if (!_p->array.empty()) { + const int n = _p->array.size() - 1; + const Variant ret = _p->array.get(n); + _p->array.resize(n); + return ret; + } + return Variant(); +} + +Variant Array::pop_front() { + if (!_p->array.empty()) { + const Variant ret = _p->array.get(0); + _p->array.remove(0); + return ret; + } + return Variant(); +} + +Variant Array::pop_at(int p_pos) { + if (_p->array.empty()) { + // Return `null` without printing an error to mimic `pop_back()` and `pop_front()` behavior. + return Variant(); + } + + if (p_pos < 0) { + // Relative offset from the end + p_pos = _p->array.size() + p_pos; + } + + ERR_FAIL_INDEX_V_MSG( + p_pos, + _p->array.size(), + Variant(), + vformat( + "The calculated index %s is out of bounds (the array has %s elements). Leaving the array untouched and returning `null`.", + p_pos, + _p->array.size())); + + const Variant ret = _p->array.get(p_pos); + _p->array.remove(p_pos); + return ret; +} + +Variant Array::min() const { + Variant minval; + for (int i = 0; i < size(); i++) { + if (i == 0) { + minval = get(i); + } else { + bool valid; + Variant ret; + Variant test = get(i); + Variant::evaluate(Variant::OP_LESS, test, minval, ret, valid); + if (!valid) { + return Variant(); //not a valid comparison + } + if (bool(ret)) { + //is less + minval = test; + } + } + } + return minval; +} + +Variant Array::max() const { + Variant maxval; + for (int i = 0; i < size(); i++) { + if (i == 0) { + maxval = get(i); + } else { + bool valid; + Variant ret; + Variant test = get(i); + Variant::evaluate(Variant::OP_GREATER, test, maxval, ret, valid); + if (!valid) { + return Variant(); //not a valid comparison + } + if (bool(ret)) { + //is less + maxval = test; + } + } + } + return maxval; +} + +const void *Array::id() const { + return _p; +} + +Array::Array(const Array &p_from) { + _p = nullptr; + _ref(p_from); +} + +Array::Array() { + _p = memnew(ArrayPrivate); + _p->refcount.init(); +} +Array::~Array() { + _unref(); +} diff --git a/sfw/object/array.h b/sfw/object/array.h new file mode 100644 index 0000000..720e31a --- /dev/null +++ b/sfw/object/array.h @@ -0,0 +1,87 @@ +#ifndef ARRAY_H +#define ARRAY_H + +/*************************************************************************/ +/* array.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +#include "core/typedefs.h" + +class Variant; +class ArrayPrivate; +class Object; +class StringName; + +class Array { + mutable ArrayPrivate *_p; + void _ref(const Array &p_from) const; + void _unref() const; + + inline int _clamp_slice_index(int p_index) const; + +public: + Variant &operator[](int p_idx); + const Variant &operator[](int p_idx) const; + + void set(int p_idx, const Variant &p_value); + const Variant &get(int p_idx) const; + + int size() const; + bool empty() const; + void clear(); + + bool deep_equal(const Array &p_array, int p_recursion_count = 0) const; + bool operator==(const Array &p_array) const; + + uint32_t hash() const; + uint32_t recursive_hash(int p_recursion_count) const; + void operator=(const Array &p_array); + + void push_back(const Variant &p_value); + _FORCE_INLINE_ void append(const Variant &p_value) { push_back(p_value); } //for python compatibility + void append_array(const Array &p_array); + Error resize(int p_new_size); + + void insert(int p_pos, const Variant &p_value); + void remove(int p_pos); + void fill(const Variant &p_value); + + Variant front() const; + Variant back() const; + + Array &sort(); + Array &sort_custom(Object *p_obj, const StringName &p_function); + void shuffle(); + int bsearch(const Variant &p_value, bool p_before = true); + int bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before = true); + Array &invert(); + + int find(const Variant &p_value, int p_from = 0) const; + int rfind(const Variant &p_value, int p_from = -1) const; + int find_last(const Variant &p_value) const; + int count(const Variant &p_value) const; + bool has(const Variant &p_value) const; + + void erase(const Variant &p_value); + + void push_front(const Variant &p_value); + Variant pop_back(); + Variant pop_front(); + Variant pop_at(int p_pos); + + Array duplicate(bool p_deep = false) const; + + Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const; + + Variant min() const; + Variant max() const; + + const void *id() const; + + Array(const Array &p_from); + Array(); + ~Array(); +}; + +#endif // ARRAY_H diff --git a/sfw/object/dictionary.cpp b/sfw/object/dictionary.cpp new file mode 100644 index 0000000..dc2e92c --- /dev/null +++ b/sfw/object/dictionary.cpp @@ -0,0 +1,297 @@ +/*************************************************************************/ +/* dictionary.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +#include "dictionary.h" + +#include "core/containers/ordered_hash_map.h" +#include "core/os/safe_refcount.h" +#include "core/variant/variant.h" + +struct DictionaryPrivate { + SafeRefCount refcount; + OrderedHashMap variant_map; +}; + +void Dictionary::get_key_list(List *p_keys) const { + if (_p->variant_map.empty()) { + return; + } + + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + p_keys->push_back(E.key()); + } +} + +Variant Dictionary::get_key_at_index(int p_index) const { + int index = 0; + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + if (index == p_index) { + return E.key(); + } + index++; + } + + return Variant(); +} + +Variant Dictionary::get_value_at_index(int p_index) const { + int index = 0; + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + if (index == p_index) { + return E.value(); + } + index++; + } + + return Variant(); +} + +Variant &Dictionary::operator[](const Variant &p_key) { + return _p->variant_map[p_key]; +} + +const Variant &Dictionary::operator[](const Variant &p_key) const { + return _p->variant_map[p_key]; +} +const Variant *Dictionary::getptr(const Variant &p_key) const { + OrderedHashMap::ConstElement E = ((const OrderedHashMap *)&_p->variant_map)->find(p_key); + + if (!E) { + return nullptr; + } + return &E.get(); +} + +Variant *Dictionary::getptr(const Variant &p_key) { + OrderedHashMap::Element E = _p->variant_map.find(p_key); + + if (!E) { + return nullptr; + } + return &E.get(); +} + +Variant Dictionary::get_valid(const Variant &p_key) const { + OrderedHashMap::ConstElement E = ((const OrderedHashMap *)&_p->variant_map)->find(p_key); + + if (!E) { + return Variant(); + } + return E.get(); +} + +Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const { + const Variant *result = getptr(p_key); + if (!result) { + return p_default; + } + + return *result; +} + +int Dictionary::size() const { + return _p->variant_map.size(); +} +bool Dictionary::empty() const { + return !_p->variant_map.size(); +} + +bool Dictionary::has(const Variant &p_key) const { + return _p->variant_map.has(p_key); +} + +bool Dictionary::has_all(const Array &p_keys) const { + for (int i = 0; i < p_keys.size(); i++) { + if (!has(p_keys[i])) { + return false; + } + } + return true; +} + +Variant Dictionary::find_key(const Variant &p_value) const { + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + if (E.value() == p_value) { + return E.key(); + } + } + return Variant(); +} + +bool Dictionary::erase(const Variant &p_key) { + return _p->variant_map.erase(p_key); +} + +bool Dictionary::deep_equal(const Dictionary &p_dictionary, int p_recursion_count) const { + // Cheap checks + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, 0, "Max recursion reached"); + if (_p == p_dictionary._p) { + return true; + } + if (_p->variant_map.size() != p_dictionary._p->variant_map.size()) { + return false; + } + + // Heavy O(n) check + OrderedHashMap::Element this_E = _p->variant_map.front(); + OrderedHashMap::Element other_E = p_dictionary._p->variant_map.front(); + p_recursion_count++; + while (this_E && other_E) { + if ( + !this_E.key().deep_equal(other_E.key(), p_recursion_count) || + !this_E.value().deep_equal(other_E.value(), p_recursion_count)) { + return false; + } + + this_E = this_E.next(); + other_E = other_E.next(); + } + + return !this_E && !other_E; +} + +bool Dictionary::operator==(const Dictionary &p_dictionary) const { + return _p == p_dictionary._p; +} + +bool Dictionary::operator!=(const Dictionary &p_dictionary) const { + return _p != p_dictionary._p; +} + +void Dictionary::_ref(const Dictionary &p_from) const { + //make a copy first (thread safe) + if (!p_from._p->refcount.ref()) { + return; // couldn't copy + } + + //if this is the same, unreference the other one + if (p_from._p == _p) { + _p->refcount.unref(); + return; + } + if (_p) { + _unref(); + } + _p = p_from._p; +} + +void Dictionary::clear() { + _p->variant_map.clear(); +} + +void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) { + for (OrderedHashMap::Element E = p_dictionary._p->variant_map.front(); E; E = E.next()) { + if (p_overwrite || !has(E.key())) { + this->operator[](E.key()) = E.value(); + } + } +} + +void Dictionary::_unref() const { + ERR_FAIL_COND(!_p); + if (_p->refcount.unref()) { + memdelete(_p); + } + _p = nullptr; +} + +uint32_t Dictionary::hash() const { + return recursive_hash(0); +} + +uint32_t Dictionary::recursive_hash(int p_recursion_count) const { + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, 0, "Max recursion reached"); + p_recursion_count++; + + uint32_t h = hash_murmur3_one_32(Variant::DICTIONARY); + + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + h = hash_murmur3_one_32(E.key().recursive_hash(p_recursion_count), h); + h = hash_murmur3_one_32(E.value().recursive_hash(p_recursion_count), h); + } + + return hash_fmix32(h); +} + +Array Dictionary::keys() const { + Array varr; + if (_p->variant_map.empty()) { + return varr; + } + + varr.resize(size()); + + int i = 0; + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + varr[i] = E.key(); + i++; + } + + return varr; +} + +Array Dictionary::values() const { + Array varr; + if (_p->variant_map.empty()) { + return varr; + } + + varr.resize(size()); + + int i = 0; + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + varr[i] = E.get(); + i++; + } + + return varr; +} + +const Variant *Dictionary::next(const Variant *p_key) const { + if (p_key == nullptr) { + // caller wants to get the first element + if (_p->variant_map.front()) { + return &_p->variant_map.front().key(); + } + return nullptr; + } + OrderedHashMap::Element E = _p->variant_map.find(*p_key); + + if (E && E.next()) { + return &E.next().key(); + } + return nullptr; +} + +Dictionary Dictionary::duplicate(bool p_deep) const { + Dictionary n; + + for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + n[E.key()] = p_deep ? E.value().duplicate(true) : E.value(); + } + + return n; +} + +void Dictionary::operator=(const Dictionary &p_dictionary) { + _ref(p_dictionary); +} + +const void *Dictionary::id() const { + return _p; +} + +Dictionary::Dictionary(const Dictionary &p_from) { + _p = nullptr; + _ref(p_from); +} + +Dictionary::Dictionary() { + _p = memnew(DictionaryPrivate); + _p->refcount.init(); +} +Dictionary::~Dictionary() { + _unref(); +} diff --git a/sfw/object/dictionary.h b/sfw/object/dictionary.h new file mode 100644 index 0000000..16183d8 --- /dev/null +++ b/sfw/object/dictionary.h @@ -0,0 +1,70 @@ +#ifndef DICTIONARY_H +#define DICTIONARY_H + +/*************************************************************************/ +/* dictionary.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +#include "core/containers/list.h" +#include "core/string/ustring.h" +#include "core/variant/array.h" + +class Variant; + +struct DictionaryPrivate; + +class Dictionary { + mutable DictionaryPrivate *_p; + + void _ref(const Dictionary &p_from) const; + void _unref() const; + +public: + void get_key_list(List *p_keys) const; + Variant get_key_at_index(int p_index) const; + Variant get_value_at_index(int p_index) const; + + Variant &operator[](const Variant &p_key); + const Variant &operator[](const Variant &p_key) const; + + const Variant *getptr(const Variant &p_key) const; + Variant *getptr(const Variant &p_key); + + Variant get_valid(const Variant &p_key) const; + Variant get(const Variant &p_key, const Variant &p_default) const; + + int size() const; + bool empty() const; + void clear(); + void merge(const Dictionary &p_dictionary, bool p_overwrite = false); + + bool has(const Variant &p_key) const; + bool has_all(const Array &p_keys) const; + Variant find_key(const Variant &p_value) const; + + bool erase(const Variant &p_key); + + bool deep_equal(const Dictionary &p_dictionary, int p_recursion_count = 0) const; + bool operator==(const Dictionary &p_dictionary) const; + bool operator!=(const Dictionary &p_dictionary) const; + + uint32_t hash() const; + uint32_t recursive_hash(int p_recursion_count) const; + void operator=(const Dictionary &p_dictionary); + + const Variant *next(const Variant *p_key = nullptr) const; + + Array keys() const; + Array values() const; + + Dictionary duplicate(bool p_deep = false) const; + + const void *id() const; + + Dictionary(const Dictionary &p_from); + Dictionary(); + ~Dictionary(); +}; + +#endif // DICTIONARY_H diff --git a/sfw/object/old/variant.cpp b/sfw/object/old/variant.cpp new file mode 100644 index 0000000..146c9a8 --- /dev/null +++ b/sfw/object/old/variant.cpp @@ -0,0 +1,624 @@ +#include "variant.h" + +#include "math.h" +#include "core/reference.h" + +Variant::Type Variant::get_type() const { + return _type; +} + +void Variant::clear() { + switch (_type) { + case TYPE_NULL: + break; + case TYPE_BOOL: + _bool = false; + break; + case TYPE_INT: + _int = 0; + break; + case TYPE_UINT: + _uint = 0; + break; + case TYPE_FLOAT: + _float = 0; + break; + case TYPE_STRING: + if (_string->owner) { + delete _string->string; + } + + delete _string; + _string = nullptr; + + break; + case TYPE_OBJECT: + delete _object; + _object = nullptr; + + break; + case TYPE_POINTER: + _pointer = nullptr; + + break; + default: + break; + } + + _type = TYPE_NULL; +} +void Variant::zero() { + switch (_type) { + case TYPE_NULL: + break; + case TYPE_BOOL: + _bool = false; + break; + case TYPE_INT: + _int = 0; + break; + case TYPE_UINT: + _uint = 0; + break; + case TYPE_FLOAT: + _float = 0; + break; + case TYPE_STRING: + _string->string->resize(0); + break; + case TYPE_OBJECT: + _object->object = nullptr; + _object->reference.unref(); + break; + case TYPE_POINTER: + _pointer = nullptr; + break; + default: + break; + } +} + +void Variant::parse(const String &str) { + if (str.is_int()) { + set_int(str.to_int()); + return; + } + + if (str.is_uint()) { + set_uint(str.to_uint()); + return; + } + + if (str.is_numeric()) { + set_float(str.to_float()); + return; + } + + if (str.is_bool()) { + set_bool(str.to_bool()); + return; + } + + set_string(str); +} +Variant Variant::parse_string(const String &str) { + Variant v = Variant(); + + v.parse(str); + + return v; +} + +bool Variant::is_null() const { + return _type == TYPE_NULL; +} +bool Variant::is_bool() const { + return _type == TYPE_BOOL; +} +bool Variant::is_int() const { + return _type == TYPE_INT; +} +bool Variant::is_uint() const { + return _type == TYPE_UINT; +} +bool Variant::is_float() const { + return _type == TYPE_FLOAT; +} +bool Variant::is_numeric() const { + return _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT; +} +bool Variant::is_string() const { + return _type == TYPE_STRING; +} +bool Variant::is_object() const { + return _type == TYPE_OBJECT; +} +bool Variant::is_pointer() const { + return _type == TYPE_POINTER; +} +bool Variant::is_reference() const { + if (_type == TYPE_OBJECT) { + return _object->reference.is_valid(); + } + + return false; +} + +bool Variant::is_primitive_type() const { + return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT; +} + +bool Variant::is_simple_type() const { + return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT || _type == TYPE_STRING; +} + +bool Variant::to_bool() const { + return _bool; +} +int Variant::to_int() const { + switch (_type) { + case TYPE_NULL: + return 0; + case TYPE_BOOL: + if (_bool) { + return 1; + } else { + return 0; + } + case TYPE_INT: + case TYPE_UINT: + return _int; + case TYPE_FLOAT: + return static_cast(_int); + case TYPE_STRING: + return _string->string->to_int(); + case TYPE_OBJECT: + case TYPE_POINTER: + // just read the value of the pointer as int + // Could return 1 or 0, but this is almost the same, but hopefully it's more useful + return _int; + default: + return 0; + } +} +uint64_t Variant::to_uint() const { + switch (_type) { + case TYPE_NULL: + return 0; + case TYPE_BOOL: + if (_bool) { + return 1; + } else { + return 0; + } + case TYPE_INT: + case TYPE_UINT: + return _uint; + case TYPE_FLOAT: + return static_cast(_float); + case TYPE_STRING: + return _string->string->to_uint(); + case TYPE_OBJECT: + case TYPE_POINTER: + // just read the value of the pointer as uint + // Could return 1 or 0, but this is almost the same, but hopefully it's more useful + return _uint; + default: + return 0; + } +} +float Variant::to_float() const { + switch (_type) { + case TYPE_NULL: + return 0; + case TYPE_BOOL: + if (_bool) { + return 0; + } else { + return 1; + } + case TYPE_INT: + return static_cast(_int); + case TYPE_UINT: + return static_cast(_uint); + case TYPE_FLOAT: + return _float; + case TYPE_STRING: + return _string->string->to_float(); + case TYPE_OBJECT: + case TYPE_POINTER: + if (_uint) { + return 1; + } else { + return 0; + } + default: + return 0; + } +} +String Variant::to_string() const { + switch (_type) { + case TYPE_NULL: + return "NULL"; + case TYPE_BOOL: + if (Math::is_zero_approx(_float)) { + return "false"; + } else { + return "true"; + } + case TYPE_INT: + return String::num(_int); + case TYPE_UINT: + return String::num(_uint); + case TYPE_FLOAT: + return String::num(_float); + case TYPE_STRING: + return *(_string->string); + case TYPE_OBJECT: + case TYPE_POINTER: + if (_uint) { + return "[ Object ]"; + } else { + return "[ Object (NULL) ]"; + } + default: + return ""; + } +} +Object *Variant::to_object() const { + switch (_type) { + case TYPE_NULL: + return nullptr; + case TYPE_BOOL: + return nullptr; + case TYPE_INT: + return nullptr; + case TYPE_UINT: + return nullptr; + case TYPE_FLOAT: + return nullptr; + case TYPE_STRING: + return nullptr; + case TYPE_OBJECT: + return _object->object; + case TYPE_POINTER: + return nullptr; + default: + return nullptr; + } +} +Reference *Variant::to_reference() const { + switch (_type) { + case TYPE_NULL: + return nullptr; + case TYPE_BOOL: + return nullptr; + case TYPE_INT: + return nullptr; + case TYPE_UINT: + return nullptr; + case TYPE_FLOAT: + return nullptr; + case TYPE_STRING: + return nullptr; + case TYPE_OBJECT: + return Object::cast_to(_object->object); + case TYPE_POINTER: + return nullptr; + default: + return nullptr; + } +} +void *Variant::to_pointer() const { + switch (_type) { + case TYPE_NULL: + return nullptr; + case TYPE_BOOL: + return nullptr; + case TYPE_INT: + return nullptr; + case TYPE_UINT: + return nullptr; + case TYPE_FLOAT: + return nullptr; + case TYPE_STRING: + return nullptr; + case TYPE_OBJECT: + return nullptr; + case TYPE_POINTER: + return _pointer; + default: + return nullptr; + } +} +String *Variant::get_string_ptr() const { + if (_type == TYPE_STRING) { + return _string->string; + } + + return nullptr; +} +bool Variant::is_string_owned() const { + if (_type == TYPE_STRING) { + return _string->owner; + } + + return false; +} + +void Variant::set_null() { + clear(); + + _type = TYPE_NULL; +} +void Variant::set_bool(const bool value) { + clear(); + + _type = TYPE_BOOL; + _bool = value; +} +void Variant::set_int(const int value) { + clear(); + + _type = TYPE_INT; + _int = value; +} +void Variant::set_uint(const uint64_t value) { + clear(); + + _type = TYPE_UINT; + _uint = value; +} +void Variant::set_float(const float value) { + clear(); + + _type = TYPE_FLOAT; + _float = value; +} +void Variant::set_float(const double value) { + clear(); + + _type = TYPE_FLOAT; + _float = value; +} +void Variant::set_string(String *value, const bool copy) { + clear(); + + if (!value) { + return; + } + + _type = TYPE_STRING; + + _string = new StringData(); + + if (copy) { + _string->string = new String(*value); + _string->owner = true; + } else { + _string->string = value; + _string->owner = false; + } +} +void Variant::set_string(const String &value, const bool copy) { + clear(); + + _type = TYPE_STRING; + + _string = new StringData(); + + if (copy) { + _string->string = new String(value); + _string->owner = true; + } else { + _string->string = &const_cast(value); + _string->owner = false; + } +} +void Variant::set_object(Object *value) { + clear(); + + if (!value) { + return; + } + + _object = new ObjectData(); + _object->object = value; + + if (value->is_class_ptr(Reference::get_class_ptr_static())) { + _object->reference = Ref(Object::cast_to(value)); + } +} +void Variant::set_pointer(void *value) { + clear(); + + _type = TYPE_POINTER; + _pointer = value; +} +void Variant::set_variant(const Variant &value) { + clear(); + + switch (value._type) { + case TYPE_NULL: + break; + case TYPE_BOOL: + _bool = value._bool; + break; + case TYPE_INT: + _int = value._int; + break; + case TYPE_UINT: + _uint = value._uint; + break; + case TYPE_FLOAT: + _float = value._float; + break; + case TYPE_STRING: + set_string(value._string->string, true); + break; + case TYPE_OBJECT: + set_object(value._object->object); + break; + case TYPE_POINTER: + _pointer = value._pointer; + default: + break; + } + + _type = value._type; +} + +Variant::operator bool() const { + return to_bool(); +} +Variant::operator int() const { + return to_int(); +} +Variant::operator uint64_t() const { + return to_uint(); +} +Variant::operator float() const { + return to_float(); +} +Variant::operator double() const { + return to_float(); +} +Variant::operator String() const { + return to_string(); +} +Variant::operator Object *() const { + return to_object(); +} +Variant::operator Reference *() const { + return to_reference(); +} +Variant::operator void *() const { + return to_pointer(); +} + +void Variant::operator=(const Variant &other) { + set_variant(other); +} +bool Variant::operator==(const Variant &other) const { + if (_type != other._type) { + return false; + } + + switch (_type) { + case TYPE_NULL: + return true; + case TYPE_BOOL: + return _bool == other._bool; + case TYPE_INT: + return _int == other._int; + case TYPE_UINT: + return _uint == other._uint; + case TYPE_FLOAT: + return _float == other._float; + case TYPE_STRING: + return (*_string->string) == (*other._string->string); + case TYPE_OBJECT: + return (_object->object) == (other._object->object); + case TYPE_POINTER: + return _pointer == other._pointer; + default: + break; + } + + return false; +} +bool Variant::operator!=(const Variant &other) const { + return !(operator==(other)); +} +bool Variant::operator<(const Variant &other) const { + switch (_type) { + case TYPE_NULL: { + if (other.is_null()) { + return false; + } else { + return true; + } + } + case TYPE_BOOL: { + return _bool < other.to_bool(); + } + case TYPE_INT: + return _int < other.to_int(); + return _int == other._int; + case TYPE_UINT: + return _uint < other.to_uint(); + return _uint == other._uint; + case TYPE_FLOAT: + return _float < other.to_float(); + return _float == other._float; + case TYPE_STRING: + return (*_string->string) < other.to_string(); + case TYPE_OBJECT: + return (_object->object) < other.to_object(); + case TYPE_POINTER: + return _pointer < other.to_pointer(); + default: + break; + } + + return false; +} + +Variant::Variant(const bool value) { + _type = TYPE_BOOL; + + _bool = value; +} +Variant::Variant(const int value) { + _type = TYPE_INT; + + _int = value; +} +Variant::Variant(const uint64_t value) { + _type = TYPE_UINT; + + _uint = value; +} +Variant::Variant(const float value) { + _type = TYPE_FLOAT; + + _float = value; +} +Variant::Variant(const double value) { + _type = TYPE_FLOAT; + + _float = value; +} +Variant::Variant(String *value, bool copy) { + _type = TYPE_NULL; + + set_string(value, copy); +} +Variant::Variant(const String &value, bool copy) { + _type = TYPE_NULL; + + set_string(value, copy); +} +Variant::Variant(Object *value) { + _type = TYPE_NULL; + + set_object(value); +} +Variant::Variant(void *value) { + _type = TYPE_NULL; + + set_pointer(value); +} +Variant::Variant(const Variant &value) { + _type = TYPE_NULL; + + set_variant(value); +} + +Variant::Variant() { + _type = TYPE_NULL; +} + +Variant::~Variant() { + clear(); +} \ No newline at end of file diff --git a/sfw/object/old/variant.h b/sfw/object/old/variant.h new file mode 100644 index 0000000..8720915 --- /dev/null +++ b/sfw/object/old/variant.h @@ -0,0 +1,120 @@ +#ifndef VARIANT_H +#define VARIANT_H + +#include "core/object.h" +#include "core/reference.h" +#include "core/string.h" + +class Variant { + +public: + enum Type { + TYPE_NULL = 0, + TYPE_BOOL, + TYPE_INT, + TYPE_UINT, + TYPE_FLOAT, + TYPE_STRING, + TYPE_OBJECT, + TYPE_POINTER, + }; + + Type get_type() const; + + void clear(); + void zero(); + + void parse(const String &str); + static Variant parse_string(const String &str); + + bool is_null() const; + bool is_bool() const; + bool is_int() const; + bool is_uint() const; + bool is_float() const; + bool is_numeric() const; + bool is_string() const; + bool is_object() const; + bool is_pointer() const; + bool is_reference() const; + + bool is_primitive_type() const; + bool is_simple_type() const; + + bool to_bool() const; + int to_int() const; + uint64_t to_uint() const; + float to_float() const; + String to_string() const; + Object *to_object() const; + Reference *to_reference() const; + void *to_pointer() const; + String *get_string_ptr() const; + bool is_string_owned() const; + + void set_null(); + void set_bool(const bool value); + void set_int(const int value); + void set_uint(const uint64_t value); + void set_float(const float value); + void set_float(const double value); + void set_string(String *value, bool copy = false); + void set_string(const String &value, bool copy = true); + void set_object(Object *value); + void set_pointer(void *value); + void set_variant(const Variant &value); + + operator bool() const; + operator int() const; + operator uint64_t() const; + operator float() const; + operator double() const; + operator String() const; + operator Object *() const; + operator Reference *() const; + operator void *() const; + + void operator=(const Variant &other); + bool operator==(const Variant &other) const; + bool operator!=(const Variant &other) const; + bool operator<(const Variant &other) const; + + Variant(const bool value); + Variant(const int value); + Variant(const uint64_t value); + Variant(const float value); + Variant(const double value); + Variant(String *value, const bool copy = false); + Variant(const String &value, const bool copy = true); + Variant(Object *value); + Variant(void *value); + Variant(const Variant &value); + + Variant(); + ~Variant(); + +private: + struct StringData { + bool owner; + String *string; + }; + + struct ObjectData { + Object *object; + Ref reference; + }; + + union { + bool _bool; + int _int; + uint64_t _uint; + float _float; + StringData *_string; + ObjectData *_object; + void *_pointer; + }; + + Type _type; +}; + +#endif \ No newline at end of file diff --git a/sfw/object/variant.cpp b/sfw/object/variant.cpp index 146c9a8..8ba3bf0 100644 --- a/sfw/object/variant.cpp +++ b/sfw/object/variant.cpp @@ -1,624 +1,3988 @@ +/*************************************************************************/ +/* variant.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + #include "variant.h" -#include "math.h" -#include "core/reference.h" +#include "core/core_string_names.h" +#include "core/io/marshalls.h" +#include "core/math/math_funcs.h" +#include "core/object/object_rc.h" +#include "core/object/resource.h" +#include "core/string/print_string.h" +#include "core/variant/variant_parser.h" +#include "scene/main/control.h" +#include "scene/main/node.h" -Variant::Type Variant::get_type() const { - return _type; +String Variant::get_type_name(Variant::Type p_type) { + switch (p_type) { + case NIL: { + return "Nil"; + } break; + + // atomic types + case BOOL: { + return "bool"; + } break; + case INT: { + return "int"; + + } break; + case REAL: { + return "float"; + + } break; + case STRING: { + return "String"; + } break; + + // math types + case RECT2: { + return "Rect2"; + } break; + case RECT2I: { + return "Rect2i"; + } break; + case VECTOR2: { + return "Vector2"; + } break; + case VECTOR2I: { + return "Vector2i"; + } break; + case VECTOR3: { + return "Vector3"; + } break; + case VECTOR3I: { + return "Vector3i"; + } break; + case VECTOR4: { + return "Vector4"; + } break; + case VECTOR4I: { + return "Vector4i"; + } break; + + case PLANE: { + return "Plane"; + } break; + case QUATERNION: { + return "Quaternion"; + } break; + case AABB: { + return "AABB"; + } break; + case BASIS: { + return "Basis"; + } break; + case TRANSFORM: { + return "Transform"; + } break; + case TRANSFORM2D: { + return "Transform2D"; + } break; + case PROJECTION: { + return "Projection"; + } break; + + // misc types + case COLOR: { + return "Color"; + } break; + case NODE_PATH: { + return "NodePath"; + } break; + case RID: { + return "RID"; + } break; + case OBJECT: { + return "Object"; + } break; + case STRING_NAME: { + return "StringName"; + } break; + case DICTIONARY: { + return "Dictionary"; + } break; + case ARRAY: { + return "Array"; + } break; + + // arrays + case POOL_BYTE_ARRAY: { + return "PoolByteArray"; + } break; + case POOL_INT_ARRAY: { + return "PoolIntArray"; + } break; + case POOL_REAL_ARRAY: { + return "PoolRealArray"; + } break; + case POOL_STRING_ARRAY: { + return "PoolStringArray"; + } break; + case POOL_VECTOR2_ARRAY: { + return "PoolVector2Array"; + } break; + case POOL_VECTOR2I_ARRAY: { + return "PoolVector2iArray"; + } break; + case POOL_VECTOR3_ARRAY: { + return "PoolVector3Array"; + } break; + case POOL_VECTOR3I_ARRAY: { + return "PoolVector3iArray"; + } break; + case POOL_VECTOR4_ARRAY: { + return "PoolVector4Array"; + } break; + case POOL_VECTOR4I_ARRAY: { + return "PoolVector4iArray"; + } break; + case POOL_COLOR_ARRAY: { + return "PoolColorArray"; + } break; + default: { + } + } + + return ""; +} + +bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { + if (p_type_from == p_type_to) { + return true; + } + if (p_type_to == NIL && p_type_from != NIL) { //nil can convert to anything + return true; + } + + if (p_type_from == NIL) { + return (p_type_to == OBJECT); + }; + + const Type *valid_types = nullptr; + const Type *invalid_types = nullptr; + + switch (p_type_to) { + case NIL: { + //can't + } break; + case BOOL: { + static const Type valid[] = { + INT, + REAL, + STRING, + NIL, + }; + + valid_types = valid; + } break; + case INT: { + static const Type valid[] = { + BOOL, + REAL, + STRING, + NIL, + }; + + valid_types = valid; + } break; + case REAL: { + static const Type valid[] = { + BOOL, + INT, + STRING, + NIL, + }; + + valid_types = valid; + } break; + case STRING: { + static const Type invalid[] = { + OBJECT, + NIL + }; + + invalid_types = invalid; + } break; + case RECT2: { + static const Type valid[] = { + RECT2I, + NIL + }; + + valid_types = valid; + } break; + case RECT2I: { + static const Type valid[] = { + RECT2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2: { + static const Type valid[] = { + VECTOR2I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2I: { + static const Type valid[] = { + VECTOR2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3: { + static const Type valid[] = { + VECTOR3I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3I: { + static const Type valid[] = { + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4: { + static const Type valid[] = { + VECTOR4I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4I: { + static const Type valid[] = { + VECTOR4, + NIL + }; + + valid_types = valid; + } break; + case PLANE: { + //can't + } break; + case QUATERNION: { + static const Type valid[] = { + BASIS, + NIL + }; + + valid_types = valid; + } break; + case AABB: { + //can't + } break; + case BASIS: { + static const Type valid[] = { + QUATERNION, + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM: { + static const Type valid[] = { + TRANSFORM2D, + QUATERNION, + BASIS, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM2D: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case PROJECTION: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + // misc types + case COLOR: { + static const Type valid[] = { + STRING, + INT, + NIL, + }; + + valid_types = valid; + } break; + case NODE_PATH: { + static const Type valid[] = { + STRING, + NIL + }; + + valid_types = valid; + } break; + case RID: { + static const Type valid[] = { + OBJECT, + NIL + }; + + valid_types = valid; + } break; + case OBJECT: { + static const Type valid[] = { + NIL + }; + + valid_types = valid; + } break; + case STRING_NAME: { + static const Type valid[] = { + STRING, + NIL + }; + + valid_types = valid; + } break; + case DICTIONARY: { + //can't + } break; + case ARRAY: { + static const Type valid[] = { + POOL_BYTE_ARRAY, + POOL_INT_ARRAY, + POOL_STRING_ARRAY, + POOL_REAL_ARRAY, + POOL_COLOR_ARRAY, + POOL_VECTOR2_ARRAY, + POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, + NIL + }; + + valid_types = valid; + } break; + // arrays + case POOL_BYTE_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_INT_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_REAL_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_STRING_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR2_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR2I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR3_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR3I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR4_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR4I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_COLOR_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + default: { + } + } + + if (valid_types) { + int i = 0; + while (valid_types[i] != NIL) { + if (p_type_from == valid_types[i]) { + return true; + } + i++; + } + + } else if (invalid_types) { + int i = 0; + while (invalid_types[i] != NIL) { + if (p_type_from == invalid_types[i]) { + return false; + } + i++; + } + + return true; + } + + return false; +} + +bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type_to) { + if (p_type_from == p_type_to) { + return true; + } + if (p_type_to == NIL && p_type_from != NIL) { //nil can convert to anything + return true; + } + + if (p_type_from == NIL) { + return (p_type_to == OBJECT); + }; + + const Type *valid_types = nullptr; + + switch (p_type_to) { + case NIL: { + //can't, also already handled + } break; + case BOOL: { + static const Type valid[] = { + INT, + REAL, + //STRING, + NIL, + }; + + valid_types = valid; + } break; + case INT: { + static const Type valid[] = { + BOOL, + REAL, + //STRING, + NIL, + }; + + valid_types = valid; + + } break; + case REAL: { + static const Type valid[] = { + BOOL, + INT, + //STRING, + NIL, + }; + + valid_types = valid; + + } break; + case STRING: { + static const Type valid[] = { + NODE_PATH, + STRING_NAME, + NIL + }; + + valid_types = valid; + } break; + case RECT2: { + static const Type valid[] = { + RECT2I, + NIL + }; + + valid_types = valid; + } break; + case RECT2I: { + static const Type valid[] = { + RECT2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2: { + static const Type valid[] = { + VECTOR2I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2I: { + static const Type valid[] = { + VECTOR2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3: { + static const Type valid[] = { + VECTOR3I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3I: { + static const Type valid[] = { + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4: { + static const Type valid[] = { + VECTOR4I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4I: { + static const Type valid[] = { + VECTOR4, + NIL + }; + + valid_types = valid; + } break; + case PLANE: { + //Can't + } break; + case QUATERNION: { + static const Type valid[] = { + BASIS, + NIL + }; + + valid_types = valid; + } break; + case AABB: { + //Can't + } break; + case BASIS: { + static const Type valid[] = { + QUATERNION, + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM: { + static const Type valid[] = { + TRANSFORM2D, + QUATERNION, + BASIS, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM2D: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case PROJECTION: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case COLOR: { + static const Type valid[] = { + STRING, + INT, + NIL, + }; + + valid_types = valid; + } break; + case NODE_PATH: { + static const Type valid[] = { + STRING, + NIL + }; + + valid_types = valid; + } break; + case RID: { + static const Type valid[] = { + OBJECT, + NIL + }; + + valid_types = valid; + } break; + case OBJECT: { + static const Type valid[] = { + NIL + }; + + valid_types = valid; + } break; + case STRING_NAME: { + static const Type valid[] = { + STRING, + NIL + }; + + valid_types = valid; + } break; + case DICTIONARY: { + //Can't + } break; + case ARRAY: { + static const Type valid[] = { + POOL_BYTE_ARRAY, + POOL_INT_ARRAY, + POOL_STRING_ARRAY, + POOL_REAL_ARRAY, + POOL_COLOR_ARRAY, + POOL_VECTOR2_ARRAY, + POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, + POOL_VECTOR4_ARRAY, + POOL_VECTOR4I_ARRAY, + NIL + }; + + valid_types = valid; + } break; + // arrays + case POOL_BYTE_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_INT_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_REAL_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_STRING_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR2_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR2I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR3_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR3I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR4_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR4I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_COLOR_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + default: { + } + } + + if (valid_types) { + int i = 0; + while (valid_types[i] != NIL) { + if (p_type_from == valid_types[i]) { + return true; + } + i++; + } + } + + return false; +} + +bool Variant::deep_equal(const Variant &p_variant, int p_recursion_count) const { + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, true, "Max recursion reached"); + + // Containers must be handled with recursivity checks + switch (type) { + case Variant::Type::DICTIONARY: { + if (p_variant.type != Variant::Type::DICTIONARY) { + return false; + } + + const Dictionary v1_as_d = Dictionary(*this); + const Dictionary v2_as_d = Dictionary(p_variant); + + return v1_as_d.deep_equal(v2_as_d, p_recursion_count + 1); + } break; + case Variant::Type::ARRAY: { + if (p_variant.type != Variant::Type::ARRAY) { + return false; + } + + const Array v1_as_a = Array(*this); + const Array v2_as_a = Array(p_variant); + + return v1_as_a.deep_equal(v2_as_a, p_recursion_count + 1); + } break; + default: { + return *this == p_variant; + } break; + } +} + +bool Variant::operator==(const Variant &p_variant) const { + if (type != p_variant.type) { //evaluation of operator== needs to be more strict + return false; + } + bool v; + Variant r; + evaluate(OP_EQUAL, *this, p_variant, r, v); + return r; +} + +bool Variant::operator!=(const Variant &p_variant) const { + if (type != p_variant.type) { //evaluation of operator== needs to be more strict + return true; + } + bool v; + Variant r; + evaluate(OP_NOT_EQUAL, *this, p_variant, r, v); + return r; +} + +bool Variant::operator<(const Variant &p_variant) const { + if (type != p_variant.type) { //if types differ, then order by type first + return type < p_variant.type; + } + bool v; + Variant r; + evaluate(OP_LESS, *this, p_variant, r, v); + return r; +} + +bool Variant::is_zero() const { + switch (type) { + case NIL: { + return true; + } break; + + // atomic types + case BOOL: { + return !(_data._bool); + } break; + case INT: { + return _data._int == 0; + } break; + case REAL: { + return _data._real == 0; + } break; + case STRING: { + return *reinterpret_cast(_data._mem) == String(); + } break; + + // math types + case RECT2: { + return *reinterpret_cast(_data._mem) == Rect2(); + } break; + case RECT2I: { + return *reinterpret_cast(_data._mem) == Rect2i(); + } break; + case VECTOR2: { + return *reinterpret_cast(_data._mem) == Vector2(); + } break; + case VECTOR2I: { + return *reinterpret_cast(_data._mem) == Vector2i(); + } break; + case VECTOR3: { + return *reinterpret_cast(_data._mem) == Vector3(); + } break; + case VECTOR3I: { + return *reinterpret_cast(_data._mem) == Vector3i(); + } break; + case VECTOR4: { + return *reinterpret_cast(_data._mem) == Vector4(); + } break; + case VECTOR4I: { + return *reinterpret_cast(_data._mem) == Vector4i(); + } break; + + case PLANE: { + return *reinterpret_cast(_data._mem) == Plane(); + } break; + case QUATERNION: { + return *reinterpret_cast(_data._mem) == Quaternion(); + } break; + case AABB: { + return *_data._aabb == ::AABB(); + } break; + case BASIS: { + return *_data._basis == Basis(); + } break; + case TRANSFORM: { + return *_data._transform == Transform(); + } break; + case TRANSFORM2D: { + return *_data._transform2d == Transform2D(); + } break; + case PROJECTION: { + return *_data._projection == Projection(); + } break; + + // misc types + case COLOR: { + return *reinterpret_cast(_data._mem) == Color(); + } break; + case NODE_PATH: { + return reinterpret_cast(_data._mem)->is_empty(); + } break; + case RID: { + return *reinterpret_cast(_data._mem) == ::RID(); + } break; + case OBJECT: { + return _UNSAFE_OBJ_PROXY_PTR(*this) == nullptr; + } break; + case STRING_NAME: { + return *reinterpret_cast(_data._mem) != StringName(); + } break; + case DICTIONARY: { + return reinterpret_cast(_data._mem)->empty(); + } break; + case ARRAY: { + return reinterpret_cast(_data._mem)->empty(); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_INT_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_REAL_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_STRING_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR2_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR2I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR3_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR3I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR4_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR4I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_COLOR_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + default: { + } + } + + return false; +} + +bool Variant::is_one() const { + switch (type) { + case NIL: { + return true; + } break; + + // atomic types + case BOOL: { + return _data._bool; + } break; + case INT: { + return _data._int == 1; + } break; + case REAL: { + return _data._real == 1; + } break; + case RECT2: { + return *reinterpret_cast(_data._mem) == Rect2(1, 1, 1, 1); + } break; + case RECT2I: { + return *reinterpret_cast(_data._mem) == Rect2i(1, 1, 1, 1); + } break; + case VECTOR2: { + return *reinterpret_cast(_data._mem) == Vector2(1, 1); + } break; + case VECTOR2I: { + return *reinterpret_cast(_data._mem) == Vector2i(1, 1); + } break; + case VECTOR3: { + return *reinterpret_cast(_data._mem) == Vector3(1, 1, 1); + } break; + case VECTOR3I: { + return *reinterpret_cast(_data._mem) == Vector3i(1, 1, 1); + } break; + case VECTOR4: { + return *reinterpret_cast(_data._mem) == Vector4(1, 1, 1, 1); + } break; + case VECTOR4I: { + return *reinterpret_cast(_data._mem) == Vector4i(1, 1, 1, 1); + } break; + case PLANE: { + return *reinterpret_cast(_data._mem) == Plane(1, 1, 1, 1); + } break; + case COLOR: { + return *reinterpret_cast(_data._mem) == Color(1, 1, 1, 1); + } break; + + default: { + return !is_zero(); + } + } + + return false; +} + +ObjectID Variant::get_object_instance_id() const { + if (unlikely(type != OBJECT)) { + return 0; + } else if (likely(_get_obj().rc)) { + return _get_obj().rc->instance_id; + } else if (likely(!_get_obj().ref.is_null())) { + return _REF_OBJ_PTR(*this)->get_instance_id(); + } else { + return 0; + } +} + +bool Variant::is_invalid_object() const { + return type == OBJECT && _get_obj().rc && !_get_obj().rc->get_ptr(); +} + +void Variant::reference(const Variant &p_variant) { + switch (type) { + case NIL: + case BOOL: + case INT: + case REAL: + break; + default: + clear(); + } + + type = p_variant.type; + + switch (p_variant.type) { + case NIL: { + // none + } break; + + // atomic types + case BOOL: { + _data._bool = p_variant._data._bool; + } break; + case INT: { + _data._int = p_variant._data._int; + } break; + case REAL: { + _data._real = p_variant._data._real; + } break; + case STRING: { + memnew_placement(_data._mem, String(*reinterpret_cast(p_variant._data._mem))); + } break; + + // math types + case RECT2: { + memnew_placement(_data._mem, Rect2(*reinterpret_cast(p_variant._data._mem))); + } break; + case RECT2I: { + memnew_placement(_data._mem, Rect2i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR2: { + memnew_placement(_data._mem, Vector2(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR2I: { + memnew_placement(_data._mem, Vector2i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR3: { + memnew_placement(_data._mem, Vector3(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR3I: { + memnew_placement(_data._mem, Vector3i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR4: { + memnew_placement(_data._mem, Vector4(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR4I: { + memnew_placement(_data._mem, Vector4i(*reinterpret_cast(p_variant._data._mem))); + } break; + + case PLANE: { + memnew_placement(_data._mem, Plane(*reinterpret_cast(p_variant._data._mem))); + } break; + case QUATERNION: { + memnew_placement(_data._mem, Quaternion(*reinterpret_cast(p_variant._data._mem))); + } break; + case AABB: { + _data._aabb = memnew(::AABB(*p_variant._data._aabb)); + } break; + case BASIS: { + _data._basis = memnew(Basis(*p_variant._data._basis)); + } break; + case TRANSFORM: { + _data._transform = memnew(Transform(*p_variant._data._transform)); + } break; + case TRANSFORM2D: { + _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); + } break; + case PROJECTION: { + _data._projection = memnew(Projection(*p_variant._data._projection)); + } break; + + // misc types + case COLOR: { + memnew_placement(_data._mem, Color(*reinterpret_cast(p_variant._data._mem))); + } break; + case NODE_PATH: { + memnew_placement(_data._mem, NodePath(*reinterpret_cast(p_variant._data._mem))); + } break; + case RID: { + memnew_placement(_data._mem, ::RID(*reinterpret_cast(p_variant._data._mem))); + } break; + case OBJECT: { + memnew_placement(_data._mem, ObjData(p_variant._get_obj())); + if (likely(_get_obj().rc)) { + _get_obj().rc->increment(); + } + } break; + case STRING_NAME: { + memnew_placement(_data._mem, StringName(*reinterpret_cast(p_variant._data._mem))); + } break; + case DICTIONARY: { + memnew_placement(_data._mem, Dictionary(*reinterpret_cast(p_variant._data._mem))); + } break; + case ARRAY: { + memnew_placement(_data._mem, Array(*reinterpret_cast(p_variant._data._mem))); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_INT_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_REAL_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_STRING_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR2_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR2I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR3_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR3I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR4_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR4I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_COLOR_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + default: { + } + } +} + +void Variant::zero() { + switch (type) { + case NIL: + break; + case BOOL: + this->_data._bool = false; + break; + case INT: + this->_data._int = 0; + break; + case REAL: + this->_data._real = 0; + break; + case RECT2: + *reinterpret_cast(this->_data._mem) = Rect2(); + break; + case RECT2I: + *reinterpret_cast(this->_data._mem) = Rect2i(); + break; + case VECTOR2: + *reinterpret_cast(this->_data._mem) = Vector2(); + break; + case VECTOR2I: + *reinterpret_cast(this->_data._mem) = Vector2i(); + break; + case VECTOR3: + *reinterpret_cast(this->_data._mem) = Vector3(); + break; + case VECTOR3I: + *reinterpret_cast(this->_data._mem) = Vector3i(); + break; + case VECTOR4: + *reinterpret_cast(this->_data._mem) = Vector4(); + break; + case VECTOR4I: + *reinterpret_cast(this->_data._mem) = Vector4i(); + break; + case PLANE: + *reinterpret_cast(this->_data._mem) = Plane(); + break; + case QUATERNION: + *reinterpret_cast(this->_data._mem) = Quaternion(); + break; + case AABB: + *reinterpret_cast<::AABB *>(this->_data._mem) = ::AABB(); + break; + case COLOR: + *reinterpret_cast(this->_data._mem) = Color(); + break; + case PROJECTION: + *reinterpret_cast(this->_data._mem) = Projection(); + break; + default: + this->clear(); + break; + } } void Variant::clear() { - switch (_type) { - case TYPE_NULL: - break; - case TYPE_BOOL: - _bool = false; - break; - case TYPE_INT: - _int = 0; - break; - case TYPE_UINT: - _uint = 0; - break; - case TYPE_FLOAT: - _float = 0; - break; - case TYPE_STRING: - if (_string->owner) { - delete _string->string; - } + switch (type) { + /* + // no point, they don't allocate memory + BOOL, + INT, + REAL, + */ + case STRING: { + reinterpret_cast(_data._mem)->~String(); + } break; + /* + RECT2, + RECT2I + VECTOR2, + VECTOR2I, + VECTOR3, + VECTOR3i, + VECTOR4, + VECTOR4i, - delete _string; - _string = nullptr; + PLANE, + QUATERNION, + */ + case AABB: { + memdelete(_data._aabb); + } break; + case BASIS: { + memdelete(_data._basis); + } break; + case TRANSFORM: { + memdelete(_data._transform); + } break; + case TRANSFORM2D: { + memdelete(_data._transform2d); + } break; + case PROJECTION: { + memdelete(_data._projection); + } break; + //COLOR - break; - case TYPE_OBJECT: - delete _object; - _object = nullptr; - - break; - case TYPE_POINTER: - _pointer = nullptr; - - break; - default: - break; - } - - _type = TYPE_NULL; -} -void Variant::zero() { - switch (_type) { - case TYPE_NULL: - break; - case TYPE_BOOL: - _bool = false; - break; - case TYPE_INT: - _int = 0; - break; - case TYPE_UINT: - _uint = 0; - break; - case TYPE_FLOAT: - _float = 0; - break; - case TYPE_STRING: - _string->string->resize(0); - break; - case TYPE_OBJECT: - _object->object = nullptr; - _object->reference.unref(); - break; - case TYPE_POINTER: - _pointer = nullptr; - break; - default: - break; - } -} - -void Variant::parse(const String &str) { - if (str.is_int()) { - set_int(str.to_int()); - return; - } - - if (str.is_uint()) { - set_uint(str.to_uint()); - return; - } - - if (str.is_numeric()) { - set_float(str.to_float()); - return; - } - - if (str.is_bool()) { - set_bool(str.to_bool()); - return; - } - - set_string(str); -} -Variant Variant::parse_string(const String &str) { - Variant v = Variant(); - - v.parse(str); - - return v; -} - -bool Variant::is_null() const { - return _type == TYPE_NULL; -} -bool Variant::is_bool() const { - return _type == TYPE_BOOL; -} -bool Variant::is_int() const { - return _type == TYPE_INT; -} -bool Variant::is_uint() const { - return _type == TYPE_UINT; -} -bool Variant::is_float() const { - return _type == TYPE_FLOAT; -} -bool Variant::is_numeric() const { - return _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT; -} -bool Variant::is_string() const { - return _type == TYPE_STRING; -} -bool Variant::is_object() const { - return _type == TYPE_OBJECT; -} -bool Variant::is_pointer() const { - return _type == TYPE_POINTER; -} -bool Variant::is_reference() const { - if (_type == TYPE_OBJECT) { - return _object->reference.is_valid(); - } - - return false; -} - -bool Variant::is_primitive_type() const { - return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT; -} - -bool Variant::is_simple_type() const { - return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT || _type == TYPE_STRING; -} - -bool Variant::to_bool() const { - return _bool; -} -int Variant::to_int() const { - switch (_type) { - case TYPE_NULL: - return 0; - case TYPE_BOOL: - if (_bool) { - return 1; + // misc types + case NODE_PATH: { + reinterpret_cast(_data._mem)->~NodePath(); + } break; + case RID: { + // not much need probably + reinterpret_cast<::RID *>(_data._mem)->~RID(); + } break; + case OBJECT: { + if (likely(_get_obj().rc)) { + if (unlikely(_get_obj().rc->decrement())) { + memdelete(_get_obj().rc); + } } else { - return 0; + _get_obj().ref.unref(); } - case TYPE_INT: - case TYPE_UINT: - return _int; - case TYPE_FLOAT: - return static_cast(_int); - case TYPE_STRING: - return _string->string->to_int(); - case TYPE_OBJECT: - case TYPE_POINTER: - // just read the value of the pointer as int - // Could return 1 or 0, but this is almost the same, but hopefully it's more useful - return _int; - default: + } break; + case STRING_NAME: { + reinterpret_cast(_data._mem)->~StringName(); + } break; + case DICTIONARY: { + reinterpret_cast(_data._mem)->~Dictionary(); + } break; + case ARRAY: { + reinterpret_cast(_data._mem)->~Array(); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_INT_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_REAL_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_STRING_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR2_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR2I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR3_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR3I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR4_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR4I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_COLOR_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + default: { + } /* not needed */ + } + + type = NIL; +} + +Variant::operator signed int() const { + switch (type) { + case NIL: return 0; - } -} -uint64_t Variant::to_uint() const { - switch (_type) { - case TYPE_NULL: + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { return 0; - case TYPE_BOOL: - if (_bool) { - return 1; - } else { - return 0; - } - case TYPE_INT: - case TYPE_UINT: - return _uint; - case TYPE_FLOAT: - return static_cast(_float); - case TYPE_STRING: - return _string->string->to_uint(); - case TYPE_OBJECT: - case TYPE_POINTER: - // just read the value of the pointer as uint - // Could return 1 or 0, but this is almost the same, but hopefully it's more useful - return _uint; - default: + } + } +} +Variant::operator unsigned int() const { + switch (type) { + case NIL: return 0; - } -} -float Variant::to_float() const { - switch (_type) { - case TYPE_NULL: + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { return 0; - case TYPE_BOOL: - if (_bool) { - return 0; - } else { - return 1; - } - case TYPE_INT: - return static_cast(_int); - case TYPE_UINT: - return static_cast(_uint); - case TYPE_FLOAT: - return _float; - case TYPE_STRING: - return _string->string->to_float(); - case TYPE_OBJECT: - case TYPE_POINTER: - if (_uint) { - return 1; - } else { - return 0; - } - default: + } + } +} + +Variant::operator int64_t() const { + switch (type) { + case NIL: return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int64(); + default: { + return 0; + } } } -String Variant::to_string() const { - switch (_type) { - case TYPE_NULL: - return "NULL"; - case TYPE_BOOL: - if (Math::is_zero_approx(_float)) { - return "false"; - } else { - return "true"; - } - case TYPE_INT: - return String::num(_int); - case TYPE_UINT: - return String::num(_uint); - case TYPE_FLOAT: - return String::num(_float); - case TYPE_STRING: - return *(_string->string); - case TYPE_OBJECT: - case TYPE_POINTER: - if (_uint) { - return "[ Object ]"; - } else { - return "[ Object (NULL) ]"; - } - default: - return ""; - } -} -Object *Variant::to_object() const { - switch (_type) { - case TYPE_NULL: - return nullptr; - case TYPE_BOOL: - return nullptr; - case TYPE_INT: - return nullptr; - case TYPE_UINT: - return nullptr; - case TYPE_FLOAT: - return nullptr; - case TYPE_STRING: - return nullptr; - case TYPE_OBJECT: - return _object->object; - case TYPE_POINTER: - return nullptr; - default: - return nullptr; - } -} -Reference *Variant::to_reference() const { - switch (_type) { - case TYPE_NULL: - return nullptr; - case TYPE_BOOL: - return nullptr; - case TYPE_INT: - return nullptr; - case TYPE_UINT: - return nullptr; - case TYPE_FLOAT: - return nullptr; - case TYPE_STRING: - return nullptr; - case TYPE_OBJECT: - return Object::cast_to(_object->object); - case TYPE_POINTER: - return nullptr; - default: - return nullptr; - } -} -void *Variant::to_pointer() const { - switch (_type) { - case TYPE_NULL: - return nullptr; - case TYPE_BOOL: - return nullptr; - case TYPE_INT: - return nullptr; - case TYPE_UINT: - return nullptr; - case TYPE_FLOAT: - return nullptr; - case TYPE_STRING: - return nullptr; - case TYPE_OBJECT: - return nullptr; - case TYPE_POINTER: - return _pointer; - default: - return nullptr; - } -} -String *Variant::get_string_ptr() const { - if (_type == TYPE_STRING) { - return _string->string; + +/* +Variant::operator long unsigned int() const { + + switch( type ) { + + case NIL: return 0; + case BOOL: return _data._bool ? 1 : 0; + case INT: return _data._int; + case REAL: return _data._real; + case STRING: return operator String().to_int(); + default: { + + return 0; + } } - return nullptr; -} -bool Variant::is_string_owned() const { - if (_type == TYPE_STRING) { - return _string->owner; - } + return 0; +}; +*/ - return false; -} - -void Variant::set_null() { - clear(); - - _type = TYPE_NULL; -} -void Variant::set_bool(const bool value) { - clear(); - - _type = TYPE_BOOL; - _bool = value; -} -void Variant::set_int(const int value) { - clear(); - - _type = TYPE_INT; - _int = value; -} -void Variant::set_uint(const uint64_t value) { - clear(); - - _type = TYPE_UINT; - _uint = value; -} -void Variant::set_float(const float value) { - clear(); - - _type = TYPE_FLOAT; - _float = value; -} -void Variant::set_float(const double value) { - clear(); - - _type = TYPE_FLOAT; - _float = value; -} -void Variant::set_string(String *value, const bool copy) { - clear(); - - if (!value) { - return; - } - - _type = TYPE_STRING; - - _string = new StringData(); - - if (copy) { - _string->string = new String(*value); - _string->owner = true; - } else { - _string->string = value; - _string->owner = false; - } -} -void Variant::set_string(const String &value, const bool copy) { - clear(); - - _type = TYPE_STRING; - - _string = new StringData(); - - if (copy) { - _string->string = new String(value); - _string->owner = true; - } else { - _string->string = &const_cast(value); - _string->owner = false; - } -} -void Variant::set_object(Object *value) { - clear(); - - if (!value) { - return; - } - - _object = new ObjectData(); - _object->object = value; - - if (value->is_class_ptr(Reference::get_class_ptr_static())) { - _object->reference = Ref(Object::cast_to(value)); - } -} -void Variant::set_pointer(void *value) { - clear(); - - _type = TYPE_POINTER; - _pointer = value; -} -void Variant::set_variant(const Variant &value) { - clear(); - - switch (value._type) { - case TYPE_NULL: - break; - case TYPE_BOOL: - _bool = value._bool; - break; - case TYPE_INT: - _int = value._int; - break; - case TYPE_UINT: - _uint = value._uint; - break; - case TYPE_FLOAT: - _float = value._float; - break; - case TYPE_STRING: - set_string(value._string->string, true); - break; - case TYPE_OBJECT: - set_object(value._object->object); - break; - case TYPE_POINTER: - _pointer = value._pointer; - default: - break; - } - - _type = value._type; -} - -Variant::operator bool() const { - return to_bool(); -} -Variant::operator int() const { - return to_int(); -} Variant::operator uint64_t() const { - return to_uint(); + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } } + +#ifdef NEED_LONG_INT +Variant::operator signed long() const { + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } + + return 0; +}; + +Variant::operator unsigned long() const { + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } + + return 0; +}; +#endif + +Variant::operator signed short() const { + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } +} +Variant::operator unsigned short() const { + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } +} +Variant::operator signed char() const { + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } +} +Variant::operator unsigned char() const { + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1 : 0; + case INT: + return _data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_int(); + default: { + return 0; + } + } +} + +Variant::operator CharType() const { + return operator unsigned int(); +} + Variant::operator float() const { - return to_float(); + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1.0 : 0.0; + case INT: + return (float)_data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_double(); + default: { + return 0; + } + } } Variant::operator double() const { - return to_float(); -} -Variant::operator String() const { - return to_string(); -} -Variant::operator Object *() const { - return to_object(); -} -Variant::operator Reference *() const { - return to_reference(); -} -Variant::operator void *() const { - return to_pointer(); + switch (type) { + case NIL: + return 0; + case BOOL: + return _data._bool ? 1.0 : 0.0; + case INT: + return (double)_data._int; + case REAL: + return _data._real; + case STRING: + return operator String().to_double(); + default: { + return 0; + } + } } -void Variant::operator=(const Variant &other) { - set_variant(other); +Variant::operator StringName() const { + if (type == STRING_NAME) { + return *reinterpret_cast(_data._mem); + } else if (type == NODE_PATH) { + return reinterpret_cast(_data._mem)->get_sname(); + } + + return StringName(operator String()); } -bool Variant::operator==(const Variant &other) const { - if (_type != other._type) { + +struct _VariantStrPair { + String key; + String value; + + bool operator<(const _VariantStrPair &p) const { + return key < p.key; + } +}; + +Variant::operator String() const { + List stack; + + return stringify(stack); +} + +template +String stringify_vector(const T &vec, List &stack) { + String str("["); + for (int i = 0; i < vec.size(); i++) { + if (i > 0) { + str += ", "; + } + str = str + Variant(vec[i]).stringify(stack); + } + str += "]"; + return str; +} + +String Variant::stringify(List &stack) const { + switch (type) { + case NIL: + return "Null"; + case BOOL: + return _data._bool ? "True" : "False"; + case INT: + return itos(_data._int); + case REAL: + return rtos(_data._real); + case STRING: + return *reinterpret_cast(_data._mem); + case RECT2: + return operator Rect2(); + case RECT2I: + return operator Rect2i(); + case VECTOR2: + return operator Vector2(); + case VECTOR2I: + return operator Vector2i(); + case VECTOR3: + return operator Vector3(); + case VECTOR3I: + return operator Vector3i(); + case VECTOR4: + return operator Vector4(); + case VECTOR4I: + return operator Vector4i(); + case PLANE: + return operator Plane(); + case QUATERNION: + return operator Quaternion(); + case AABB: + return operator ::AABB(); + case BASIS: { + return operator Basis(); + } break; + case TRANSFORM: + return operator Transform(); + case TRANSFORM2D: { + return operator Transform2D(); + } break; + case PROJECTION: + return operator Projection(); + case COLOR: + return operator Color(); + case NODE_PATH: + return operator NodePath(); + //RID + case OBJECT: { + Object *obj = _OBJ_PTR(*this); + if (likely(obj)) { + return obj->to_string(); + } else { + if (_get_obj().rc) { + return "[Deleted Object]"; + } + return "[Object:null]"; + } + } break; + case STRING_NAME: + return operator StringName(); + case DICTIONARY: { + const Dictionary &d = *reinterpret_cast(_data._mem); + if (stack.find(d.id())) { + return "{...}"; + } + + stack.push_back(d.id()); + + //const String *K=NULL; + String str("{"); + List keys; + d.get_key_list(&keys); + + Vector<_VariantStrPair> pairs; + + for (List::Element *E = keys.front(); E; E = E->next()) { + _VariantStrPair sp; + sp.key = E->get().stringify(stack); + sp.value = d[E->get()].stringify(stack); + + pairs.push_back(sp); + } + + pairs.sort(); + + for (int i = 0; i < pairs.size(); i++) { + if (i > 0) { + str += ", "; + } + str += pairs[i].key + ":" + pairs[i].value; + } + str += "}"; + + stack.erase(d.id()); + return str; + } break; + case ARRAY: { + Array arr = operator Array(); + if (stack.find(arr.id())) { + return "[...]"; + } + stack.push_back(arr.id()); + String str = stringify_vector(arr, stack); + stack.erase(arr.id()); + return str; + + } break; + + case POOL_BYTE_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_INT_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_REAL_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_STRING_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR2_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR2I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR3_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR3I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR4_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR4I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_COLOR_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + + default: { + return "[" + get_type_name(type) + "]"; + } + } + + return ""; +} + +Variant::operator Rect2() const { + if (type == RECT2) { + return *reinterpret_cast(_data._mem); + } else if (type == RECT2I) { + return Rect2(*reinterpret_cast(_data._mem)); + } else { + return Rect2(); + } +} +Variant::operator Rect2i() const { + if (type == RECT2I) { + return *reinterpret_cast(_data._mem); + } else if (type == RECT2) { + return Rect2i(*reinterpret_cast(_data._mem)); + } else { + return Rect2i(); + } +} + +Variant::operator Vector2() const { + if (type == VECTOR2) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else { + return Vector2(); + } +} +Variant::operator Vector2i() const { + if (type == VECTOR2I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3I) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4I) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else { + return Vector2i(); + } +} + +Variant::operator Vector3() const { + if (type == VECTOR3) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3I) { + return Vector3(*reinterpret_cast(_data._mem)); + } else if (type == VECTOR2) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR2I) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR4) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR4I) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else { + return Vector3(); + } +} +Variant::operator Vector3i() const { + if (type == VECTOR3I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR2) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR2I) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR4) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR4I) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else { + return Vector3i(); + } +} + +Variant::operator Vector4() const { + if (type == VECTOR4) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR4I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR2I) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR3) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else if (type == VECTOR3I) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else { + return Vector4(); + } +} + +Variant::operator Vector4i() const { + if (type == VECTOR4I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR4) { + const Vector4 &v4 = *reinterpret_cast(_data._mem); + return Vector4i(v4.x, v4.y, v4.z, v4.w); + } else if (type == VECTOR2) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR2I) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR3) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else if (type == VECTOR3I) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else { + return Vector4i(); + } +} + +Variant::operator Plane() const { + if (type == PLANE) { + return *reinterpret_cast(_data._mem); + } else { + return Plane(); + } +} +Variant::operator ::AABB() const { + if (type == AABB) { + return *_data._aabb; + } else { + return ::AABB(); + } +} + +Variant::operator Basis() const { + if (type == BASIS) { + return *_data._basis; + } else if (type == QUATERNION) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3) { + return Basis(*reinterpret_cast(_data._mem)); + } else if (type == TRANSFORM) { // unexposed in Variant::can_convert? + return _data._transform->basis; + } else { + return Basis(); + } +} + +Variant::operator Quaternion() const { + if (type == QUATERNION) { + return *reinterpret_cast(_data._mem); + } else if (type == BASIS) { + return *_data._basis; + } else if (type == TRANSFORM) { + return _data._transform->basis; + } else { + return Quaternion(); + } +} + +Variant::operator Transform2D() const { + if (type == TRANSFORM2D) { + return *_data._transform2d; + } else if (type == TRANSFORM) { + const Transform &t = *_data._transform; + Transform2D m; + m.columns[0][0] = t.basis.rows[0][0]; + m.columns[0][1] = t.basis.rows[1][0]; + m.columns[1][0] = t.basis.rows[0][1]; + m.columns[1][1] = t.basis.rows[1][1]; + m.columns[2][0] = t.origin[0]; + m.columns[2][1] = t.origin[1]; + return m; + } else { + return Transform2D(); + } +} + +Variant::operator Transform() const { + if (type == TRANSFORM) { + return *_data._transform; + } else if (type == BASIS) { + return Transform(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform(Basis(*reinterpret_cast(_data._mem)), Vector3()); + } else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.rows[0][0] = t.columns[0][0]; + m.basis.rows[1][0] = t.columns[0][1]; + m.basis.rows[0][1] = t.columns[1][0]; + m.basis.rows[1][1] = t.columns[1][1]; + m.origin[0] = t.columns[2][0]; + m.origin[1] = t.columns[2][1]; + return m; + } else if (type == PROJECTION) { + return *_data._projection; + } else { + return Transform(); + } +} + +Variant::operator Projection() const { + if (type == TRANSFORM) { + return *_data._transform; + } else if (type == BASIS) { + return Transform(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform(Basis(*reinterpret_cast(_data._mem)), Vector3()); + } else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.rows[0][0] = t.columns[0][0]; + m.basis.rows[1][0] = t.columns[0][1]; + m.basis.rows[0][1] = t.columns[1][0]; + m.basis.rows[1][1] = t.columns[1][1]; + m.origin[0] = t.columns[2][0]; + m.origin[1] = t.columns[2][1]; + return m; + } else if (type == PROJECTION) { + return *_data._projection; + } else { + return Projection(); + } +} + +Variant::operator Color() const { + if (type == COLOR) { + return *reinterpret_cast(_data._mem); + } else if (type == STRING) { + return Color::html(operator String()); + } else if (type == INT) { + return Color::hex(operator int()); + } else { + return Color(); + } +} + +Variant::operator NodePath() const { + if (type == NODE_PATH) { + return *reinterpret_cast(_data._mem); + } else if (type == STRING) { + return NodePath(operator String()); + } else { + return NodePath(); + } +} + +Variant::operator RefPtr() const { + if (type == OBJECT) { + return _get_obj().ref; + } else { + return RefPtr(); + } +} + +Variant::operator ::RID() const { + if (type == RID) { + return *reinterpret_cast(_data._mem); + } else if (type == OBJECT) { + if (!_get_obj().ref.is_null()) { + return _get_obj().ref.get_rid(); + } else { + Object *obj = likely(_get_obj().rc) ? _get_obj().rc->get_ptr() : nullptr; + if (unlikely(!obj)) { + if (_get_obj().rc) { + ERR_PRINT("Attempted get RID on a deleted object."); + } + return ::RID(); + } + Variant::CallError ce; + Variant ret = obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce); + if (ce.error == Variant::CallError::CALL_OK && ret.get_type() == Variant::RID) { + return ret; + } else { + return ::RID(); + } + } + } else { + return ::RID(); + } +} + +Variant::operator Object *() const { + if (type == OBJECT) { + return _OBJ_PTR(*this); + } else { + return nullptr; + } +} +Variant::operator Node *() const { + if (type == OBJECT) { + Object *obj = _get_obj().rc ? _get_obj().rc->get_ptr() : nullptr; + return Object::cast_to(obj); + } + return nullptr; +} +Variant::operator Control *() const { + if (type == OBJECT) { + Object *obj = _get_obj().rc ? _get_obj().rc->get_ptr() : nullptr; + return Object::cast_to(obj); + } + return nullptr; +} + +Variant::operator Dictionary() const { + if (type == DICTIONARY) { + return *reinterpret_cast(_data._mem); + } else { + return Dictionary(); + } +} + +template +inline DA _convert_array(const SA &p_array) { + DA da; + da.resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + da.set(i, Variant(p_array.get(i))); + } + + return da; +} + +template +inline DA _convert_array_from_variant(const Variant &p_variant) { + switch (p_variant.get_type()) { + case Variant::ARRAY: { + return _convert_array(p_variant.operator Array()); + } + case Variant::POOL_BYTE_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_INT_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_REAL_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_STRING_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR2_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR2I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR3_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR3I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR4_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR4I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_COLOR_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + default: { + return DA(); + } + } +} + +Variant::operator Array() const { + if (type == ARRAY) { + return *reinterpret_cast(_data._mem); + } else { + return _convert_array_from_variant(*this); + } +} + +Variant::operator PoolVector() const { + if (type == POOL_BYTE_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_INT_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_REAL_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} + +Variant::operator PoolVector() const { + if (type == POOL_STRING_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR2_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR2I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR3_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR3I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR4_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR4I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_COLOR_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} + +/* helpers */ + +Variant::operator Vector<::RID>() const { + Array va = operator Array(); + Vector<::RID> rids; + rids.resize(va.size()); + for (int i = 0; i < rids.size(); i++) { + rids.write[i] = va[i]; + } + return rids; +} + +Variant::operator PoolVector() const { + Array va = operator Array(); + PoolVector planes; + int va_size = va.size(); + if (va_size == 0) { + return planes; + } + + planes.resize(va_size); + PoolVector::Write w = planes.write(); + + for (int i = 0; i < va_size; i++) { + w[i] = va[i]; + } + + return planes; +} + +Variant::operator PoolVector() const { + PoolVector va = operator PoolVector(); + PoolVector faces; + int va_size = va.size(); + if (va_size == 0) { + return faces; + } + + faces.resize(va_size / 3); + PoolVector::Write w = faces.write(); + PoolVector::Read r = va.read(); + + for (int i = 0; i < va_size; i++) { + w[i / 3].vertex[i % 3] = r[i]; + } + + return faces; +} + +Variant::operator Vector() const { + Array va = operator Array(); + Vector planes; + int va_size = va.size(); + if (va_size == 0) { + return planes; + } + + planes.resize(va_size); + + for (int i = 0; i < va_size; i++) { + planes.write[i] = va[i]; + } + + return planes; +} + +Variant::operator Vector() const { + Array from = operator Array(); + Vector to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + to.write[i] = from[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + to.write[i] = from[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + to.write[i] = from[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + to.write[i] = from[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + to.write[i] = from[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + to.write[i] = from[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector2 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector2i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector3 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector3i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector4 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector4i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Color *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Margin() const { + return (Margin) operator int(); +} +Variant::operator Side() const { + return (Side) operator int(); +} +Variant::operator Orientation() const { + return (Orientation) operator int(); +} + +Variant::operator IP_Address() const { + if (type == POOL_REAL_ARRAY || type == POOL_INT_ARRAY || type == POOL_BYTE_ARRAY) { + PoolVector addr = operator PoolVector(); + if (addr.size() == 4) { + return IP_Address(addr.get(0), addr.get(1), addr.get(2), addr.get(3)); + } + } + + return IP_Address(operator String()); +} + +Variant::Variant(bool p_bool) { + type = BOOL; + _data._bool = p_bool; +} + +/* +Variant::Variant(long unsigned int p_long) { + + type=INT; + _data._int=p_long; +}; +*/ + +Variant::Variant(signed int p_int) { + type = INT; + _data._int = p_int; +} +Variant::Variant(unsigned int p_int) { + type = INT; + _data._int = p_int; +} + +#ifdef NEED_LONG_INT + +Variant::Variant(signed long p_int) { + type = INT; + _data._int = p_int; +} +Variant::Variant(unsigned long p_int) { + type = INT; + _data._int = p_int; +} +#endif + +Variant::Variant(int64_t p_int) { + type = INT; + _data._int = p_int; +} + +Variant::Variant(uint64_t p_int) { + type = INT; + _data._int = p_int; +} + +Variant::Variant(signed short p_short) { + type = INT; + _data._int = p_short; +} +Variant::Variant(unsigned short p_short) { + type = INT; + _data._int = p_short; +} +Variant::Variant(signed char p_char) { + type = INT; + _data._int = p_char; +} +Variant::Variant(unsigned char p_char) { + type = INT; + _data._int = p_char; +} +Variant::Variant(float p_float) { + type = REAL; + _data._real = p_float; +} +Variant::Variant(double p_double) { + type = REAL; + _data._real = p_double; +} + +Variant::Variant(const StringName &p_string) { + type = STRING_NAME; + memnew_placement(_data._mem, StringName(p_string)); +} +Variant::Variant(const String &p_string) { + type = STRING; + memnew_placement(_data._mem, String(p_string)); +} + +Variant::Variant(const char *const p_cstring) { + type = STRING; + memnew_placement(_data._mem, String((const char *)p_cstring)); +} + +Variant::Variant(const CharType *p_wstring) { + type = STRING; + memnew_placement(_data._mem, String(p_wstring)); +} + +Variant::Variant(const Rect2 &p_rect2) { + type = RECT2; + memnew_placement(_data._mem, Rect2(p_rect2)); +} +Variant::Variant(const Rect2i &p_rect2) { + type = RECT2I; + memnew_placement(_data._mem, Rect2i(p_rect2)); +} + +Variant::Variant(const Vector2 &p_vector2) { + type = VECTOR2; + memnew_placement(_data._mem, Vector2(p_vector2)); +} +Variant::Variant(const Vector2i &p_vector2) { + type = VECTOR2I; + memnew_placement(_data._mem, Vector2i(p_vector2)); +} + +Variant::Variant(const Vector3 &p_vector3) { + type = VECTOR3; + memnew_placement(_data._mem, Vector3(p_vector3)); +} +Variant::Variant(const Vector3i &p_vector3) { + type = VECTOR3I; + memnew_placement(_data._mem, Vector3i(p_vector3)); +} + +Variant::Variant(const Vector4 &p_vector4) { + type = VECTOR4; + memnew_placement(_data._mem, Vector4(p_vector4)); +} +Variant::Variant(const Vector4i &p_vector4) { + type = VECTOR4I; + memnew_placement(_data._mem, Vector4i(p_vector4)); +} + +Variant::Variant(const Plane &p_plane) { + type = PLANE; + memnew_placement(_data._mem, Plane(p_plane)); +} +Variant::Variant(const ::AABB &p_aabb) { + type = AABB; + _data._aabb = memnew(::AABB(p_aabb)); +} + +Variant::Variant(const Basis &p_matrix) { + type = BASIS; + _data._basis = memnew(Basis(p_matrix)); +} + +Variant::Variant(const Quaternion &p_quat) { + type = QUATERNION; + memnew_placement(_data._mem, Quaternion(p_quat)); +} +Variant::Variant(const Transform &p_transform) { + type = TRANSFORM; + _data._transform = memnew(Transform(p_transform)); +} + +Variant::Variant(const Transform2D &p_transform) { + type = TRANSFORM2D; + _data._transform2d = memnew(Transform2D(p_transform)); +} + +Variant::Variant(const Projection &p_projection) { + type = PROJECTION; + _data._projection = memnew(Projection(p_projection)); +} + +Variant::Variant(const Color &p_color) { + type = COLOR; + memnew_placement(_data._mem, Color(p_color)); +} + +Variant::Variant(const NodePath &p_node_path) { + type = NODE_PATH; + memnew_placement(_data._mem, NodePath(p_node_path)); +} + +Variant::Variant(const RefPtr &p_resource) { + type = OBJECT; + memnew_placement(_data._mem, ObjData); + _get_obj().rc = nullptr; + _get_obj().ref = p_resource; +} + +Variant::Variant(const ::RID &p_rid) { + type = RID; + memnew_placement(_data._mem, ::RID(p_rid)); +} + +Variant::Variant(const Object *p_object) { + type = OBJECT; + Object *obj = const_cast(p_object); + + memnew_placement(_data._mem, ObjData); + Reference *ref = Object::cast_to(obj); + if (unlikely(ref)) { + *reinterpret_cast *>(_get_obj().ref.get_data()) = Ref(ref); + _get_obj().rc = nullptr; + } else { + _get_obj().rc = likely(obj) ? obj->_use_rc() : nullptr; + } +} + +Variant::Variant(const Dictionary &p_dictionary) { + type = DICTIONARY; + memnew_placement(_data._mem, Dictionary(p_dictionary)); +} + +Variant::Variant(const Array &p_array) { + type = ARRAY; + memnew_placement(_data._mem, Array(p_array)); +} + +Variant::Variant(const PoolVector &p_array) { + type = ARRAY; + + Array *plane_array = memnew_placement(_data._mem, Array); + + plane_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + plane_array->operator[](i) = Variant(p_array[i]); + } +} + +Variant::Variant(const Vector &p_array) { + type = ARRAY; + + Array *plane_array = memnew_placement(_data._mem, Array); + + plane_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + plane_array->operator[](i) = Variant(p_array[i]); + } +} + +Variant::Variant(const Vector<::RID> &p_array) { + type = ARRAY; + + Array *rid_array = memnew_placement(_data._mem, Array); + + rid_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + rid_array->set(i, Variant(p_array[i])); + } +} + +Variant::Variant(const PoolVector &p_raw_array) { + type = POOL_BYTE_ARRAY; + memnew_placement(_data._mem, PoolVector(p_raw_array)); +} +Variant::Variant(const PoolVector &p_int_array) { + type = POOL_INT_ARRAY; + memnew_placement(_data._mem, PoolVector(p_int_array)); +} +Variant::Variant(const PoolVector &p_real_array) { + type = POOL_REAL_ARRAY; + memnew_placement(_data._mem, PoolVector(p_real_array)); +} +Variant::Variant(const PoolVector &p_string_array) { + type = POOL_STRING_ARRAY; + memnew_placement(_data._mem, PoolVector(p_string_array)); +} +Variant::Variant(const PoolVector &p_vector2_array) { + type = POOL_VECTOR2_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector2_array)); +} +Variant::Variant(const PoolVector &p_vector2_array) { + type = POOL_VECTOR2I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector2_array)); +} +Variant::Variant(const PoolVector &p_vector3_array) { + type = POOL_VECTOR3_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector3_array)); +} +Variant::Variant(const PoolVector &p_vector3_array) { + type = POOL_VECTOR3I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector3_array)); +} + +Variant::Variant(const PoolVector &p_vector4_array) { + type = POOL_VECTOR4_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector4_array)); +} +Variant::Variant(const PoolVector &p_vector4_array) { + type = POOL_VECTOR4I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector4_array)); +} + +Variant::Variant(const PoolVector &p_color_array) { + type = POOL_COLOR_ARRAY; + memnew_placement(_data._mem, PoolVector(p_color_array)); +} + +Variant::Variant(const PoolVector &p_face_array) { + PoolVector vertices; + int face_count = p_face_array.size(); + vertices.resize(face_count * 3); + + if (face_count) { + PoolVector::Read r = p_face_array.read(); + PoolVector::Write w = vertices.write(); + + for (int i = 0; i < face_count; i++) { + for (int j = 0; j < 3; j++) { + w[i * 3 + j] = r[i].vertex[j]; + } + } + } + + type = NIL; + + *this = vertices; +} + +/* helpers */ + +Variant::Variant(const Vector &p_array) { + type = NIL; + Array v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector2 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector2i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector3 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector3i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector4 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector4i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + +void Variant::operator=(const Variant &p_variant) { + if (unlikely(this == &p_variant)) { + return; + } + + if (unlikely(type != p_variant.type)) { + reference(p_variant); + return; + } + + switch (p_variant.type) { + case NIL: { + // none + } break; + + // atomic types + case BOOL: { + _data._bool = p_variant._data._bool; + } break; + case INT: { + _data._int = p_variant._data._int; + } break; + case REAL: { + _data._real = p_variant._data._real; + } break; + case STRING: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + // math types + case RECT2: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case RECT2I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR2: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR2I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR3: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR3I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR4: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR4I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + case PLANE: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case QUATERNION: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case AABB: { + *_data._aabb = *(p_variant._data._aabb); + } break; + case BASIS: { + *_data._basis = *(p_variant._data._basis); + } break; + case TRANSFORM: { + *_data._transform = *(p_variant._data._transform); + } break; + case TRANSFORM2D: { + *_data._transform2d = *(p_variant._data._transform2d); + } break; + case PROJECTION: { + *_data._projection = *(p_variant._data._projection); + } break; + + // misc types + case COLOR: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case NODE_PATH: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case RID: { + *reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case OBJECT: { + if (likely(_get_obj().rc)) { + if (unlikely(_get_obj().rc->decrement())) { + memdelete(_get_obj().rc); + } + } + *reinterpret_cast(_data._mem) = p_variant._get_obj(); + if (likely(_get_obj().rc)) { + _get_obj().rc->increment(); + } + } break; + case STRING_NAME: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case DICTIONARY: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case ARRAY: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_INT_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_REAL_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_STRING_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR2_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR2I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR3_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR3I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR4_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR4I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_COLOR_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + default: { + } + } +} + +Variant::Variant(const IP_Address &p_address) { + type = STRING; + memnew_placement(_data._mem, String(p_address)); +} + +Variant::Variant(const Variant &p_variant) { + type = NIL; + reference(p_variant); +} + +/* +Variant::~Variant() { + + clear(); +}*/ + +uint32_t Variant::hash() const { + return recursive_hash(0); +} + +uint32_t Variant::recursive_hash(int p_recursion_count) const { + switch (type) { + case NIL: { + return 0; + } break; + + case BOOL: { + return _data._bool ? 1 : 0; + } break; + case INT: { + return hash_one_uint64((uint64_t)_data._int); + } break; + case REAL: { + return hash_murmur3_one_float(_data._real); + } break; + case STRING: { + return reinterpret_cast(_data._mem)->hash(); + } break; + + // math types + case RECT2: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case RECT2I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR2: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR2I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR3: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR3I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR4: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR4I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case PLANE: { + uint32_t h = HASH_MURMUR3_SEED; + const Plane &p = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_real(p.normal.x, h); + h = hash_murmur3_one_real(p.normal.y, h); + h = hash_murmur3_one_real(p.normal.z, h); + h = hash_murmur3_one_real(p.d, h); + return hash_fmix32(h); + } break; + case QUATERNION: { + uint32_t h = HASH_MURMUR3_SEED; + const Quaternion &q = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_real(q.x, h); + h = hash_murmur3_one_real(q.y, h); + h = hash_murmur3_one_real(q.z, h); + h = hash_murmur3_one_real(q.w, h); + return hash_fmix32(h); + } break; + case AABB: { + return HashMapHasherDefault::hash(*_data._aabb); + } break; + case BASIS: { + uint32_t h = HASH_MURMUR3_SEED; + const Basis &b = *_data._basis; + h = hash_murmur3_one_real(b[0].x, h); + h = hash_murmur3_one_real(b[0].y, h); + h = hash_murmur3_one_real(b[0].z, h); + h = hash_murmur3_one_real(b[1].x, h); + h = hash_murmur3_one_real(b[1].y, h); + h = hash_murmur3_one_real(b[1].z, h); + h = hash_murmur3_one_real(b[2].x, h); + h = hash_murmur3_one_real(b[2].y, h); + h = hash_murmur3_one_real(b[2].z, h); + return hash_fmix32(h); + } break; + case TRANSFORM: { + uint32_t h = HASH_MURMUR3_SEED; + const Transform &t = *_data._transform; + h = hash_murmur3_one_real(t.basis[0].x, h); + h = hash_murmur3_one_real(t.basis[0].y, h); + h = hash_murmur3_one_real(t.basis[0].z, h); + h = hash_murmur3_one_real(t.basis[1].x, h); + h = hash_murmur3_one_real(t.basis[1].y, h); + h = hash_murmur3_one_real(t.basis[1].z, h); + h = hash_murmur3_one_real(t.basis[2].x, h); + h = hash_murmur3_one_real(t.basis[2].y, h); + h = hash_murmur3_one_real(t.basis[2].z, h); + h = hash_murmur3_one_real(t.origin.x, h); + h = hash_murmur3_one_real(t.origin.y, h); + h = hash_murmur3_one_real(t.origin.z, h); + return hash_fmix32(h); + } break; + case TRANSFORM2D: { + uint32_t h = HASH_MURMUR3_SEED; + const Transform2D &t = *_data._transform2d; + h = hash_murmur3_one_real(t[0].x, h); + h = hash_murmur3_one_real(t[0].y, h); + h = hash_murmur3_one_real(t[1].x, h); + h = hash_murmur3_one_real(t[1].y, h); + h = hash_murmur3_one_real(t[2].x, h); + h = hash_murmur3_one_real(t[2].y, h); + + return hash_fmix32(h); + } break; + case PROJECTION: { + uint32_t h = HASH_MURMUR3_SEED; + const Projection &t = *_data._projection; + h = hash_murmur3_one_real(t.matrix[0].x, h); + h = hash_murmur3_one_real(t.matrix[0].y, h); + h = hash_murmur3_one_real(t.matrix[0].z, h); + h = hash_murmur3_one_real(t.matrix[0].w, h); + h = hash_murmur3_one_real(t.matrix[1].x, h); + h = hash_murmur3_one_real(t.matrix[1].y, h); + h = hash_murmur3_one_real(t.matrix[1].z, h); + h = hash_murmur3_one_real(t.matrix[1].w, h); + h = hash_murmur3_one_real(t.matrix[2].x, h); + h = hash_murmur3_one_real(t.matrix[2].y, h); + h = hash_murmur3_one_real(t.matrix[2].z, h); + h = hash_murmur3_one_real(t.matrix[2].w, h); + h = hash_murmur3_one_real(t.matrix[3].x, h); + h = hash_murmur3_one_real(t.matrix[3].y, h); + h = hash_murmur3_one_real(t.matrix[3].z, h); + h = hash_murmur3_one_real(t.matrix[3].w, h); + return hash_fmix32(h); + } break; + + // misc types + case COLOR: { + uint32_t h = HASH_MURMUR3_SEED; + const Color &c = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_float(c.r, h); + h = hash_murmur3_one_float(c.g, h); + h = hash_murmur3_one_float(c.b, h); + h = hash_murmur3_one_float(c.a, h); + return hash_fmix32(h); + } break; + case NODE_PATH: { + return reinterpret_cast(_data._mem)->hash(); + } break; + case RID: { + return hash_one_uint64(reinterpret_cast(_data._mem)->get_id()); + } break; + case OBJECT: { + return hash_one_uint64(hash_make_uint64_t(_UNSAFE_OBJ_PROXY_PTR(*this))); + } break; + case STRING_NAME: { + return reinterpret_cast(_data._mem)->hash(); + } break; + case DICTIONARY: { + return reinterpret_cast(_data._mem)->recursive_hash(p_recursion_count); + } break; + case ARRAY: { + const Array &arr = *reinterpret_cast(_data._mem); + return arr.recursive_hash(p_recursion_count); + } break; + + case POOL_BYTE_ARRAY: { + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + if (likely(len)) { + PoolVector::Read r = arr.read(); + return hash_murmur3_buffer((uint8_t *)&r[0], len); + } else { + return hash_murmur3_one_64(0); + } + + } break; + case POOL_INT_ARRAY: { + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + if (likely(len)) { + PoolVector::Read r = arr.read(); + return hash_murmur3_buffer((uint8_t *)&r[0], len * sizeof(int)); + } else { + return hash_murmur3_one_64(0); + } + + } break; + case POOL_REAL_ARRAY: { + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + uint32_t h = HASH_MURMUR3_SEED; + + for (int i = 0; i < len; i++) { + h = hash_murmur3_one_real(r[i], h); + } + + return hash_fmix32(h); + } else { + return hash_murmur3_one_real(0.0); + } + + } break; + case POOL_STRING_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].hash(), hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR2_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR2I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR3_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR3I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + hash = hash_murmur3_one_32(r[i].z, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR4_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); + hash = hash_murmur3_one_real(r[i].w, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR4I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + hash = hash_murmur3_one_32(r[i].z, hash); + hash = hash_murmur3_one_32(r[i].w, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_COLOR_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].r, hash); + hash = hash_murmur3_one_real(r[i].g, hash); + hash = hash_murmur3_one_real(r[i].b, hash); + hash = hash_murmur3_one_real(r[i].a, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + default: { + } + } + + return 0; +} + +#define hash_compare_scalar(p_lhs, p_rhs) \ + (((p_lhs) == (p_rhs)) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs))) + +#define hash_compare_vector2(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y)) + +#define hash_compare_vector2i(p_lhs, p_rhs) \ + (((p_lhs).x == (p_rhs).x) && \ + ((p_lhs).y == (p_rhs).y)) + +#define hash_compare_vector3(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y) && \ + hash_compare_scalar((p_lhs).z, (p_rhs).z)) + +#define hash_compare_vector3i(p_lhs, p_rhs) \ + (((p_lhs).x == (p_rhs).x) && \ + ((p_lhs).y == (p_rhs).y) && \ + ((p_lhs).z == (p_rhs).z)) + +#define hash_compare_vector4(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y) && \ + hash_compare_scalar((p_lhs).z, (p_rhs).z) && \ + hash_compare_scalar((p_lhs).w, (p_rhs).w)) + +#define hash_compare_vector4i(p_lhs, p_rhs) \ + (((p_lhs).x == (p_rhs).x) && \ + ((p_lhs).y == (p_rhs).y) && \ + ((p_lhs).z == (p_rhs).z) && \ + ((p_lhs).w == (p_rhs).w)) + +#define hash_compare_quat(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y) && \ + hash_compare_scalar((p_lhs).z, (p_rhs).z) && \ + hash_compare_scalar((p_lhs).w, (p_rhs).w)) + +#define hash_compare_color(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).r, (p_rhs).r) && \ + hash_compare_scalar((p_lhs).g, (p_rhs).g) && \ + hash_compare_scalar((p_lhs).b, (p_rhs).b) && \ + hash_compare_scalar((p_lhs).a, (p_rhs).a)) + +#define hash_compare_pool_array(p_lhs, p_rhs, p_type, p_compare_func) \ + const PoolVector &l = *reinterpret_cast *>(p_lhs); \ + const PoolVector &r = *reinterpret_cast *>(p_rhs); \ + \ + if (l.size() != r.size()) \ + return false; \ + \ + PoolVector::Read lr = l.read(); \ + PoolVector::Read rr = r.read(); \ + \ + for (int i = 0; i < l.size(); ++i) { \ + if (!p_compare_func((lr[i]), (rr[i]))) \ + return false; \ + } \ + \ + return true + +bool Variant::hash_compare(const Variant &p_variant) const { + if (type != p_variant.type) { return false; } - switch (_type) { - case TYPE_NULL: + switch (type) { + //BOOL + case INT: { + return _data._int == p_variant._data._int; + } break; + case REAL: { + return hash_compare_scalar(_data._real, p_variant._data._real); + } break; + case STRING: { + return *reinterpret_cast(_data._mem) == *reinterpret_cast(p_variant._data._mem); + } break; + + case RECT2: { + const Rect2 *l = reinterpret_cast(_data._mem); + const Rect2 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2(l->position, r->position) && + hash_compare_vector2(l->size, r->size); + } break; + case RECT2I: { + const Rect2i *l = reinterpret_cast(_data._mem); + const Rect2i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2i(l->position, r->position) && + hash_compare_vector2i(l->size, r->size); + } break; + case VECTOR2: { + const Vector2 *l = reinterpret_cast(_data._mem); + const Vector2 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2(*l, *r); + } break; + case VECTOR2I: { + const Vector2i *l = reinterpret_cast(_data._mem); + const Vector2i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2i(*l, *r); + } break; + case VECTOR3: { + const Vector3 *l = reinterpret_cast(_data._mem); + const Vector3 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3(*l, *r); + } break; + case VECTOR3I: { + const Vector3i *l = reinterpret_cast(_data._mem); + const Vector3i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3i(*l, *r); + } break; + case VECTOR4: { + const Vector4 *l = reinterpret_cast(_data._mem); + const Vector4 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector4(*l, *r); + } break; + case VECTOR4I: { + const Vector4i *l = reinterpret_cast(_data._mem); + const Vector4i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector4i(*l, *r); + } break; + + case PLANE: { + const Plane *l = reinterpret_cast(_data._mem); + const Plane *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3(l->normal, r->normal) && + hash_compare_scalar(l->d, r->d); + } break; + case QUATERNION: { + const Quaternion *l = reinterpret_cast(_data._mem); + const Quaternion *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_quat(*l, *r); + } break; + case AABB: { + const ::AABB *l = _data._aabb; + const ::AABB *r = p_variant._data._aabb; + + return hash_compare_vector3(l->position, r->position) && + hash_compare_vector3(l->size, r->size); + + } break; + case BASIS: { + const Basis *l = _data._basis; + const Basis *r = p_variant._data._basis; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector3(l->rows[i], r->rows[i])) { + return false; + } + } + return true; - case TYPE_BOOL: - return _bool == other._bool; - case TYPE_INT: - return _int == other._int; - case TYPE_UINT: - return _uint == other._uint; - case TYPE_FLOAT: - return _float == other._float; - case TYPE_STRING: - return (*_string->string) == (*other._string->string); - case TYPE_OBJECT: - return (_object->object) == (other._object->object); - case TYPE_POINTER: - return _pointer == other._pointer; + } break; + case TRANSFORM: { + const Transform *l = _data._transform; + const Transform *r = p_variant._data._transform; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector3(l->basis.rows[i], r->basis.rows[i])) { + return false; + } + } + + return hash_compare_vector3(l->origin, r->origin); + } break; + case TRANSFORM2D: { + Transform2D *l = _data._transform2d; + Transform2D *r = p_variant._data._transform2d; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector2(l->columns[i], r->columns[i])) { + return false; + } + } + + return true; + } break; + case PROJECTION: { + const Projection *l = _data._projection; + const Projection *r = p_variant._data._projection; + + for (int i = 0; i < 4; i++) { + if (!hash_compare_vector4(l->matrix[i], r->matrix[i])) { + return false; + } + } + + return true; + } break; + + case COLOR: { + const Color *l = reinterpret_cast(_data._mem); + const Color *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_color(*l, *r); + } break; + case ARRAY: { + const Array &l = *(reinterpret_cast(_data._mem)); + const Array &r = *(reinterpret_cast(p_variant._data._mem)); + + if (l.size() != r.size()) { + return false; + } + + for (int i = 0; i < l.size(); ++i) { + if (!l[i].hash_compare(r[i])) { + return false; + } + } + + return true; + } break; + + case POOL_REAL_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, real_t, hash_compare_scalar); + } break; + case POOL_VECTOR2_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector2, hash_compare_vector2); + } break; + case POOL_VECTOR2I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector2i, hash_compare_vector2i); + } break; + case POOL_VECTOR3_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector3, hash_compare_vector3); + } break; + case POOL_VECTOR3I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector3i, hash_compare_vector3i); + } break; + case POOL_VECTOR4_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector4, hash_compare_vector4); + } break; + case POOL_VECTOR4I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector4i, hash_compare_vector4i); + } break; + case POOL_COLOR_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Color, hash_compare_color); + } break; + default: - break; + bool v; + Variant r; + evaluate(OP_EQUAL, *this, p_variant, r, v); + return r; } return false; } -bool Variant::operator!=(const Variant &other) const { - return !(operator==(other)); + +bool Variant::is_ref() const { + return type == OBJECT && !_get_obj().ref.is_null(); } -bool Variant::operator<(const Variant &other) const { - switch (_type) { - case TYPE_NULL: { - if (other.is_null()) { - return false; - } else { - return true; + +Vector varray() { + return Vector(); +} + +Vector varray(const Variant &p_arg1) { + Vector v; + v.push_back(p_arg1); + return v; +} +Vector varray(const Variant &p_arg1, const Variant &p_arg2) { + Vector v; + v.push_back(p_arg1); + v.push_back(p_arg2); + return v; +} +Vector varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) { + Vector v; + v.push_back(p_arg1); + v.push_back(p_arg2); + v.push_back(p_arg3); + return v; +} +Vector varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4) { + Vector v; + v.push_back(p_arg1); + v.push_back(p_arg2); + v.push_back(p_arg3); + v.push_back(p_arg4); + return v; +} + +Vector varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5) { + Vector v; + v.push_back(p_arg1); + v.push_back(p_arg2); + v.push_back(p_arg3); + v.push_back(p_arg4); + v.push_back(p_arg5); + return v; +} + +void Variant::static_assign(const Variant &p_variant) { +} + +bool Variant::is_shared() const { + switch (type) { + case OBJECT: + return true; + case ARRAY: + return true; + case DICTIONARY: + return true; + default: { + } + } + + return false; +} + +Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) { + VARIANT_ARGPTRS; + int argc = 0; + for (int i = 0; i < VARIANT_ARG_MAX; i++) { + if (argptr[i]->get_type() == Variant::NIL) { + break; + } + argc++; + } + + CallError error; + + Variant ret = call(p_method, argptr, argc, error); + + switch (error.error) { + case CallError::CALL_ERROR_INVALID_ARGUMENT: { + String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(error.expected) + "'."; + ERR_PRINT(err.utf8().get_data()); + + } break; + case CallError::CALL_ERROR_INVALID_METHOD: { + String err = "Invalid method '" + p_method + "' for type '" + Variant::get_type_name(type) + "'."; + ERR_PRINT(err.utf8().get_data()); + } break; + case CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { + String err = "Too many arguments for method '" + p_method + "'"; + ERR_PRINT(err.utf8().get_data()); + } break; + default: { + } + } + + return ret; +} + +void Variant::construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct, void *p_construct_ud) { + r_value = Variant(); +} + +String Variant::get_construct_string() const { + String vars; + VariantWriter::write_to_string(*this, vars); + + return vars; +} + +String Variant::get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Variant::CallError &ce) { + String err_text; + + if (ce.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { + int errorarg = ce.argument; + if (p_argptrs) { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + "."; + } else { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(ce.expected) + "."; + } + } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { + err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; + } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { + err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; + } else if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) { + err_text = "Method not found."; + } else if (ce.error == Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { + err_text = "Instance is null"; + } else if (ce.error == Variant::CallError::CALL_OK) { + return "Call OK"; + } + + String class_name = p_base->get_class(); + Ref