diff --git a/sfw/variant/SCsub b/sfw/variant/SCsub new file mode 100644 index 0000000..7f4c8b7 --- /dev/null +++ b/sfw/variant/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import("env") + +env_variant = env.Clone() + +env_variant.add_source_files(env.core_sources, "*.cpp") diff --git a/sfw/variant/array.cpp b/sfw/variant/array.cpp new file mode 100644 index 0000000..36929e6 --- /dev/null +++ b/sfw/variant/array.cpp @@ -0,0 +1,505 @@ +/*************************************************************************/ +/* array.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#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/variant/array.h b/sfw/variant/array.h new file mode 100644 index 0000000..28e81df --- /dev/null +++ b/sfw/variant/array.h @@ -0,0 +1,113 @@ +#ifndef ARRAY_H +#define ARRAY_H + +/*************************************************************************/ +/* array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#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/variant/dictionary.cpp b/sfw/variant/dictionary.cpp new file mode 100644 index 0000000..d95af10 --- /dev/null +++ b/sfw/variant/dictionary.cpp @@ -0,0 +1,323 @@ +/*************************************************************************/ +/* dictionary.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#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/variant/dictionary.h b/sfw/variant/dictionary.h new file mode 100644 index 0000000..99346d6 --- /dev/null +++ b/sfw/variant/dictionary.h @@ -0,0 +1,96 @@ +#ifndef DICTIONARY_H +#define DICTIONARY_H + +/*************************************************************************/ +/* dictionary.h */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#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/variant/method_ptrcall.h b/sfw/variant/method_ptrcall.h new file mode 100644 index 0000000..a8608ed --- /dev/null +++ b/sfw/variant/method_ptrcall.h @@ -0,0 +1,470 @@ +#ifndef METHOD_PTRCALL_H +#define METHOD_PTRCALL_H + +/*************************************************************************/ +/* method_ptrcall.h */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/math/transform_2d.h" +#include "core/typedefs.h" +#include "core/variant/variant.h" + +#ifdef PTRCALL_ENABLED + +template +struct PtrToArg { +}; + +#define MAKE_PTRARG(m_type) \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return *reinterpret_cast(p_ptr); \ + } \ + _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ + *((m_type *)p_ptr) = p_val; \ + } \ + }; \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return *reinterpret_cast(p_ptr); \ + } \ + _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ + *((m_type *)p_ptr) = p_val; \ + } \ + } + +#define MAKE_PTRARGCONV(m_type, m_conv) \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return static_cast(*reinterpret_cast(p_ptr)); \ + } \ + _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ + *((m_conv *)p_ptr) = static_cast(p_val); \ + } \ + }; \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return static_cast(*reinterpret_cast(p_ptr)); \ + } \ + _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ + *((m_conv *)p_ptr) = static_cast(p_val); \ + } \ + } + +#define MAKE_PTRARG_BY_REFERENCE(m_type) \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return *reinterpret_cast(p_ptr); \ + } \ + _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \ + *((m_type *)p_ptr) = p_val; \ + } \ + }; \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return *reinterpret_cast(p_ptr); \ + } \ + _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \ + *((m_type *)p_ptr) = p_val; \ + } \ + } + +MAKE_PTRARG(bool); +MAKE_PTRARGCONV(uint8_t, int64_t); +MAKE_PTRARGCONV(int8_t, int64_t); +MAKE_PTRARGCONV(uint16_t, int64_t); +MAKE_PTRARGCONV(int16_t, int64_t); +MAKE_PTRARGCONV(uint32_t, int64_t); +MAKE_PTRARGCONV(int32_t, int64_t); +MAKE_PTRARG(int64_t); +MAKE_PTRARG(uint64_t); +MAKE_PTRARGCONV(float, double); +MAKE_PTRARG(double); + +MAKE_PTRARG(String); +MAKE_PTRARG(StringName); + +MAKE_PTRARG(Rect2); +MAKE_PTRARG(Rect2i); +MAKE_PTRARG(Vector2); +MAKE_PTRARG(Vector2i); +MAKE_PTRARG_BY_REFERENCE(Vector3); +MAKE_PTRARG_BY_REFERENCE(Vector3i); +MAKE_PTRARG_BY_REFERENCE(Vector4); +MAKE_PTRARG_BY_REFERENCE(Vector4i); +MAKE_PTRARG_BY_REFERENCE(Plane); +MAKE_PTRARG(Quaternion); +MAKE_PTRARG_BY_REFERENCE(AABB); +MAKE_PTRARG_BY_REFERENCE(Basis); +MAKE_PTRARG_BY_REFERENCE(Transform); +MAKE_PTRARG(Transform2D); +MAKE_PTRARG(Projection); +MAKE_PTRARG_BY_REFERENCE(Color); +MAKE_PTRARG(NodePath); +MAKE_PTRARG(RID); +MAKE_PTRARG(Dictionary); +MAKE_PTRARG(Array); +MAKE_PTRARG(PoolByteArray); +MAKE_PTRARG(PoolIntArray); +MAKE_PTRARG(PoolRealArray); +MAKE_PTRARG(PoolStringArray); +MAKE_PTRARG(PoolVector2Array); +MAKE_PTRARG(PoolVector2iArray); +MAKE_PTRARG(PoolVector3Array); +MAKE_PTRARG(PoolVector3iArray); +MAKE_PTRARG(PoolVector4Array); +MAKE_PTRARG(PoolVector4iArray); +MAKE_PTRARG(PoolColorArray); +MAKE_PTRARG_BY_REFERENCE(Variant); + +//this is for Object + +template +struct PtrToArg { + _FORCE_INLINE_ static T *convert(const void *p_ptr) { + return const_cast(reinterpret_cast(p_ptr)); + } + + _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { + *((T **)p_ptr) = p_var; + } +}; + +template +struct PtrToArg { + _FORCE_INLINE_ static const T *convert(const void *p_ptr) { + return reinterpret_cast(p_ptr); + } + + _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { + *((T **)p_ptr) = p_var; + } +}; + +//this is for the special cases used by Variant + +#define MAKE_VECARG(m_type) \ + template <> \ + struct PtrToArg> { \ + _FORCE_INLINE_ static Vector convert(const void *p_ptr) { \ + const PoolVector *dvs = reinterpret_cast *>(p_ptr); \ + Vector ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret.write[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + _FORCE_INLINE_ static void encode(Vector p_vec, void *p_ptr) { \ + PoolVector *dv = reinterpret_cast *>(p_ptr); \ + int len = p_vec.size(); \ + dv->resize(len); \ + { \ + PoolVector::Write w = dv->write(); \ + for (int i = 0; i < len; i++) { \ + w[i] = p_vec[i]; \ + } \ + } \ + } \ + }; \ + template <> \ + struct PtrToArg &> { \ + _FORCE_INLINE_ static Vector convert(const void *p_ptr) { \ + const PoolVector *dvs = reinterpret_cast *>(p_ptr); \ + Vector ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret.write[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + } + +#define MAKE_VECARG_ALT(m_type, m_type_alt) \ + template <> \ + struct PtrToArg> { \ + _FORCE_INLINE_ static Vector convert(const void *p_ptr) { \ + const PoolVector *dvs = reinterpret_cast *>(p_ptr); \ + Vector ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret.write[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + _FORCE_INLINE_ static void encode(Vector p_vec, void *p_ptr) { \ + PoolVector *dv = reinterpret_cast *>(p_ptr); \ + int len = p_vec.size(); \ + dv->resize(len); \ + { \ + PoolVector::Write w = dv->write(); \ + for (int i = 0; i < len; i++) { \ + w[i] = p_vec[i]; \ + } \ + } \ + } \ + }; \ + template <> \ + struct PtrToArg &> { \ + _FORCE_INLINE_ static Vector convert(const void *p_ptr) { \ + const PoolVector *dvs = reinterpret_cast *>(p_ptr); \ + Vector ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret.write[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + } +MAKE_VECARG(String); +MAKE_VECARG(StringName); +MAKE_VECARG(uint8_t); +MAKE_VECARG(int); +MAKE_VECARG(float); +MAKE_VECARG(Vector2); +MAKE_VECARG(Vector2i); +MAKE_VECARG(Vector3); +MAKE_VECARG(Vector3i); +MAKE_VECARG(Vector4); +MAKE_VECARG(Vector4i); +MAKE_VECARG(Color); +//MAKE_VECARG_ALT(String, StringName); + +//for stuff that gets converted to Array vectors +#define MAKE_VECARR(m_type) \ + template <> \ + struct PtrToArg> { \ + _FORCE_INLINE_ static Vector convert(const void *p_ptr) { \ + const Array *arr = reinterpret_cast(p_ptr); \ + Vector ret; \ + int len = arr->size(); \ + ret.resize(len); \ + for (int i = 0; i < len; i++) { \ + ret.write[i] = (*arr)[i]; \ + } \ + return ret; \ + } \ + _FORCE_INLINE_ static void encode(Vector p_vec, void *p_ptr) { \ + Array *arr = reinterpret_cast(p_ptr); \ + int len = p_vec.size(); \ + arr->resize(len); \ + for (int i = 0; i < len; i++) { \ + (*arr)[i] = p_vec[i]; \ + } \ + } \ + }; \ + template <> \ + struct PtrToArg &> { \ + _FORCE_INLINE_ static Vector convert(const void *p_ptr) { \ + const Array *arr = reinterpret_cast(p_ptr); \ + Vector ret; \ + int len = arr->size(); \ + ret.resize(len); \ + for (int i = 0; i < len; i++) { \ + ret.write[i] = (*arr)[i]; \ + } \ + return ret; \ + } \ + } + +MAKE_VECARR(Variant); +MAKE_VECARR(RID); +MAKE_VECARR(Plane); + +#define MAKE_DVECARR(m_type) \ + template <> \ + struct PtrToArg> { \ + _FORCE_INLINE_ static PoolVector convert(const void *p_ptr) { \ + const Array *arr = reinterpret_cast(p_ptr); \ + PoolVector ret; \ + int len = arr->size(); \ + ret.resize(len); \ + { \ + PoolVector::Write w = ret.write(); \ + for (int i = 0; i < len; i++) { \ + w[i] = (*arr)[i]; \ + } \ + } \ + return ret; \ + } \ + _FORCE_INLINE_ static void encode(PoolVector p_vec, void *p_ptr) { \ + Array *arr = reinterpret_cast(p_ptr); \ + int len = p_vec.size(); \ + arr->resize(len); \ + { \ + PoolVector::Read r = p_vec.read(); \ + for (int i = 0; i < len; i++) { \ + (*arr)[i] = r[i]; \ + } \ + } \ + } \ + }; \ + template <> \ + struct PtrToArg &> { \ + _FORCE_INLINE_ static PoolVector convert(const void *p_ptr) { \ + const Array *arr = reinterpret_cast(p_ptr); \ + PoolVector ret; \ + int len = arr->size(); \ + ret.resize(len); \ + { \ + PoolVector::Write w = ret.write(); \ + for (int i = 0; i < len; i++) { \ + w[i] = (*arr)[i]; \ + } \ + } \ + return ret; \ + } \ + } + +MAKE_DVECARR(Plane); +//for special case StringName + +#define MAKE_STRINGCONV(m_type) \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + m_type s = *reinterpret_cast(p_ptr); \ + return s; \ + } \ + _FORCE_INLINE_ static void encode(m_type p_vec, void *p_ptr) { \ + String *arr = reinterpret_cast(p_ptr); \ + *arr = p_vec; \ + } \ + }; \ + \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + m_type s = *reinterpret_cast(p_ptr); \ + return s; \ + } \ + } + +#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + m_type s = *reinterpret_cast(p_ptr); \ + return s; \ + } \ + _FORCE_INLINE_ static void encode(const m_type &p_vec, void *p_ptr) { \ + String *arr = reinterpret_cast(p_ptr); \ + *arr = p_vec; \ + } \ + }; \ + \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + m_type s = *reinterpret_cast(p_ptr); \ + return s; \ + } \ + } + +//MAKE_STRINGCONV(StringName); +MAKE_STRINGCONV_BY_REFERENCE(IP_Address); + +template <> +struct PtrToArg> { + _FORCE_INLINE_ static PoolVector convert(const void *p_ptr) { + const PoolVector *dvs = reinterpret_cast *>(p_ptr); + PoolVector ret; + int len = dvs->size() / 3; + ret.resize(len); + { + PoolVector::Read r = dvs->read(); + PoolVector::Write w = ret.write(); + for (int i = 0; i < len; i++) { + w[i].vertex[0] = r[i * 3 + 0]; + w[i].vertex[1] = r[i * 3 + 1]; + w[i].vertex[2] = r[i * 3 + 2]; + } + } + return ret; + } + _FORCE_INLINE_ static void encode(PoolVector p_vec, void *p_ptr) { + PoolVector *arr = reinterpret_cast *>(p_ptr); + int len = p_vec.size(); + arr->resize(len * 3); + { + PoolVector::Read r = p_vec.read(); + PoolVector::Write w = arr->write(); + for (int i = 0; i < len; i++) { + w[i * 3 + 0] = r[i].vertex[0]; + w[i * 3 + 1] = r[i].vertex[1]; + w[i * 3 + 2] = r[i].vertex[2]; + } + } + } +}; +template <> +struct PtrToArg &> { + _FORCE_INLINE_ static PoolVector convert(const void *p_ptr) { + const PoolVector *dvs = reinterpret_cast *>(p_ptr); + PoolVector ret; + int len = dvs->size() / 3; + ret.resize(len); + { + PoolVector::Read r = dvs->read(); + PoolVector::Write w = ret.write(); + for (int i = 0; i < len; i++) { + w[i].vertex[0] = r[i * 3 + 0]; + w[i].vertex[1] = r[i * 3 + 1]; + w[i].vertex[2] = r[i * 3 + 2]; + } + } + return ret; + } +}; + +#endif // METHOD_PTRCALL_H +#endif diff --git a/sfw/variant/type_info.h b/sfw/variant/type_info.h new file mode 100644 index 0000000..e578309 --- /dev/null +++ b/sfw/variant/type_info.h @@ -0,0 +1,305 @@ +#ifndef GET_TYPE_INFO_H +#define GET_TYPE_INFO_H + +/*************************************************************************/ +/* type_info.h */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef DEBUG_METHODS_ENABLED + +template +struct EnableIf { + typedef T type; +}; + +template +struct EnableIf { +}; + +template +struct TypesAreSame { + static bool const value = false; +}; + +template +struct TypesAreSame { + static bool const value = true; +}; + +template +struct TypeInherits { + static D *get_d(); + + static char (&test(B *))[1]; + static char (&test(...))[2]; + + static bool const value = sizeof(test(get_d())) == sizeof(char) && + !TypesAreSame::value; +}; + +namespace PandemoniumTypeInfo { +enum Metadata { + METADATA_NONE, + METADATA_INT_IS_INT8, + METADATA_INT_IS_INT16, + METADATA_INT_IS_INT32, + METADATA_INT_IS_INT64, + METADATA_INT_IS_UINT8, + METADATA_INT_IS_UINT16, + METADATA_INT_IS_UINT32, + METADATA_INT_IS_UINT64, + METADATA_REAL_IS_FLOAT, + METADATA_REAL_IS_DOUBLE +}; +} + +// If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template +// instead of one of the specializations, it's most likely because the type 'T' is not supported. +// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration +// instead of a forward declaration. You can always forward declare 'T' in a header file, and then +// include the actual declaration of 'T' in the source file where 'GetTypeInfo' is instantiated. +template +struct GetTypeInfo; + +#define MAKE_TYPE_INFO(m_type, m_var_type) \ + template <> \ + struct GetTypeInfo { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; \ + template <> \ + struct GetTypeInfo { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; + +#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \ + template <> \ + struct GetTypeInfo { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const PandemoniumTypeInfo::Metadata METADATA = m_metadata; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; \ + template <> \ + struct GetTypeInfo { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const PandemoniumTypeInfo::Metadata METADATA = m_metadata; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; + +MAKE_TYPE_INFO(bool, Variant::BOOL) +MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_UINT8) +MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_INT8) +MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_UINT16) +MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_INT16) +MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_UINT32) +MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_INT32) +MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_UINT64) +MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, PandemoniumTypeInfo::METADATA_INT_IS_INT64) +MAKE_TYPE_INFO(char16_t, Variant::INT) +MAKE_TYPE_INFO(char32_t, Variant::INT) +MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, PandemoniumTypeInfo::METADATA_REAL_IS_FLOAT) +MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, PandemoniumTypeInfo::METADATA_REAL_IS_DOUBLE) + +MAKE_TYPE_INFO(String, Variant::STRING) +MAKE_TYPE_INFO(Rect2, Variant::RECT2) +MAKE_TYPE_INFO(Rect2i, Variant::RECT2I) +MAKE_TYPE_INFO(Vector2, Variant::VECTOR2) +MAKE_TYPE_INFO(Vector2i, Variant::VECTOR2I) +MAKE_TYPE_INFO(Vector3, Variant::VECTOR3) +MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I) +MAKE_TYPE_INFO(Vector4, Variant::VECTOR4) +MAKE_TYPE_INFO(Vector4i, Variant::VECTOR4I) +MAKE_TYPE_INFO(Plane, Variant::PLANE) +MAKE_TYPE_INFO(Quaternion, Variant::QUATERNION) +MAKE_TYPE_INFO(AABB, Variant::AABB) +MAKE_TYPE_INFO(Basis, Variant::BASIS) +MAKE_TYPE_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D) +MAKE_TYPE_INFO(Projection, Variant::PROJECTION) +MAKE_TYPE_INFO(Color, Variant::COLOR) +MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH) +MAKE_TYPE_INFO(RID, Variant::RID) +MAKE_TYPE_INFO(Dictionary, Variant::DICTIONARY) +MAKE_TYPE_INFO(Array, Variant::ARRAY) +MAKE_TYPE_INFO(PoolByteArray, Variant::POOL_BYTE_ARRAY) +MAKE_TYPE_INFO(PoolIntArray, Variant::POOL_INT_ARRAY) +MAKE_TYPE_INFO(PoolRealArray, Variant::POOL_REAL_ARRAY) +MAKE_TYPE_INFO(PoolStringArray, Variant::POOL_STRING_ARRAY) +MAKE_TYPE_INFO(PoolVector2Array, Variant::POOL_VECTOR2_ARRAY) +MAKE_TYPE_INFO(PoolVector2iArray, Variant::POOL_VECTOR2I_ARRAY) +MAKE_TYPE_INFO(PoolVector3Array, Variant::POOL_VECTOR3_ARRAY) +MAKE_TYPE_INFO(PoolVector3iArray, Variant::POOL_VECTOR3I_ARRAY) +MAKE_TYPE_INFO(PoolVector4Array, Variant::POOL_VECTOR4_ARRAY) +MAKE_TYPE_INFO(PoolVector4iArray, Variant::POOL_VECTOR4I_ARRAY) +MAKE_TYPE_INFO(PoolColorArray, Variant::POOL_COLOR_ARRAY) + +MAKE_TYPE_INFO(StringName, Variant::STRING_NAME) +MAKE_TYPE_INFO(IP_Address, Variant::STRING) + +class BSP_Tree; +MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY) + +//for RefPtr +template <> +struct GetTypeInfo { + static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference"); + } +}; +template <> +struct GetTypeInfo { + static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference"); + } +}; + +//for variant +template <> +struct GetTypeInfo { + static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT); + } +}; + +template <> +struct GetTypeInfo { + static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT); + } +}; + +#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \ + template <> \ + struct GetTypeInfo> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; \ + template <> \ + struct GetTypeInfo &> { \ + static const Variant::Type VARIANT_TYPE = m_var_type; \ + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(VARIANT_TYPE, String()); \ + } \ + }; + +MAKE_TEMPLATE_TYPE_INFO(Vector, uint8_t, Variant::POOL_BYTE_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, int, Variant::POOL_INT_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, float, Variant::POOL_REAL_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, String, Variant::POOL_STRING_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Vector2, Variant::POOL_VECTOR2_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Vector2i, Variant::POOL_VECTOR2I_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Vector3, Variant::POOL_VECTOR3_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Vector3i, Variant::POOL_VECTOR3I_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Vector4, Variant::POOL_VECTOR4_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Vector4i, Variant::POOL_VECTOR4I_ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Color, Variant::POOL_COLOR_ARRAY) + +MAKE_TEMPLATE_TYPE_INFO(Vector, Variant, Variant::ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, RID, Variant::ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, Plane, Variant::ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::POOL_STRING_ARRAY) + +MAKE_TEMPLATE_TYPE_INFO(PoolVector, Plane, Variant::ARRAY) +MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY) + +template +struct GetTypeInfo::value>::type> { + static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(StringName(T::get_class_static())); + } +}; + +template +struct GetTypeInfo::value>::type> { + static const Variant::Type VARIANT_TYPE = Variant::OBJECT; + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(StringName(T::get_class_static())); + } +}; + +#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \ + template <> \ + struct GetTypeInfo { \ + static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const PandemoniumTypeInfo::Metadata METADATA = PandemoniumTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \ + } \ + }; + +#define MAKE_ENUM_TYPE_INFO(m_enum) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \ + TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &) + +template +inline StringName __constant_get_enum_name(T param, const String &p_constant) { + if (GetTypeInfo::VARIANT_TYPE == Variant::NIL) + ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's enum: " + p_constant); + return GetTypeInfo::get_class_info().class_name; +} + +#define CLASS_INFO(m_type) (GetTypeInfo::get_class_info()) + +#else + +#define MAKE_ENUM_TYPE_INFO(m_enum) +#define CLASS_INFO(m_type) + +#endif // DEBUG_METHODS_ENABLED + +#endif // GET_TYPE_INFO_H diff --git a/sfw/variant/variant.cpp b/sfw/variant/variant.cpp new file mode 100644 index 0000000..aa585a6 --- /dev/null +++ b/sfw/variant/variant.cpp @@ -0,0 +1,4014 @@ +/*************************************************************************/ +/* variant.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "variant.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" + +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) { + /* + // 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, + + 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 + + // 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 { + _get_obj().ref.unref(); + } + } 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; + 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 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; + } + } +} + +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; + } + } +} + +/* +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 0; +}; +*/ + +Variant::operator uint64_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_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 { + 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 { + 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; + } + } +} + +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()); +} + +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) { + //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; + } 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: + bool v; + Variant r; + evaluate(OP_EQUAL, *this, p_variant, r, v); + return r; + } + + return false; +} + +bool Variant::is_ref() const { + return type == OBJECT && !_get_obj().ref.is_null(); +} + +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