initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
8
core/variant/SCsub
Normal file
8
core/variant/SCsub
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env_variant = env.Clone()
|
||||
|
||||
env_variant.add_source_files(env.core_sources, "*.cpp")
|
||||
956
core/variant/array.cpp
Normal file
956
core/variant/array.cpp
Normal file
@@ -0,0 +1,956 @@
|
||||
/**************************************************************************/
|
||||
/* array.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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 "container_type_validate.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/templates/hashfuncs.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "core/variant/callable.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
|
||||
struct ArrayPrivate {
|
||||
SafeRefCount refcount;
|
||||
Vector<Variant> array;
|
||||
Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
|
||||
ContainerTypeValidate typed;
|
||||
|
||||
ArrayPrivate() {}
|
||||
ArrayPrivate(std::initializer_list<Variant> p_init) :
|
||||
array(p_init) {}
|
||||
};
|
||||
|
||||
void Array::_ref(const Array &p_from) const {
|
||||
ArrayPrivate *_fp = p_from._p;
|
||||
|
||||
ERR_FAIL_NULL(_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 = _fp;
|
||||
}
|
||||
|
||||
void Array::_unref() const {
|
||||
if (!_p) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_p->refcount.unref()) {
|
||||
if (_p->read_only) {
|
||||
memdelete(_p->read_only);
|
||||
}
|
||||
memdelete(_p);
|
||||
}
|
||||
_p = nullptr;
|
||||
}
|
||||
|
||||
Array::Iterator Array::begin() {
|
||||
return Iterator(_p->array.ptrw(), _p->read_only);
|
||||
}
|
||||
|
||||
Array::Iterator Array::end() {
|
||||
return Iterator(_p->array.ptrw() + _p->array.size(), _p->read_only);
|
||||
}
|
||||
|
||||
Array::ConstIterator Array::begin() const {
|
||||
return ConstIterator(_p->array.ptr());
|
||||
}
|
||||
|
||||
Array::ConstIterator Array::end() const {
|
||||
return ConstIterator(_p->array.ptr() + _p->array.size());
|
||||
}
|
||||
|
||||
Variant &Array::operator[](int p_idx) {
|
||||
if (unlikely(_p->read_only)) {
|
||||
*_p->read_only = _p->array[p_idx];
|
||||
return *_p->read_only;
|
||||
}
|
||||
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::is_empty() const {
|
||||
return _p->array.is_empty();
|
||||
}
|
||||
|
||||
void Array::clear() {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
_p->array.clear();
|
||||
}
|
||||
|
||||
bool Array::operator==(const Array &p_array) const {
|
||||
return recursive_equal(p_array, 0);
|
||||
}
|
||||
|
||||
bool Array::operator!=(const Array &p_array) const {
|
||||
return !recursive_equal(p_array, 0);
|
||||
}
|
||||
|
||||
bool Array::recursive_equal(const Array &p_array, int recursion_count) const {
|
||||
// Cheap checks
|
||||
if (_p == p_array._p) {
|
||||
return true;
|
||||
}
|
||||
const Vector<Variant> &a1 = _p->array;
|
||||
const Vector<Variant> &a2 = p_array._p->array;
|
||||
const int size = a1.size();
|
||||
if (size != a2.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Heavy O(n) check
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return true;
|
||||
}
|
||||
recursion_count++;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!a1[i].hash_compare(a2[i], recursion_count, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Array::operator<(const Array &p_array) const {
|
||||
int a_len = size();
|
||||
int b_len = p_array.size();
|
||||
|
||||
int min_cmp = MIN(a_len, b_len);
|
||||
|
||||
for (int i = 0; i < min_cmp; i++) {
|
||||
if (operator[](i) < p_array[i]) {
|
||||
return true;
|
||||
} else if (p_array[i] < operator[](i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return a_len < b_len;
|
||||
}
|
||||
|
||||
bool Array::operator<=(const Array &p_array) const {
|
||||
return !operator>(p_array);
|
||||
}
|
||||
bool Array::operator>(const Array &p_array) const {
|
||||
return p_array < *this;
|
||||
}
|
||||
bool Array::operator>=(const Array &p_array) const {
|
||||
return !operator<(p_array);
|
||||
}
|
||||
|
||||
uint32_t Array::hash() const {
|
||||
return recursive_hash(0);
|
||||
}
|
||||
|
||||
uint32_t Array::recursive_hash(int recursion_count) const {
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t h = hash_murmur3_one_32(Variant::ARRAY);
|
||||
|
||||
recursion_count++;
|
||||
for (int i = 0; i < _p->array.size(); i++) {
|
||||
h = hash_murmur3_one_32(_p->array[i].recursive_hash(recursion_count), h);
|
||||
}
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
|
||||
void Array::operator=(const Array &p_array) {
|
||||
if (this == &p_array) {
|
||||
return;
|
||||
}
|
||||
_ref(p_array);
|
||||
}
|
||||
|
||||
void Array::assign(const Array &p_array) {
|
||||
const ContainerTypeValidate &typed = _p->typed;
|
||||
const ContainerTypeValidate &source_typed = p_array._p->typed;
|
||||
|
||||
if (typed == source_typed || typed.type == Variant::NIL || (source_typed.type == Variant::OBJECT && typed.can_reference(source_typed))) {
|
||||
// from same to same or
|
||||
// from anything to variants or
|
||||
// from subclasses to base classes
|
||||
_p->array = p_array._p->array;
|
||||
return;
|
||||
}
|
||||
|
||||
const Variant *source = p_array._p->array.ptr();
|
||||
int size = p_array._p->array.size();
|
||||
|
||||
if ((source_typed.type == Variant::NIL && typed.type == Variant::OBJECT) || (source_typed.type == Variant::OBJECT && source_typed.can_reference(typed))) {
|
||||
// from variants to objects or
|
||||
// from base classes to subclasses
|
||||
for (int i = 0; i < size; i++) {
|
||||
const Variant &element = source[i];
|
||||
if (element.get_type() != Variant::NIL && (element.get_type() != Variant::OBJECT || !typed.validate_object(element, "assign"))) {
|
||||
ERR_FAIL_MSG(vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(element.get_type()), Variant::get_type_name(typed.type)));
|
||||
}
|
||||
}
|
||||
_p->array = p_array._p->array;
|
||||
return;
|
||||
}
|
||||
if (typed.type == Variant::OBJECT || source_typed.type == Variant::OBJECT) {
|
||||
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type)));
|
||||
}
|
||||
|
||||
Vector<Variant> array;
|
||||
array.resize(size);
|
||||
Variant *data = array.ptrw();
|
||||
|
||||
if (source_typed.type == Variant::NIL && typed.type != Variant::OBJECT) {
|
||||
// from variants to primitives
|
||||
for (int i = 0; i < size; i++) {
|
||||
const Variant *value = source + i;
|
||||
if (value->get_type() == typed.type) {
|
||||
data[i] = *value;
|
||||
continue;
|
||||
}
|
||||
if (!Variant::can_convert_strict(value->get_type(), typed.type)) {
|
||||
ERR_FAIL_MSG(vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
|
||||
}
|
||||
Callable::CallError ce;
|
||||
Variant::construct(typed.type, data[i], &value, 1, ce);
|
||||
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
|
||||
}
|
||||
} else if (Variant::can_convert_strict(source_typed.type, typed.type)) {
|
||||
// from primitives to different convertible primitives
|
||||
for (int i = 0; i < size; i++) {
|
||||
const Variant *value = source + i;
|
||||
Callable::CallError ce;
|
||||
Variant::construct(typed.type, data[i], &value, 1, ce);
|
||||
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type)));
|
||||
}
|
||||
|
||||
_p->array = array;
|
||||
}
|
||||
|
||||
void Array::push_back(const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND(!_p->typed.validate(value, "push_back"));
|
||||
_p->array.push_back(std::move(value));
|
||||
}
|
||||
|
||||
void Array::append_array(const Array &p_array) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
|
||||
if (!is_typed() || _p->typed.can_reference(p_array._p->typed)) {
|
||||
_p->array.append_array(p_array._p->array);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<Variant> validated_array = p_array._p->array;
|
||||
Variant *write = validated_array.ptrw();
|
||||
for (int i = 0; i < validated_array.size(); ++i) {
|
||||
ERR_FAIL_COND(!_p->typed.validate(write[i], "append_array"));
|
||||
}
|
||||
|
||||
_p->array.append_array(validated_array);
|
||||
}
|
||||
|
||||
Error Array::resize(int p_new_size) {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
|
||||
Variant::Type &variant_type = _p->typed.type;
|
||||
int old_size = _p->array.size();
|
||||
Error err = _p->array.resize_initialized(p_new_size);
|
||||
if (!err && variant_type != Variant::NIL && variant_type != Variant::OBJECT) {
|
||||
for (int i = old_size; i < p_new_size; i++) {
|
||||
VariantInternal::initialize(&_p->array.write[i], variant_type);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
Error Array::insert(int p_pos, const Variant &p_value) {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "insert"), ERR_INVALID_PARAMETER);
|
||||
|
||||
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() + 1, ERR_INVALID_PARAMETER, vformat("The calculated index %d is out of bounds (the array has %d elements). Leaving the array untouched.", p_pos, _p->array.size()));
|
||||
|
||||
return _p->array.insert(p_pos, std::move(value));
|
||||
}
|
||||
|
||||
void Array::fill(const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND(!_p->typed.validate(value, "fill"));
|
||||
_p->array.fill(std::move(value));
|
||||
}
|
||||
|
||||
void Array::erase(const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND(!_p->typed.validate(value, "erase"));
|
||||
_p->array.erase(value);
|
||||
}
|
||||
|
||||
Variant Array::front() const {
|
||||
ERR_FAIL_COND_V_MSG(_p->array.is_empty(), Variant(), "Can't take value from empty array.");
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
Variant Array::back() const {
|
||||
ERR_FAIL_COND_V_MSG(_p->array.is_empty(), Variant(), "Can't take value from empty array.");
|
||||
return operator[](_p->array.size() - 1);
|
||||
}
|
||||
|
||||
Variant Array::pick_random() const {
|
||||
ERR_FAIL_COND_V_MSG(_p->array.is_empty(), Variant(), "Can't take value from empty array.");
|
||||
return operator[](Math::rand() % _p->array.size());
|
||||
}
|
||||
|
||||
int Array::find(const Variant &p_value, int p_from) const {
|
||||
if (_p->array.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "find"), -1);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = p_from; i < size(); i++) {
|
||||
if (StringLikeVariantComparator::compare(_p->array[i], value)) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Array::find_custom(const Callable &p_callable, int p_from) const {
|
||||
int ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const Variant *argptrs[1];
|
||||
|
||||
for (int i = p_from; i < size(); i++) {
|
||||
const Variant &val = _p->array[i];
|
||||
argptrs[0] = &val;
|
||||
Variant res;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, res, ce);
|
||||
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
|
||||
ERR_FAIL_V_MSG(ret, vformat("Error calling method from 'find_custom': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, ret, "Error on method from 'find_custom': Return type of callable must be boolean.");
|
||||
if (res.operator bool()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Array::rfind(const Variant &p_value, int p_from) const {
|
||||
if (_p->array.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "rfind"), -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 (StringLikeVariantComparator::compare(_p->array[i], value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Array::rfind_custom(const Callable &p_callable, int p_from) const {
|
||||
if (_p->array.is_empty()) {
|
||||
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;
|
||||
}
|
||||
|
||||
const Variant *argptrs[1];
|
||||
|
||||
for (int i = p_from; i >= 0; i--) {
|
||||
const Variant &val = _p->array[i];
|
||||
argptrs[0] = &val;
|
||||
Variant res;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, res, ce);
|
||||
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
|
||||
ERR_FAIL_V_MSG(-1, vformat("Error calling method from 'rfind_custom': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, -1, "Error on method from 'rfind_custom': Return type of callable must be boolean.");
|
||||
if (res.operator bool()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Array::count(const Variant &p_value) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0);
|
||||
if (_p->array.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amount = 0;
|
||||
for (int i = 0; i < _p->array.size(); i++) {
|
||||
if (StringLikeVariantComparator::compare(_p->array[i], value)) {
|
||||
amount++;
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
bool Array::has(const Variant &p_value) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "use 'has'"), false);
|
||||
|
||||
return find(value) != -1;
|
||||
}
|
||||
|
||||
void Array::remove_at(int p_pos) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
|
||||
if (p_pos < 0) {
|
||||
// Relative offset from the end.
|
||||
p_pos = _p->array.size() + p_pos;
|
||||
}
|
||||
|
||||
ERR_FAIL_INDEX_MSG(p_pos, _p->array.size(), vformat("The calculated index %d is out of bounds (the array has %d elements). Leaving the array untouched.", p_pos, _p->array.size()));
|
||||
|
||||
_p->array.remove_at(p_pos);
|
||||
}
|
||||
|
||||
void Array::set(int p_idx, const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND(!_p->typed.validate(value, "set"));
|
||||
|
||||
_p->array.write[p_idx] = std::move(value);
|
||||
}
|
||||
|
||||
const Variant &Array::get(int p_idx) const {
|
||||
return operator[](p_idx);
|
||||
}
|
||||
|
||||
Array Array::duplicate(bool p_deep) const {
|
||||
return recursive_duplicate(p_deep, RESOURCE_DEEP_DUPLICATE_NONE, 0);
|
||||
}
|
||||
|
||||
Array Array::duplicate_deep(ResourceDeepDuplicateMode p_deep_subresources_mode) const {
|
||||
return recursive_duplicate(true, p_deep_subresources_mode, 0);
|
||||
}
|
||||
|
||||
Array Array::recursive_duplicate(bool p_deep, ResourceDeepDuplicateMode p_deep_subresources_mode, int recursion_count) const {
|
||||
Array new_arr;
|
||||
new_arr._p->typed = _p->typed;
|
||||
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return new_arr;
|
||||
}
|
||||
|
||||
if (p_deep) {
|
||||
bool is_call_chain_end = recursion_count == 0;
|
||||
|
||||
recursion_count++;
|
||||
int element_count = size();
|
||||
new_arr.resize(element_count);
|
||||
Variant *write = new_arr._p->array.ptrw();
|
||||
for (int i = 0; i < element_count; i++) {
|
||||
write[i] = get(i).recursive_duplicate(true, p_deep_subresources_mode, recursion_count);
|
||||
}
|
||||
|
||||
// Variant::recursive_duplicate() may have created a remap cache by now.
|
||||
if (is_call_chain_end) {
|
||||
Resource::_teardown_duplicate_from_variant();
|
||||
}
|
||||
} else {
|
||||
new_arr._p->array = _p->array;
|
||||
}
|
||||
|
||||
return new_arr;
|
||||
}
|
||||
|
||||
Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
|
||||
Array result;
|
||||
result._p->typed = _p->typed;
|
||||
|
||||
ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");
|
||||
|
||||
const int s = size();
|
||||
|
||||
if (s == 0 || (p_begin < -s && p_step < 0) || (p_begin >= s && p_step > 0)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int begin = CLAMP(p_begin, -s, s - 1);
|
||||
if (begin < 0) {
|
||||
begin += s;
|
||||
}
|
||||
int end = CLAMP(p_end, -s - 1, s);
|
||||
if (end < 0) {
|
||||
end += s;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice step is positive, but bounds are decreasing.");
|
||||
ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice step is negative, but bounds are increasing.");
|
||||
|
||||
int result_size = (end - begin) / p_step + (((end - begin) % p_step != 0) ? 1 : 0);
|
||||
result.resize(result_size);
|
||||
|
||||
Variant *write = result._p->array.ptrw();
|
||||
for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
|
||||
write[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
|
||||
src_idx += p_step;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Array Array::filter(const Callable &p_callable) const {
|
||||
Array new_arr;
|
||||
new_arr.resize(size());
|
||||
new_arr._p->typed = _p->typed;
|
||||
int accepted_count = 0;
|
||||
|
||||
const Variant *argptrs[1];
|
||||
Variant *write = new_arr._p->array.ptrw();
|
||||
for (int i = 0; i < size(); i++) {
|
||||
argptrs[0] = &get(i);
|
||||
|
||||
Variant result;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, result, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_FAIL_V_MSG(Array(), vformat("Error calling method from 'filter': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
|
||||
}
|
||||
|
||||
if (result.operator bool()) {
|
||||
write[accepted_count] = get(i);
|
||||
accepted_count++;
|
||||
}
|
||||
}
|
||||
|
||||
new_arr.resize(accepted_count);
|
||||
|
||||
return new_arr;
|
||||
}
|
||||
|
||||
Array Array::map(const Callable &p_callable) const {
|
||||
Array new_arr;
|
||||
new_arr.resize(size());
|
||||
|
||||
const Variant *argptrs[1];
|
||||
Variant *write = new_arr._p->array.ptrw();
|
||||
for (int i = 0; i < size(); i++) {
|
||||
argptrs[0] = &get(i);
|
||||
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, write[i], ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_FAIL_V_MSG(Array(), vformat("Error calling method from 'map': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
|
||||
}
|
||||
}
|
||||
|
||||
return new_arr;
|
||||
}
|
||||
|
||||
Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const {
|
||||
int start = 0;
|
||||
Variant ret = p_accum;
|
||||
if (ret == Variant() && size() > 0) {
|
||||
ret = front();
|
||||
start = 1;
|
||||
}
|
||||
|
||||
const Variant *argptrs[2];
|
||||
for (int i = start; i < size(); i++) {
|
||||
argptrs[0] = &ret;
|
||||
argptrs[1] = &get(i);
|
||||
|
||||
Variant result;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 2, result, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_FAIL_V_MSG(Variant(), vformat("Error calling method from 'reduce': %s.", Variant::get_callable_error_text(p_callable, argptrs, 2, ce)));
|
||||
}
|
||||
ret = result;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Array::any(const Callable &p_callable) const {
|
||||
const Variant *argptrs[1];
|
||||
for (int i = 0; i < size(); i++) {
|
||||
argptrs[0] = &get(i);
|
||||
|
||||
Variant result;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, result, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Error calling method from 'any': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
|
||||
}
|
||||
|
||||
if (result.operator bool()) {
|
||||
// Return as early as possible when one of the conditions is `true`.
|
||||
// This improves performance compared to relying on `filter(...).size() >= 1`.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array::all(const Callable &p_callable) const {
|
||||
const Variant *argptrs[1];
|
||||
for (int i = 0; i < size(); i++) {
|
||||
argptrs[0] = &get(i);
|
||||
|
||||
Variant result;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, result, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Error calling method from 'all': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
|
||||
}
|
||||
|
||||
if (!(result.operator bool())) {
|
||||
// Return as early as possible when one of the inverted conditions is `false`.
|
||||
// This improves performance compared to relying on `filter(...).size() >= array_size().`.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
void Array::sort() {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
_p->array.sort_custom<_ArrayVariantSort>();
|
||||
}
|
||||
|
||||
void Array::sort_custom(const Callable &p_callable) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
_p->array.sort_custom<CallableComparator, true>(p_callable);
|
||||
}
|
||||
|
||||
void Array::shuffle() {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
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);
|
||||
SWAP(data[i], data[j]);
|
||||
}
|
||||
}
|
||||
|
||||
int Array::bsearch(const Variant &p_value, bool p_before) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "binary search"), -1);
|
||||
return _p->array.span().bisect<_ArrayVariantSort>(value, p_before);
|
||||
}
|
||||
|
||||
int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "custom binary search"), -1);
|
||||
|
||||
return _p->array.bsearch_custom<CallableComparator>(value, p_before, p_callable);
|
||||
}
|
||||
|
||||
void Array::reverse() {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
_p->array.reverse();
|
||||
}
|
||||
|
||||
void Array::push_front(const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND(!_p->typed.validate(value, "push_front"));
|
||||
_p->array.insert(0, std::move(value));
|
||||
}
|
||||
|
||||
Variant Array::pop_back() {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");
|
||||
if (!_p->array.is_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() {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");
|
||||
if (!_p->array.is_empty()) {
|
||||
const Variant ret = _p->array.get(0);
|
||||
_p->array.remove_at(0);
|
||||
return ret;
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant Array::pop_at(int p_pos) {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");
|
||||
if (_p->array.is_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_at(p_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant Array::min() const {
|
||||
int array_size = size();
|
||||
if (array_size == 0) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
int min_index = 0;
|
||||
Variant is_less;
|
||||
for (int i = 1; i < array_size; i++) {
|
||||
bool valid;
|
||||
Variant::evaluate(Variant::OP_LESS, _p->array[i], _p->array[min_index], is_less, valid);
|
||||
if (!valid) {
|
||||
return Variant(); //not a valid comparison
|
||||
}
|
||||
if (bool(is_less)) {
|
||||
min_index = i;
|
||||
}
|
||||
}
|
||||
return _p->array[min_index];
|
||||
}
|
||||
|
||||
Variant Array::max() const {
|
||||
int array_size = size();
|
||||
if (array_size == 0) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
int max_index = 0;
|
||||
Variant is_greater;
|
||||
for (int i = 1; i < array_size; i++) {
|
||||
bool valid;
|
||||
Variant::evaluate(Variant::OP_GREATER, _p->array[i], _p->array[max_index], is_greater, valid);
|
||||
if (!valid) {
|
||||
return Variant(); //not a valid comparison
|
||||
}
|
||||
if (bool(is_greater)) {
|
||||
max_index = i;
|
||||
}
|
||||
}
|
||||
return _p->array[max_index];
|
||||
}
|
||||
|
||||
const void *Array::id() const {
|
||||
return _p;
|
||||
}
|
||||
|
||||
Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
|
||||
_p = memnew(ArrayPrivate);
|
||||
_p->refcount.init();
|
||||
set_typed(p_type, p_class_name, p_script);
|
||||
assign(p_from);
|
||||
}
|
||||
|
||||
void Array::set_typed(const ContainerType &p_element_type) {
|
||||
set_typed(p_element_type.builtin_type, p_element_type.class_name, p_element_type.script);
|
||||
}
|
||||
|
||||
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
|
||||
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
|
||||
ERR_FAIL_COND_MSG(_p->typed.type != Variant::NIL, "Type can only be set once.");
|
||||
ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");
|
||||
Ref<Script> script = p_script;
|
||||
ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");
|
||||
|
||||
_p->typed.type = Variant::Type(p_type);
|
||||
_p->typed.class_name = p_class_name;
|
||||
_p->typed.script = script;
|
||||
_p->typed.where = "TypedArray";
|
||||
}
|
||||
|
||||
bool Array::is_typed() const {
|
||||
return _p->typed.type != Variant::NIL;
|
||||
}
|
||||
|
||||
bool Array::is_same_typed(const Array &p_other) const {
|
||||
return _p->typed == p_other._p->typed;
|
||||
}
|
||||
|
||||
bool Array::is_same_instance(const Array &p_other) const {
|
||||
return _p == p_other._p;
|
||||
}
|
||||
|
||||
ContainerType Array::get_element_type() const {
|
||||
ContainerType type;
|
||||
type.builtin_type = _p->typed.type;
|
||||
type.class_name = _p->typed.class_name;
|
||||
type.script = _p->typed.script;
|
||||
return type;
|
||||
}
|
||||
|
||||
uint32_t Array::get_typed_builtin() const {
|
||||
return _p->typed.type;
|
||||
}
|
||||
|
||||
StringName Array::get_typed_class_name() const {
|
||||
return _p->typed.class_name;
|
||||
}
|
||||
|
||||
Variant Array::get_typed_script() const {
|
||||
return _p->typed.script;
|
||||
}
|
||||
|
||||
Array Array::create_read_only() {
|
||||
Array array;
|
||||
array.make_read_only();
|
||||
return array;
|
||||
}
|
||||
|
||||
void Array::make_read_only() {
|
||||
if (_p->read_only == nullptr) {
|
||||
_p->read_only = memnew(Variant);
|
||||
}
|
||||
}
|
||||
|
||||
bool Array::is_read_only() const {
|
||||
return _p->read_only != nullptr;
|
||||
}
|
||||
|
||||
Array::Array(const Array &p_from) {
|
||||
_p = nullptr;
|
||||
_ref(p_from);
|
||||
}
|
||||
|
||||
Array::Array(std::initializer_list<Variant> p_init) {
|
||||
_p = memnew(ArrayPrivate);
|
||||
_p->refcount.init();
|
||||
_p->array = Vector<Variant>(p_init);
|
||||
}
|
||||
|
||||
Array::Array() {
|
||||
_p = memnew(ArrayPrivate);
|
||||
_p->refcount.init();
|
||||
}
|
||||
|
||||
Array::~Array() {
|
||||
_unref();
|
||||
}
|
||||
209
core/variant/array.h
Normal file
209
core/variant/array.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/**************************************************************************/
|
||||
/* array.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/variant_deep_duplicate.h"
|
||||
|
||||
#include <climits>
|
||||
#include <initializer_list>
|
||||
|
||||
class Callable;
|
||||
class StringName;
|
||||
class Variant;
|
||||
|
||||
struct ArrayPrivate;
|
||||
struct ContainerType;
|
||||
|
||||
class Array {
|
||||
mutable ArrayPrivate *_p;
|
||||
void _ref(const Array &p_from) const;
|
||||
void _unref() const;
|
||||
|
||||
public:
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const Variant &operator*() const;
|
||||
_FORCE_INLINE_ const Variant *operator->() const;
|
||||
|
||||
_FORCE_INLINE_ ConstIterator &operator++();
|
||||
_FORCE_INLINE_ ConstIterator &operator--();
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &p_other) const { return element_ptr == p_other.element_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &p_other) const { return element_ptr != p_other.element_ptr; }
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const Variant *p_element_ptr) :
|
||||
element_ptr(p_element_ptr) {}
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_other) :
|
||||
element_ptr(p_other.element_ptr) {}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator &operator=(const ConstIterator &p_other) {
|
||||
element_ptr = p_other.element_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const Variant *element_ptr = nullptr;
|
||||
};
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ Variant &operator*() const;
|
||||
_FORCE_INLINE_ Variant *operator->() const;
|
||||
|
||||
_FORCE_INLINE_ Iterator &operator++();
|
||||
_FORCE_INLINE_ Iterator &operator--();
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &p_other) const { return element_ptr == p_other.element_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &p_other) const { return element_ptr != p_other.element_ptr; }
|
||||
|
||||
_FORCE_INLINE_ Iterator(Variant *p_element_ptr, Variant *p_read_only = nullptr) :
|
||||
element_ptr(p_element_ptr), read_only(p_read_only) {}
|
||||
_FORCE_INLINE_ Iterator() {}
|
||||
_FORCE_INLINE_ Iterator(const Iterator &p_other) :
|
||||
element_ptr(p_other.element_ptr), read_only(p_other.read_only) {}
|
||||
|
||||
_FORCE_INLINE_ Iterator &operator=(const Iterator &p_other) {
|
||||
element_ptr = p_other.element_ptr;
|
||||
read_only = p_other.read_only;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator ConstIterator() const {
|
||||
return ConstIterator(element_ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
Variant *element_ptr = nullptr;
|
||||
Variant *read_only = nullptr;
|
||||
};
|
||||
|
||||
Iterator begin();
|
||||
Iterator end();
|
||||
|
||||
ConstIterator begin() const;
|
||||
ConstIterator end() const;
|
||||
|
||||
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 is_empty() const;
|
||||
void clear();
|
||||
|
||||
bool operator==(const Array &p_array) const;
|
||||
bool operator!=(const Array &p_array) const;
|
||||
bool recursive_equal(const Array &p_array, int recursion_count) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
uint32_t recursive_hash(int recursion_count) const;
|
||||
void operator=(const Array &p_array);
|
||||
|
||||
void assign(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);
|
||||
|
||||
Error insert(int p_pos, const Variant &p_value);
|
||||
void remove_at(int p_pos);
|
||||
void fill(const Variant &p_value);
|
||||
|
||||
Variant front() const;
|
||||
Variant back() const;
|
||||
Variant pick_random() const;
|
||||
|
||||
void sort();
|
||||
void sort_custom(const Callable &p_callable);
|
||||
void shuffle();
|
||||
int bsearch(const Variant &p_value, bool p_before = true) const;
|
||||
int bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before = true) const;
|
||||
void reverse();
|
||||
|
||||
int find(const Variant &p_value, int p_from = 0) const;
|
||||
int find_custom(const Callable &p_callable, int p_from = 0) const;
|
||||
int rfind(const Variant &p_value, int p_from = -1) const;
|
||||
int rfind_custom(const Callable &p_callable, int p_from = -1) 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 duplicate_deep(ResourceDeepDuplicateMode p_deep_subresources_mode = RESOURCE_DEEP_DUPLICATE_INTERNAL) const;
|
||||
Array recursive_duplicate(bool p_deep, ResourceDeepDuplicateMode p_deep_subresources_mode, int recursion_count) const;
|
||||
|
||||
Array slice(int p_begin, int p_end = INT_MAX, int p_step = 1, bool p_deep = false) const;
|
||||
Array filter(const Callable &p_callable) const;
|
||||
Array map(const Callable &p_callable) const;
|
||||
Variant reduce(const Callable &p_callable, const Variant &p_accum) const;
|
||||
bool any(const Callable &p_callable) const;
|
||||
bool all(const Callable &p_callable) const;
|
||||
|
||||
bool operator<(const Array &p_array) const;
|
||||
bool operator<=(const Array &p_array) const;
|
||||
bool operator>(const Array &p_array) const;
|
||||
bool operator>=(const Array &p_array) const;
|
||||
|
||||
Variant min() const;
|
||||
Variant max() const;
|
||||
|
||||
const void *id() const;
|
||||
|
||||
void set_typed(const ContainerType &p_element_type);
|
||||
void set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
|
||||
|
||||
bool is_typed() const;
|
||||
bool is_same_typed(const Array &p_other) const;
|
||||
bool is_same_instance(const Array &p_other) const;
|
||||
|
||||
ContainerType get_element_type() const;
|
||||
uint32_t get_typed_builtin() const;
|
||||
StringName get_typed_class_name() const;
|
||||
Variant get_typed_script() const;
|
||||
|
||||
void make_read_only();
|
||||
bool is_read_only() const;
|
||||
static Array create_read_only();
|
||||
|
||||
Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
|
||||
Array(const Array &p_from);
|
||||
Array(std::initializer_list<Variant> p_init);
|
||||
Array();
|
||||
~Array();
|
||||
};
|
||||
942
core/variant/binder_common.h
Normal file
942
core/variant/binder_common.h
Normal file
@@ -0,0 +1,942 @@
|
||||
/**************************************************************************/
|
||||
/* binder_common.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/input/input_enums.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/templates/simple_type.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/method_ptrcall.h"
|
||||
#include "core/variant/type_info.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "core/variant/variant_internal.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
// Variant cannot define an implicit cast operator for every Object subclass, so the
|
||||
// casting is done here, to allow binding methods with parameters more specific than Object *
|
||||
|
||||
template <typename T>
|
||||
struct VariantCaster {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of_v<Object, TStripped>) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCaster<T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of_v<Object, TStripped>) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCaster<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of_v<Object, TStripped>) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define VARIANT_ENUM_CAST(m_enum) MAKE_ENUM_TYPE_INFO(m_enum)
|
||||
#define VARIANT_BITFIELD_CAST(m_enum) MAKE_BITFIELD_TYPE_INFO(m_enum)
|
||||
|
||||
// Object enum casts must go here
|
||||
VARIANT_ENUM_CAST(Object::ConnectFlags);
|
||||
|
||||
VARIANT_ENUM_CAST(Vector2::Axis);
|
||||
VARIANT_ENUM_CAST(Vector2i::Axis);
|
||||
VARIANT_ENUM_CAST(Vector3::Axis);
|
||||
VARIANT_ENUM_CAST(Vector3i::Axis);
|
||||
VARIANT_ENUM_CAST(Vector4::Axis);
|
||||
VARIANT_ENUM_CAST(Vector4i::Axis);
|
||||
VARIANT_ENUM_CAST(EulerOrder);
|
||||
VARIANT_ENUM_CAST(Projection::Planes);
|
||||
|
||||
VARIANT_ENUM_CAST(Error);
|
||||
VARIANT_ENUM_CAST(Side);
|
||||
VARIANT_ENUM_CAST(ClockDirection);
|
||||
VARIANT_ENUM_CAST(Corner);
|
||||
VARIANT_ENUM_CAST(HatDir);
|
||||
VARIANT_BITFIELD_CAST(HatMask);
|
||||
VARIANT_ENUM_CAST(JoyAxis);
|
||||
VARIANT_ENUM_CAST(JoyButton);
|
||||
|
||||
VARIANT_ENUM_CAST(MIDIMessage);
|
||||
VARIANT_ENUM_CAST(MouseButton);
|
||||
VARIANT_BITFIELD_CAST(MouseButtonMask);
|
||||
VARIANT_ENUM_CAST(Orientation);
|
||||
VARIANT_ENUM_CAST(HorizontalAlignment);
|
||||
VARIANT_ENUM_CAST(VerticalAlignment);
|
||||
VARIANT_ENUM_CAST(InlineAlignment);
|
||||
VARIANT_ENUM_CAST(PropertyHint);
|
||||
VARIANT_BITFIELD_CAST(PropertyUsageFlags);
|
||||
VARIANT_ENUM_CAST(Variant::Type);
|
||||
VARIANT_ENUM_CAST(Variant::Operator);
|
||||
|
||||
// Key
|
||||
|
||||
VARIANT_ENUM_CAST(Key);
|
||||
VARIANT_BITFIELD_CAST(KeyModifierMask);
|
||||
VARIANT_ENUM_CAST(KeyLocation);
|
||||
|
||||
template <>
|
||||
struct VariantCaster<char32_t> {
|
||||
static _FORCE_INLINE_ char32_t cast(const Variant &p_variant) {
|
||||
return (char32_t)p_variant.operator int();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PtrToArg<char32_t> {
|
||||
_FORCE_INLINE_ static char32_t convert(const void *p_ptr) {
|
||||
return char32_t(*reinterpret_cast<const int64_t *>(p_ptr));
|
||||
}
|
||||
typedef int64_t EncodeT;
|
||||
_FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) {
|
||||
*(int64_t *)p_ptr = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantObjectClassChecker {
|
||||
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of_v<Object, TStripped>) {
|
||||
Object *obj = p_variant;
|
||||
return Object::cast_to<TStripped>(p_variant) || !obj;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Ref;
|
||||
|
||||
template <typename T>
|
||||
struct VariantObjectClassChecker<const Ref<T> &> {
|
||||
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
|
||||
Object *obj = p_variant;
|
||||
const Ref<T> node = p_variant;
|
||||
return node.ptr() || !obj;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
template <typename T>
|
||||
struct VariantCasterAndValidate {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
|
||||
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
|
||||
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCasterAndValidate<T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
|
||||
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
|
||||
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantCasterAndValidate<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
|
||||
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
|
||||
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
(void)(p_args); //avoid warning
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
(void)(p_args); //avoid warning
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
|
||||
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const void **p_args, IndexSequence<Is...>) {
|
||||
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_ptr_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const void **p_args, IndexSequence<Is...>) {
|
||||
p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <typename R, typename... P, size_t... Is>
|
||||
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <typename... P, size_t... Is>
|
||||
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
|
||||
p_method(PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
|
||||
(p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, IndexSequence<Is...>) {
|
||||
(p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
|
||||
VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
|
||||
VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
|
||||
VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, IndexSequence<Is...>) {
|
||||
p_method(p_instance, (VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
|
||||
}
|
||||
|
||||
template <typename R, typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_static_method_ret_helper(R (*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
|
||||
VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, p_method((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
|
||||
}
|
||||
|
||||
template <typename... P, size_t... Is>
|
||||
void call_with_validated_variant_args_static_method_helper(void (*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
|
||||
p_method((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_argsc(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
call_with_variant_argsc_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_argsc_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_ret_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_retc_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const void **p_args) {
|
||||
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_ptr_argsc(T *p_instance, void (T::*p_method)(P...) const, const void **p_args) {
|
||||
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_ptr_args_ret(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret) {
|
||||
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_ptr_args_retc(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret) {
|
||||
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_ptr_args_static(T *p_instance, void (*p_method)(T *, P...), const void **p_args) {
|
||||
call_with_ptr_args_static_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret) {
|
||||
call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename R, typename... P>
|
||||
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const void **p_args, void *r_ret) {
|
||||
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
void call_with_ptr_args_static_method(void (*p_method)(P...), const void **p_args) {
|
||||
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
// Validated
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
|
||||
call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_validated_variant_args_ret(Variant *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_ret_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_validated_variant_args_retc(Variant *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_validated_variant_args_static(Variant *base, void (*p_method)(T *, P...), const Variant **p_args) {
|
||||
call_with_validated_variant_args_static_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_static_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
void call_with_validated_variant_args_static_method(void (*p_method)(P...), const Variant **p_args) {
|
||||
call_with_validated_variant_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename R, typename... P>
|
||||
void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
// Validated Object
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_validated_object_instance_args(T *base, void (T::*p_method)(P...), const Variant **p_args) {
|
||||
call_with_validated_variant_args_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_validated_object_instance_argsc(T *base, void (T::*p_method)(P...) const, const Variant **p_args) {
|
||||
call_with_validated_variant_argsc_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_validated_object_instance_args_ret(T *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_ret_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_validated_object_instance_args_retc(T *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_retc_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_validated_object_instance_args_static(T *base, void (*p_method)(T *, P...), const Variant **p_args) {
|
||||
call_with_validated_variant_args_static_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_validated_object_instance_args_static_retc(T *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
|
||||
call_with_validated_variant_args_static_retc_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
// GCC raises "parameter 'p_args' set but not used" when P = {},
|
||||
// it's not clever enough to treat other P values as making this branch valid.
|
||||
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wunused-but-set-parameter")
|
||||
|
||||
template <typename Q>
|
||||
void call_get_argument_type_helper(int p_arg, int &index, Variant::Type &type) {
|
||||
if (p_arg == index) {
|
||||
type = GetTypeInfo<Q>::VARIANT_TYPE;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
Variant::Type call_get_argument_type(int p_arg) {
|
||||
Variant::Type type = Variant::NIL;
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_type_helper<P>(p_arg, index, type), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index; // Suppress GCC warning.
|
||||
return type;
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
|
||||
if (p_arg == index) {
|
||||
info = GetTypeInfo<Q>::get_class_info();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_type_info_helper<P>(p_arg, index, info), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index; // Suppress GCC warning.
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
template <typename Q>
|
||||
void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Metadata &md) {
|
||||
if (p_arg == index) {
|
||||
md = GetTypeInfo<Q>::METADATA;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) {
|
||||
GodotTypeInfo::Metadata md = GodotTypeInfo::METADATA_NONE;
|
||||
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_metadata_helper<P>(p_arg, index, md), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index;
|
||||
return md;
|
||||
}
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
//////////////////////
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename R, typename... P, size_t... Is>
|
||||
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
template <typename... P, size_t... Is>
|
||||
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
(p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
(void)p_args;
|
||||
}
|
||||
|
||||
template <typename R, typename... P>
|
||||
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)p_argcount < sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P, size_t... Is>
|
||||
void call_with_variant_args_retc_static_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
r_ret = (p_method)(p_instance, VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_method)(p_instance, VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
(void)p_args;
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... P>
|
||||
void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &default_values, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_retc_static_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename T, typename... P, size_t... Is>
|
||||
void call_with_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
(p_method)(p_instance, VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_method)(p_instance, VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
(void)p_args;
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, int p_argcount, const Vector<Variant> &default_values, Callable::CallError &r_error) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_static_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename R, typename... P>
|
||||
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_static_ret(p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.expected = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = p_args[i];
|
||||
} else {
|
||||
args[i] = &default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
}
|
||||
|
||||
call_with_variant_args_static(p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
GODOT_GCC_WARNING_POP
|
||||
605
core/variant/callable.cpp
Normal file
605
core/variant/callable.cpp
Normal file
@@ -0,0 +1,605 @@
|
||||
/**************************************************************************/
|
||||
/* callable.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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 "callable.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/variant/callable_bind.h"
|
||||
#include "core/variant/variant_callable.h"
|
||||
|
||||
void Callable::call_deferredp(const Variant **p_arguments, int p_argcount) const {
|
||||
MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount, true);
|
||||
}
|
||||
|
||||
void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const {
|
||||
if (is_null()) {
|
||||
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
|
||||
r_call_error.argument = 0;
|
||||
r_call_error.expected = 0;
|
||||
r_return_value = Variant();
|
||||
} else if (is_custom()) {
|
||||
if (!is_valid()) {
|
||||
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
|
||||
r_call_error.argument = 0;
|
||||
r_call_error.expected = 0;
|
||||
r_return_value = Variant();
|
||||
return;
|
||||
}
|
||||
custom->call(p_arguments, p_argcount, r_return_value, r_call_error);
|
||||
} else {
|
||||
Object *obj = ObjectDB::get_instance(ObjectID(object));
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (!obj) {
|
||||
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
|
||||
r_call_error.argument = 0;
|
||||
r_call_error.expected = 0;
|
||||
r_return_value = Variant();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
r_return_value = obj->callp(method, p_arguments, p_argcount, r_call_error);
|
||||
}
|
||||
}
|
||||
|
||||
Variant Callable::callv(const Array &p_arguments) const {
|
||||
int argcount = p_arguments.size();
|
||||
const Variant **argptrs = nullptr;
|
||||
if (argcount) {
|
||||
argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
|
||||
for (int i = 0; i < argcount; i++) {
|
||||
argptrs[i] = &p_arguments[i];
|
||||
}
|
||||
}
|
||||
CallError ce;
|
||||
Variant ret;
|
||||
callp(argptrs, argcount, ret, ce);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
|
||||
if (is_null()) {
|
||||
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
|
||||
r_call_error.argument = 0;
|
||||
r_call_error.expected = 0;
|
||||
return ERR_UNCONFIGURED;
|
||||
} else if (!is_custom()) {
|
||||
Object *obj = ObjectDB::get_instance(ObjectID(object));
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (!obj || !obj->is_class("Node")) {
|
||||
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
|
||||
r_call_error.argument = 0;
|
||||
r_call_error.expected = 0;
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
#endif
|
||||
|
||||
int argcount = p_argcount + 2;
|
||||
const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
|
||||
const Variant args[2] = { p_id, method };
|
||||
|
||||
argptrs[0] = &args[0];
|
||||
argptrs[1] = &args[1];
|
||||
for (int i = 0; i < p_argcount; ++i) {
|
||||
argptrs[i + 2] = p_arguments[i];
|
||||
}
|
||||
|
||||
CallError tmp; // TODO: Check `tmp`?
|
||||
Error err = (Error)obj->callp(SNAME("rpc_id"), argptrs, argcount, tmp).operator int64_t();
|
||||
|
||||
r_call_error.error = Callable::CallError::CALL_OK;
|
||||
return err;
|
||||
} else {
|
||||
return custom->rpc(p_id, p_arguments, p_argcount, r_call_error);
|
||||
}
|
||||
}
|
||||
|
||||
Callable Callable::bindp(const Variant **p_arguments, int p_argcount) const {
|
||||
Vector<Variant> args;
|
||||
args.resize(p_argcount);
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
args.write[i] = *p_arguments[i];
|
||||
}
|
||||
return Callable(memnew(CallableCustomBind(*this, args)));
|
||||
}
|
||||
|
||||
Callable Callable::bindv(const Array &p_arguments) {
|
||||
if (p_arguments.is_empty()) {
|
||||
return *this; // No point in creating a new callable if nothing is bound.
|
||||
}
|
||||
|
||||
Vector<Variant> args;
|
||||
args.resize(p_arguments.size());
|
||||
for (int i = 0; i < p_arguments.size(); i++) {
|
||||
args.write[i] = p_arguments[i];
|
||||
}
|
||||
return Callable(memnew(CallableCustomBind(*this, args)));
|
||||
}
|
||||
|
||||
Callable Callable::unbind(int p_argcount) const {
|
||||
ERR_FAIL_COND_V_MSG(p_argcount <= 0, Callable(*this), "Amount of unbind() arguments must be 1 or greater.");
|
||||
return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));
|
||||
}
|
||||
|
||||
bool Callable::is_valid() const {
|
||||
if (is_custom()) {
|
||||
return get_custom()->is_valid();
|
||||
} else {
|
||||
return get_object() && get_object()->has_method(get_method());
|
||||
}
|
||||
}
|
||||
|
||||
Object *Callable::get_object() const {
|
||||
if (is_null()) {
|
||||
return nullptr;
|
||||
} else if (is_custom()) {
|
||||
return ObjectDB::get_instance(custom->get_object());
|
||||
} else {
|
||||
return ObjectDB::get_instance(ObjectID(object));
|
||||
}
|
||||
}
|
||||
|
||||
ObjectID Callable::get_object_id() const {
|
||||
if (is_null()) {
|
||||
return ObjectID();
|
||||
} else if (is_custom()) {
|
||||
return custom->get_object();
|
||||
} else {
|
||||
return ObjectID(object);
|
||||
}
|
||||
}
|
||||
|
||||
StringName Callable::get_method() const {
|
||||
if (is_custom()) {
|
||||
return get_custom()->get_method();
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
int Callable::get_argument_count(bool *r_is_valid) const {
|
||||
if (is_custom()) {
|
||||
bool valid = false;
|
||||
return custom->get_argument_count(r_is_valid ? *r_is_valid : valid);
|
||||
} else if (is_valid()) {
|
||||
return get_object()->get_method_argument_count(method, r_is_valid);
|
||||
} else {
|
||||
if (r_is_valid) {
|
||||
*r_is_valid = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Callable::get_bound_arguments_count() const {
|
||||
if (!is_null() && is_custom()) {
|
||||
return custom->get_bound_arguments_count();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments) const {
|
||||
if (!is_null() && is_custom()) {
|
||||
custom->get_bound_arguments(r_arguments);
|
||||
} else {
|
||||
r_arguments.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Array Callable::get_bound_arguments() const {
|
||||
Vector<Variant> arr;
|
||||
get_bound_arguments_ref(arr);
|
||||
Array ret;
|
||||
ret.resize(arr.size());
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
ret[i] = arr[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Callable::get_unbound_arguments_count() const {
|
||||
if (!is_null() && is_custom()) {
|
||||
return custom->get_unbound_arguments_count();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
CallableCustom *Callable::get_custom() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
|
||||
vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
|
||||
return custom;
|
||||
}
|
||||
|
||||
const Callable *Callable::get_base_comparator() const {
|
||||
const Callable *comparator = nullptr;
|
||||
if (is_custom()) {
|
||||
comparator = custom->get_base_comparator();
|
||||
}
|
||||
if (comparator) {
|
||||
return comparator;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Callable::hash() const {
|
||||
if (is_custom()) {
|
||||
return custom->hash();
|
||||
} else {
|
||||
uint32_t hash = method.hash();
|
||||
hash = hash_murmur3_one_64(object, hash);
|
||||
return hash_fmix32(hash);
|
||||
}
|
||||
}
|
||||
|
||||
bool Callable::operator==(const Callable &p_callable) const {
|
||||
bool custom_a = is_custom();
|
||||
bool custom_b = p_callable.is_custom();
|
||||
|
||||
if (custom_a == custom_b) {
|
||||
if (custom_a) {
|
||||
if (custom == p_callable.custom) {
|
||||
return true; //same pointer, don't even compare
|
||||
}
|
||||
|
||||
CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func();
|
||||
CallableCustom::CompareEqualFunc eq_b = p_callable.custom->get_compare_equal_func();
|
||||
if (eq_a == eq_b) {
|
||||
return eq_a(custom, p_callable.custom);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return object == p_callable.object && method == p_callable.method;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Callable::operator!=(const Callable &p_callable) const {
|
||||
return !(*this == p_callable);
|
||||
}
|
||||
|
||||
bool Callable::operator<(const Callable &p_callable) const {
|
||||
bool custom_a = is_custom();
|
||||
bool custom_b = p_callable.is_custom();
|
||||
|
||||
if (custom_a == custom_b) {
|
||||
if (custom_a) {
|
||||
if (custom == p_callable.custom) {
|
||||
return false; //same pointer, don't even compare
|
||||
}
|
||||
|
||||
CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func();
|
||||
CallableCustom::CompareLessFunc less_b = p_callable.custom->get_compare_less_func();
|
||||
if (less_a == less_b) {
|
||||
return less_a(custom, p_callable.custom);
|
||||
} else {
|
||||
return less_a < less_b; //it's something..
|
||||
}
|
||||
|
||||
} else {
|
||||
if (object == p_callable.object) {
|
||||
return method < p_callable.method;
|
||||
} else {
|
||||
return object < p_callable.object;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return int(custom_a ? 1 : 0) < int(custom_b ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Callable::operator=(const Callable &p_callable) {
|
||||
CallableCustom *cleanup_ref = nullptr;
|
||||
if (is_custom()) {
|
||||
if (p_callable.is_custom()) {
|
||||
if (custom == p_callable.custom) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
cleanup_ref = custom;
|
||||
custom = nullptr;
|
||||
}
|
||||
|
||||
if (p_callable.is_custom()) {
|
||||
method = StringName();
|
||||
object = 0;
|
||||
if (p_callable.custom->ref_count.ref()) {
|
||||
custom = p_callable.custom;
|
||||
}
|
||||
} else {
|
||||
method = p_callable.method;
|
||||
object = p_callable.object;
|
||||
}
|
||||
|
||||
if (cleanup_ref != nullptr && cleanup_ref->ref_count.unref()) {
|
||||
memdelete(cleanup_ref);
|
||||
}
|
||||
cleanup_ref = nullptr;
|
||||
}
|
||||
|
||||
Callable::operator String() const {
|
||||
if (is_custom()) {
|
||||
return custom->get_as_text();
|
||||
} else {
|
||||
if (is_null()) {
|
||||
return "null::null";
|
||||
}
|
||||
|
||||
Object *base = get_object();
|
||||
if (base) {
|
||||
String class_name = base->get_class();
|
||||
Ref<Script> script = base->get_script();
|
||||
if (script.is_valid()) {
|
||||
if (!script->get_global_name().is_empty()) {
|
||||
class_name += "(" + script->get_global_name() + ")";
|
||||
} else if (script->get_path().is_resource_file()) {
|
||||
class_name += "(" + script->get_path().get_file() + ")";
|
||||
}
|
||||
}
|
||||
return class_name + "::" + String(method);
|
||||
} else {
|
||||
return "null::" + String(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Callable Callable::create(const Variant &p_variant, const StringName &p_method) {
|
||||
ERR_FAIL_COND_V_MSG(p_method == StringName(), Callable(), "Method argument to Callable::create method must be a non-empty string.");
|
||||
|
||||
switch (p_variant.get_type()) {
|
||||
case Variant::NIL:
|
||||
return Callable(ObjectID(), p_method);
|
||||
case Variant::OBJECT:
|
||||
return Callable(p_variant.operator ObjectID(), p_method);
|
||||
default:
|
||||
return Callable(memnew(VariantCallable(p_variant, p_method)));
|
||||
}
|
||||
}
|
||||
|
||||
Callable::Callable(const Object *p_object, const StringName &p_method) {
|
||||
if (unlikely(p_method == StringName())) {
|
||||
object = 0;
|
||||
ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string.");
|
||||
}
|
||||
if (unlikely(p_object == nullptr)) {
|
||||
object = 0;
|
||||
ERR_FAIL_MSG("Object argument to Callable constructor must be non-null.");
|
||||
}
|
||||
|
||||
object = p_object->get_instance_id();
|
||||
method = p_method;
|
||||
}
|
||||
|
||||
Callable::Callable(ObjectID p_object, const StringName &p_method) {
|
||||
if (unlikely(p_method == StringName())) {
|
||||
object = 0;
|
||||
ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string.");
|
||||
}
|
||||
|
||||
object = p_object;
|
||||
method = p_method;
|
||||
}
|
||||
|
||||
Callable::Callable(CallableCustom *p_custom) {
|
||||
if (unlikely(p_custom->referenced)) {
|
||||
object = 0;
|
||||
ERR_FAIL_MSG("Callable custom is already referenced.");
|
||||
}
|
||||
p_custom->referenced = true;
|
||||
object = 0; //ensure object is all zero, since pointer may be 32 bits
|
||||
custom = p_custom;
|
||||
}
|
||||
|
||||
Callable::Callable(const Callable &p_callable) {
|
||||
if (p_callable.is_custom()) {
|
||||
if (!p_callable.custom->ref_count.ref()) {
|
||||
object = 0;
|
||||
} else {
|
||||
object = 0;
|
||||
custom = p_callable.custom;
|
||||
}
|
||||
} else {
|
||||
method = p_callable.method;
|
||||
object = p_callable.object;
|
||||
}
|
||||
}
|
||||
|
||||
Callable::~Callable() {
|
||||
if (is_custom()) {
|
||||
if (custom->ref_count.unref()) {
|
||||
memdelete(custom);
|
||||
custom = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CallableCustom::is_valid() const {
|
||||
// Sensible default implementation so most custom callables don't need their own.
|
||||
return ObjectDB::get_instance(get_object());
|
||||
}
|
||||
|
||||
StringName CallableCustom::get_method() const {
|
||||
ERR_FAIL_V_MSG(StringName(), vformat("Can't get method on CallableCustom \"%s\".", get_as_text()));
|
||||
}
|
||||
|
||||
Error CallableCustom::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
|
||||
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
|
||||
r_call_error.argument = 0;
|
||||
r_call_error.expected = 0;
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
|
||||
const Callable *CallableCustom::get_base_comparator() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int CallableCustom::get_argument_count(bool &r_is_valid) const {
|
||||
r_is_valid = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CallableCustom::get_bound_arguments_count() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments) const {
|
||||
r_arguments.clear();
|
||||
}
|
||||
|
||||
int CallableCustom::get_unbound_arguments_count() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CallableCustom::CallableCustom() {
|
||||
ref_count.init();
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
|
||||
Object *Signal::get_object() const {
|
||||
return ObjectDB::get_instance(object);
|
||||
}
|
||||
|
||||
ObjectID Signal::get_object_id() const {
|
||||
return object;
|
||||
}
|
||||
|
||||
StringName Signal::get_name() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
bool Signal::operator==(const Signal &p_signal) const {
|
||||
return object == p_signal.object && name == p_signal.name;
|
||||
}
|
||||
|
||||
bool Signal::operator!=(const Signal &p_signal) const {
|
||||
return object != p_signal.object || name != p_signal.name;
|
||||
}
|
||||
|
||||
bool Signal::operator<(const Signal &p_signal) const {
|
||||
if (object == p_signal.object) {
|
||||
return name < p_signal.name;
|
||||
} else {
|
||||
return object < p_signal.object;
|
||||
}
|
||||
}
|
||||
|
||||
Signal::operator String() const {
|
||||
Object *base = get_object();
|
||||
if (base) {
|
||||
String class_name = base->get_class();
|
||||
Ref<Script> script = base->get_script();
|
||||
if (script.is_valid() && script->get_path().is_resource_file()) {
|
||||
class_name += "(" + script->get_path().get_file() + ")";
|
||||
}
|
||||
return class_name + "::[signal]" + String(name);
|
||||
} else {
|
||||
return "null::[signal]" + String(name);
|
||||
}
|
||||
}
|
||||
|
||||
Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
|
||||
Object *obj = ObjectDB::get_instance(object);
|
||||
if (!obj) {
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
||||
return obj->emit_signalp(name, p_arguments, p_argcount);
|
||||
}
|
||||
|
||||
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
|
||||
Object *obj = get_object();
|
||||
ERR_FAIL_NULL_V(obj, ERR_UNCONFIGURED);
|
||||
|
||||
return obj->connect(name, p_callable, p_flags);
|
||||
}
|
||||
|
||||
void Signal::disconnect(const Callable &p_callable) {
|
||||
Object *obj = get_object();
|
||||
ERR_FAIL_NULL(obj);
|
||||
obj->disconnect(name, p_callable);
|
||||
}
|
||||
|
||||
bool Signal::is_connected(const Callable &p_callable) const {
|
||||
Object *obj = get_object();
|
||||
ERR_FAIL_NULL_V(obj, false);
|
||||
|
||||
return obj->is_connected(name, p_callable);
|
||||
}
|
||||
|
||||
bool Signal::has_connections() const {
|
||||
Object *obj = get_object();
|
||||
ERR_FAIL_NULL_V(obj, false);
|
||||
|
||||
return obj->has_connections(name);
|
||||
}
|
||||
|
||||
Array Signal::get_connections() const {
|
||||
Object *obj = get_object();
|
||||
if (!obj) {
|
||||
return Array();
|
||||
}
|
||||
|
||||
List<Object::Connection> connections;
|
||||
obj->get_signal_connection_list(name, &connections);
|
||||
|
||||
Array arr;
|
||||
for (const Object::Connection &E : connections) {
|
||||
arr.push_back(E);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
Signal::Signal(const Object *p_object, const StringName &p_name) {
|
||||
ERR_FAIL_NULL_MSG(p_object, "Object argument to Signal constructor must be non-null.");
|
||||
|
||||
object = p_object->get_instance_id();
|
||||
name = p_name;
|
||||
}
|
||||
|
||||
Signal::Signal(ObjectID p_object, const StringName &p_name) {
|
||||
object = p_object;
|
||||
name = p_name;
|
||||
}
|
||||
|
||||
bool CallableComparator::operator()(const Variant &p_l, const Variant &p_r) const {
|
||||
const Variant *args[2] = { &p_l, &p_r };
|
||||
Callable::CallError err;
|
||||
Variant res;
|
||||
func.callp(args, 2, res, err);
|
||||
ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false,
|
||||
"Error calling compare method: " + Variant::get_callable_error_text(func, args, 2, err));
|
||||
return res;
|
||||
}
|
||||
215
core/variant/callable.h
Normal file
215
core/variant/callable.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/**************************************************************************/
|
||||
/* callable.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/string/string_name.h"
|
||||
|
||||
class Object;
|
||||
class Variant;
|
||||
class CallableCustom;
|
||||
|
||||
// This is an abstraction of things that can be called.
|
||||
// It is used for signals and other cases where efficient calling of functions
|
||||
// is required. It is designed for the standard case (object and method)
|
||||
// but can be optimized or customized.
|
||||
|
||||
// Enforce 16 bytes with `alignas` to avoid arch-specific alignment issues on x86 vs armv7.
|
||||
|
||||
class Callable {
|
||||
alignas(8) StringName method;
|
||||
union {
|
||||
uint64_t object = 0;
|
||||
CallableCustom *custom;
|
||||
};
|
||||
|
||||
public:
|
||||
struct CallError {
|
||||
enum Error {
|
||||
CALL_OK,
|
||||
CALL_ERROR_INVALID_METHOD,
|
||||
CALL_ERROR_INVALID_ARGUMENT, // expected is variant type
|
||||
CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments
|
||||
CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
|
||||
CALL_ERROR_INSTANCE_IS_NULL,
|
||||
CALL_ERROR_METHOD_NOT_CONST,
|
||||
};
|
||||
Error error = Error::CALL_OK;
|
||||
int argument = 0;
|
||||
int expected = 0;
|
||||
};
|
||||
|
||||
template <typename... VarArgs>
|
||||
Variant call(VarArgs... p_args) const;
|
||||
void callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
|
||||
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
|
||||
Variant callv(const Array &p_arguments) const;
|
||||
|
||||
template <typename... VarArgs>
|
||||
void call_deferred(VarArgs... p_args) const {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., 0 }; // +1 makes sure zero sized arrays are also supported.
|
||||
const Variant *argptrs[sizeof...(p_args) + 1];
|
||||
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
|
||||
argptrs[i] = &args[i];
|
||||
}
|
||||
return call_deferredp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
|
||||
|
||||
_FORCE_INLINE_ bool is_null() const {
|
||||
return method == StringName() && object == 0;
|
||||
}
|
||||
_FORCE_INLINE_ bool is_custom() const {
|
||||
return method == StringName() && custom != nullptr;
|
||||
}
|
||||
_FORCE_INLINE_ bool is_standard() const {
|
||||
return method != StringName();
|
||||
}
|
||||
bool is_valid() const;
|
||||
|
||||
template <typename... VarArgs>
|
||||
Callable bind(VarArgs... p_args) const;
|
||||
Callable bindv(const Array &p_arguments);
|
||||
|
||||
Callable bindp(const Variant **p_arguments, int p_argcount) const;
|
||||
Callable unbind(int p_argcount) const;
|
||||
|
||||
Object *get_object() const;
|
||||
ObjectID get_object_id() const;
|
||||
StringName get_method() const;
|
||||
CallableCustom *get_custom() const;
|
||||
int get_argument_count(bool *r_is_valid = nullptr) const;
|
||||
int get_bound_arguments_count() const;
|
||||
void get_bound_arguments_ref(Vector<Variant> &r_arguments) const; // Internal engine use, the exposed one is below.
|
||||
Array get_bound_arguments() const;
|
||||
int get_unbound_arguments_count() const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
const Callable *get_base_comparator() const; //used for bind/unbind to do less precise comparisons (ignoring binds) in signal connect/disconnect
|
||||
|
||||
bool operator==(const Callable &p_callable) const;
|
||||
bool operator!=(const Callable &p_callable) const;
|
||||
bool operator<(const Callable &p_callable) const;
|
||||
|
||||
void operator=(const Callable &p_callable);
|
||||
|
||||
explicit operator String() const;
|
||||
|
||||
static Callable create(const Variant &p_variant, const StringName &p_method);
|
||||
|
||||
Callable(const Object *p_object, const StringName &p_method);
|
||||
Callable(ObjectID p_object, const StringName &p_method);
|
||||
Callable(CallableCustom *p_custom);
|
||||
Callable(const Callable &p_callable);
|
||||
Callable() {}
|
||||
~Callable();
|
||||
};
|
||||
|
||||
// Zero-constructing Callable initializes method and object to 0 (and thus empty).
|
||||
template <>
|
||||
struct is_zero_constructible<Callable> : std::true_type {};
|
||||
|
||||
class CallableCustom {
|
||||
friend class Callable;
|
||||
SafeRefCount ref_count;
|
||||
bool referenced = false;
|
||||
|
||||
public:
|
||||
typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
|
||||
//for every type that inherits, these must always be the same for this type
|
||||
virtual uint32_t hash() const = 0;
|
||||
virtual String get_as_text() const = 0;
|
||||
virtual CompareEqualFunc get_compare_equal_func() const = 0;
|
||||
virtual CompareLessFunc get_compare_less_func() const = 0;
|
||||
virtual bool is_valid() const;
|
||||
virtual StringName get_method() const;
|
||||
virtual ObjectID get_object() const = 0;
|
||||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
|
||||
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const;
|
||||
virtual const Callable *get_base_comparator() const;
|
||||
virtual int get_argument_count(bool &r_is_valid) const;
|
||||
virtual int get_bound_arguments_count() const;
|
||||
virtual void get_bound_arguments(Vector<Variant> &r_arguments) const;
|
||||
virtual int get_unbound_arguments_count() const;
|
||||
|
||||
CallableCustom();
|
||||
virtual ~CallableCustom() {}
|
||||
};
|
||||
|
||||
// This is just a proxy object to object signals, its only
|
||||
// allocated on demand by/for scripting languages so it can
|
||||
// be put inside a Variant, but it is not
|
||||
// used by the engine itself.
|
||||
|
||||
// Enforce 16 bytes with `alignas` to avoid arch-specific alignment issues on x86 vs armv7.
|
||||
class Signal {
|
||||
alignas(8) StringName name;
|
||||
ObjectID object;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool is_null() const {
|
||||
return object.is_null() && name == StringName();
|
||||
}
|
||||
Object *get_object() const;
|
||||
ObjectID get_object_id() const;
|
||||
StringName get_name() const;
|
||||
|
||||
bool operator==(const Signal &p_signal) const;
|
||||
bool operator!=(const Signal &p_signal) const;
|
||||
bool operator<(const Signal &p_signal) const;
|
||||
|
||||
explicit operator String() const;
|
||||
|
||||
Error emit(const Variant **p_arguments, int p_argcount) const;
|
||||
Error connect(const Callable &p_callable, uint32_t p_flags = 0);
|
||||
void disconnect(const Callable &p_callable);
|
||||
bool is_connected(const Callable &p_callable) const;
|
||||
bool has_connections() const;
|
||||
|
||||
Array get_connections() const;
|
||||
Signal(const Object *p_object, const StringName &p_name);
|
||||
Signal(ObjectID p_object, const StringName &p_name);
|
||||
Signal() {}
|
||||
};
|
||||
|
||||
// Zero-constructing Signal initializes name and object to 0 (and thus empty).
|
||||
template <>
|
||||
struct is_zero_constructible<Signal> : std::true_type {};
|
||||
|
||||
struct CallableComparator {
|
||||
const Callable &func;
|
||||
|
||||
bool operator()(const Variant &p_l, const Variant &p_r) const;
|
||||
};
|
||||
278
core/variant/callable_bind.cpp
Normal file
278
core/variant/callable_bind.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/**************************************************************************/
|
||||
/* callable_bind.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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 "callable_bind.h"
|
||||
|
||||
//////////////////////////////////
|
||||
|
||||
uint32_t CallableCustomBind::hash() const {
|
||||
return callable.hash();
|
||||
}
|
||||
String CallableCustomBind::get_as_text() const {
|
||||
return callable.operator String();
|
||||
}
|
||||
|
||||
bool CallableCustomBind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||
const CallableCustomBind *a = static_cast<const CallableCustomBind *>(p_a);
|
||||
const CallableCustomBind *b = static_cast<const CallableCustomBind *>(p_b);
|
||||
|
||||
if (a->callable != b->callable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->binds.size() != b->binds.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallableCustomBind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||
const CallableCustomBind *a = static_cast<const CallableCustomBind *>(p_a);
|
||||
const CallableCustomBind *b = static_cast<const CallableCustomBind *>(p_b);
|
||||
|
||||
if (a->callable < b->callable) {
|
||||
return true;
|
||||
} else if (b->callable < a->callable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return a->binds.size() < b->binds.size();
|
||||
}
|
||||
|
||||
CallableCustom::CompareEqualFunc CallableCustomBind::get_compare_equal_func() const {
|
||||
return _equal_func;
|
||||
}
|
||||
|
||||
CallableCustom::CompareLessFunc CallableCustomBind::get_compare_less_func() const {
|
||||
return _less_func;
|
||||
}
|
||||
|
||||
bool CallableCustomBind::is_valid() const {
|
||||
return callable.is_valid();
|
||||
}
|
||||
|
||||
StringName CallableCustomBind::get_method() const {
|
||||
return callable.get_method();
|
||||
}
|
||||
|
||||
ObjectID CallableCustomBind::get_object() const {
|
||||
return callable.get_object_id();
|
||||
}
|
||||
|
||||
const Callable *CallableCustomBind::get_base_comparator() const {
|
||||
return callable.get_base_comparator();
|
||||
}
|
||||
|
||||
int CallableCustomBind::get_argument_count(bool &r_is_valid) const {
|
||||
int ret = callable.get_argument_count(&r_is_valid);
|
||||
if (r_is_valid) {
|
||||
return ret - binds.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CallableCustomBind::get_bound_arguments_count() const {
|
||||
return callable.get_bound_arguments_count() + MAX(0, binds.size() - callable.get_unbound_arguments_count());
|
||||
}
|
||||
|
||||
void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments) const {
|
||||
Vector<Variant> sub_bound_args;
|
||||
callable.get_bound_arguments_ref(sub_bound_args);
|
||||
int sub_bound_count = sub_bound_args.size();
|
||||
|
||||
int sub_unbound_count = callable.get_unbound_arguments_count();
|
||||
|
||||
if (sub_bound_count == 0 && sub_unbound_count == 0) {
|
||||
r_arguments = binds;
|
||||
return;
|
||||
}
|
||||
|
||||
int added_count = MAX(0, binds.size() - sub_unbound_count);
|
||||
int new_count = sub_bound_count + added_count;
|
||||
|
||||
if (added_count <= 0) {
|
||||
// All added arguments are consumed by `sub_unbound_count`.
|
||||
r_arguments = sub_bound_args;
|
||||
return;
|
||||
}
|
||||
|
||||
r_arguments.resize(new_count);
|
||||
Variant *args = r_arguments.ptrw();
|
||||
for (int i = 0; i < added_count; i++) {
|
||||
args[i] = binds[i];
|
||||
}
|
||||
for (int i = 0; i < sub_bound_count; i++) {
|
||||
args[i + added_count] = sub_bound_args[i];
|
||||
}
|
||||
}
|
||||
|
||||
int CallableCustomBind::get_unbound_arguments_count() const {
|
||||
return MAX(0, callable.get_unbound_arguments_count() - binds.size());
|
||||
}
|
||||
|
||||
void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
const Variant **args = (const Variant **)alloca(sizeof(Variant *) * (binds.size() + p_argcount));
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
args[i] = (const Variant *)p_arguments[i];
|
||||
}
|
||||
for (int i = 0; i < binds.size(); i++) {
|
||||
args[i + p_argcount] = (const Variant *)&binds[i];
|
||||
}
|
||||
|
||||
callable.callp(args, p_argcount + binds.size(), r_return_value, r_call_error);
|
||||
}
|
||||
|
||||
Error CallableCustomBind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
|
||||
const Variant **args = (const Variant **)alloca(sizeof(Variant *) * (binds.size() + p_argcount));
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
args[i] = (const Variant *)p_arguments[i];
|
||||
}
|
||||
for (int i = 0; i < binds.size(); i++) {
|
||||
args[i + p_argcount] = (const Variant *)&binds[i];
|
||||
}
|
||||
|
||||
return callable.rpcp(p_peer_id, args, p_argcount + binds.size(), r_call_error);
|
||||
}
|
||||
|
||||
CallableCustomBind::CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds) {
|
||||
callable = p_callable;
|
||||
binds = p_binds;
|
||||
}
|
||||
|
||||
CallableCustomBind::~CallableCustomBind() {
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
|
||||
uint32_t CallableCustomUnbind::hash() const {
|
||||
return callable.hash();
|
||||
}
|
||||
String CallableCustomUnbind::get_as_text() const {
|
||||
return callable.operator String();
|
||||
}
|
||||
|
||||
bool CallableCustomUnbind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||
const CallableCustomUnbind *a = static_cast<const CallableCustomUnbind *>(p_a);
|
||||
const CallableCustomUnbind *b = static_cast<const CallableCustomUnbind *>(p_b);
|
||||
|
||||
if (a->callable != b->callable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->argcount != b->argcount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallableCustomUnbind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||
const CallableCustomUnbind *a = static_cast<const CallableCustomUnbind *>(p_a);
|
||||
const CallableCustomUnbind *b = static_cast<const CallableCustomUnbind *>(p_b);
|
||||
|
||||
if (a->callable < b->callable) {
|
||||
return true;
|
||||
} else if (b->callable < a->callable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return a->argcount < b->argcount;
|
||||
}
|
||||
|
||||
CallableCustom::CompareEqualFunc CallableCustomUnbind::get_compare_equal_func() const {
|
||||
return _equal_func;
|
||||
}
|
||||
|
||||
CallableCustom::CompareLessFunc CallableCustomUnbind::get_compare_less_func() const {
|
||||
return _less_func;
|
||||
}
|
||||
|
||||
bool CallableCustomUnbind::is_valid() const {
|
||||
return callable.is_valid();
|
||||
}
|
||||
|
||||
StringName CallableCustomUnbind::get_method() const {
|
||||
return callable.get_method();
|
||||
}
|
||||
|
||||
ObjectID CallableCustomUnbind::get_object() const {
|
||||
return callable.get_object_id();
|
||||
}
|
||||
|
||||
const Callable *CallableCustomUnbind::get_base_comparator() const {
|
||||
return callable.get_base_comparator();
|
||||
}
|
||||
|
||||
int CallableCustomUnbind::get_argument_count(bool &r_is_valid) const {
|
||||
int ret = callable.get_argument_count(&r_is_valid);
|
||||
if (r_is_valid) {
|
||||
return ret + argcount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CallableCustomUnbind::get_bound_arguments_count() const {
|
||||
return callable.get_bound_arguments_count();
|
||||
}
|
||||
|
||||
void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments) const {
|
||||
callable.get_bound_arguments_ref(r_arguments);
|
||||
}
|
||||
|
||||
int CallableCustomUnbind::get_unbound_arguments_count() const {
|
||||
return callable.get_unbound_arguments_count() + argcount;
|
||||
}
|
||||
|
||||
void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
if (p_argcount < argcount) {
|
||||
r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_call_error.expected = argcount;
|
||||
return;
|
||||
}
|
||||
callable.callp(p_arguments, p_argcount - argcount, r_return_value, r_call_error);
|
||||
}
|
||||
|
||||
Error CallableCustomUnbind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
|
||||
if (p_argcount < argcount) {
|
||||
r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_call_error.expected = argcount;
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
return callable.rpcp(p_peer_id, p_arguments, p_argcount - argcount, r_call_error);
|
||||
}
|
||||
|
||||
CallableCustomUnbind::CallableCustomUnbind(const Callable &p_callable, int p_argcount) {
|
||||
callable = p_callable;
|
||||
argcount = p_argcount;
|
||||
}
|
||||
|
||||
CallableCustomUnbind::~CallableCustomUnbind() {
|
||||
}
|
||||
95
core/variant/callable_bind.h
Normal file
95
core/variant/callable_bind.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**************************************************************************/
|
||||
/* callable_bind.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/variant/callable.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class CallableCustomBind : public CallableCustom {
|
||||
Callable callable;
|
||||
Vector<Variant> binds;
|
||||
|
||||
static bool _equal_func(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
static bool _less_func(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
|
||||
public:
|
||||
//for every type that inherits, these must always be the same for this type
|
||||
virtual uint32_t hash() const override;
|
||||
virtual String get_as_text() const override;
|
||||
virtual CompareEqualFunc get_compare_equal_func() const override;
|
||||
virtual CompareLessFunc get_compare_less_func() const override;
|
||||
virtual bool is_valid() const override;
|
||||
virtual StringName get_method() const override;
|
||||
virtual ObjectID get_object() const override;
|
||||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
|
||||
virtual const Callable *get_base_comparator() const override;
|
||||
virtual int get_argument_count(bool &r_is_valid) const override;
|
||||
virtual int get_bound_arguments_count() const override;
|
||||
virtual void get_bound_arguments(Vector<Variant> &r_arguments) const override;
|
||||
virtual int get_unbound_arguments_count() const override;
|
||||
Callable get_callable() { return callable; }
|
||||
Vector<Variant> get_binds() { return binds; }
|
||||
|
||||
CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds);
|
||||
virtual ~CallableCustomBind();
|
||||
};
|
||||
|
||||
class CallableCustomUnbind : public CallableCustom {
|
||||
Callable callable;
|
||||
int argcount;
|
||||
|
||||
static bool _equal_func(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
static bool _less_func(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
|
||||
public:
|
||||
//for every type that inherits, these must always be the same for this type
|
||||
virtual uint32_t hash() const override;
|
||||
virtual String get_as_text() const override;
|
||||
virtual CompareEqualFunc get_compare_equal_func() const override;
|
||||
virtual CompareLessFunc get_compare_less_func() const override;
|
||||
virtual bool is_valid() const override;
|
||||
virtual StringName get_method() const override;
|
||||
virtual ObjectID get_object() const override;
|
||||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
|
||||
virtual const Callable *get_base_comparator() const override;
|
||||
virtual int get_argument_count(bool &r_is_valid) const override;
|
||||
virtual int get_bound_arguments_count() const override;
|
||||
virtual void get_bound_arguments(Vector<Variant> &r_arguments) const override;
|
||||
virtual int get_unbound_arguments_count() const override;
|
||||
|
||||
Callable get_callable() { return callable; }
|
||||
int get_unbinds() { return argcount; }
|
||||
|
||||
CallableCustomUnbind(const Callable &p_callable, int p_argcount);
|
||||
virtual ~CallableCustomUnbind();
|
||||
};
|
||||
190
core/variant/container_type_validate.h
Normal file
190
core/variant/container_type_validate.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/**************************************************************************/
|
||||
/* container_type_validate.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
struct ContainerType {
|
||||
Variant::Type builtin_type = Variant::NIL;
|
||||
StringName class_name;
|
||||
Ref<Script> script;
|
||||
};
|
||||
|
||||
struct ContainerTypeValidate {
|
||||
Variant::Type type = Variant::NIL;
|
||||
StringName class_name;
|
||||
Ref<Script> script;
|
||||
const char *where = "container";
|
||||
|
||||
private:
|
||||
// Coerces String and StringName into each other and int into float when needed.
|
||||
_FORCE_INLINE_ bool _internal_validate(Variant &inout_variant, const char *p_operation, bool p_output_errors) const {
|
||||
if (type == Variant::NIL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type != inout_variant.get_type()) {
|
||||
if (inout_variant.get_type() == Variant::NIL && type == Variant::OBJECT) {
|
||||
return true;
|
||||
}
|
||||
if (type == Variant::STRING && inout_variant.get_type() == Variant::STRING_NAME) {
|
||||
inout_variant = String(inout_variant);
|
||||
return true;
|
||||
} else if (type == Variant::STRING_NAME && inout_variant.get_type() == Variant::STRING) {
|
||||
inout_variant = StringName(inout_variant);
|
||||
return true;
|
||||
} else if (type == Variant::FLOAT && inout_variant.get_type() == Variant::INT) {
|
||||
inout_variant = (float)inout_variant;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p_output_errors) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Attempted to %s a variable of type '%s' into a %s of type '%s'.", String(p_operation), Variant::get_type_name(inout_variant.get_type()), where, Variant::get_type_name(type)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != Variant::OBJECT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _internal_validate_object(inout_variant, p_operation, p_output_errors);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool _internal_validate_object(const Variant &p_variant, const char *p_operation, bool p_output_errors) const {
|
||||
ERR_FAIL_COND_V(p_variant.get_type() != Variant::OBJECT, false);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ObjectID object_id = p_variant;
|
||||
if (object_id == ObjectID()) {
|
||||
return true; // This is fine, it's null.
|
||||
}
|
||||
Object *object = ObjectDB::get_instance(object_id);
|
||||
if (object == nullptr) {
|
||||
if (p_output_errors) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Attempted to %s an invalid (previously freed?) object instance into a '%s'.", String(p_operation), String(where)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
Object *object = p_variant;
|
||||
if (object == nullptr) {
|
||||
return true; //fine
|
||||
}
|
||||
#endif
|
||||
if (class_name == StringName()) {
|
||||
return true; // All good, no class type requested.
|
||||
}
|
||||
|
||||
const StringName &obj_class = object->get_class_name();
|
||||
if (obj_class != class_name && !ClassDB::is_parent_class(obj_class, class_name)) {
|
||||
if (p_output_errors) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Attempted to %s an object of type '%s' into a %s, which does not inherit from '%s'.", String(p_operation), object->get_class(), where, String(class_name)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (script.is_null()) {
|
||||
return true; // All good, no script requested.
|
||||
}
|
||||
|
||||
Ref<Script> other_script = object->get_script();
|
||||
|
||||
// Check base script..
|
||||
if (other_script.is_null()) {
|
||||
if (p_output_errors) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Attempted to %s an object into a %s, that does not inherit from '%s'.", String(p_operation), String(where), String(script->get_class_name())));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!other_script->inherits_script(script)) {
|
||||
if (p_output_errors) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Attempted to %s an object into a %s, that does not inherit from '%s'.", String(p_operation), String(where), String(script->get_class_name())));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool validate(Variant &inout_variant, const char *p_operation = "use") const {
|
||||
return _internal_validate(inout_variant, p_operation, true);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool validate_object(const Variant &p_variant, const char *p_operation = "use") const {
|
||||
return _internal_validate_object(p_variant, p_operation, true);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool test_validate(const Variant &p_variant) const {
|
||||
Variant tmp = p_variant;
|
||||
return _internal_validate(tmp, "", false);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool can_reference(const ContainerTypeValidate &p_type) const {
|
||||
if (type != p_type.type) {
|
||||
return false;
|
||||
} else if (type != Variant::OBJECT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (class_name == StringName()) {
|
||||
return true;
|
||||
} else if (p_type.class_name == StringName()) {
|
||||
return false;
|
||||
} else if (class_name != p_type.class_name && !ClassDB::is_parent_class(p_type.class_name, class_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (script.is_null()) {
|
||||
return true;
|
||||
} else if (p_type.script.is_null()) {
|
||||
return false;
|
||||
} else if (script != p_type.script && !p_type.script->inherits_script(script)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ContainerTypeValidate &p_type) const {
|
||||
return type == p_type.type && class_name == p_type.class_name && script == p_type.script;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator!=(const ContainerTypeValidate &p_type) const {
|
||||
return type != p_type.type || class_name != p_type.class_name || script != p_type.script;
|
||||
}
|
||||
};
|
||||
772
core/variant/dictionary.cpp
Normal file
772
core/variant/dictionary.cpp
Normal file
@@ -0,0 +1,772 @@
|
||||
/**************************************************************************/
|
||||
/* dictionary.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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/templates/hash_map.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/variant/container_type_validate.h"
|
||||
#include "core/variant/variant.h"
|
||||
// required in this order by VariantInternal, do not remove this comment.
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/type_info.h"
|
||||
#include "core/variant/variant_internal.h"
|
||||
|
||||
struct DictionaryPrivate {
|
||||
SafeRefCount refcount;
|
||||
Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator> variant_map;
|
||||
ContainerTypeValidate typed_key;
|
||||
ContainerTypeValidate typed_value;
|
||||
Variant *typed_fallback = nullptr; // Allows a typed dictionary to return dummy values when attempting an invalid access.
|
||||
};
|
||||
|
||||
Dictionary::ConstIterator Dictionary::begin() const {
|
||||
return _p->variant_map.begin();
|
||||
}
|
||||
|
||||
Dictionary::ConstIterator Dictionary::end() const {
|
||||
return _p->variant_map.end();
|
||||
}
|
||||
|
||||
LocalVector<Variant> Dictionary::get_key_list() const {
|
||||
LocalVector<Variant> keys;
|
||||
|
||||
keys.reserve(_p->variant_map.size());
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
keys.push_back(E.key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
Variant Dictionary::get_key_at_index(int p_index) const {
|
||||
int index = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
if (index == p_index) {
|
||||
return E.key;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant Dictionary::get_value_at_index(int p_index) const {
|
||||
int index = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
if (index == p_index) {
|
||||
return E.value;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
// WARNING: This operator does not validate the value type. For scripting/extensions this is
|
||||
// done in `variant_setget.cpp`. Consider using `set()` if the data might be invalid.
|
||||
Variant &Dictionary::operator[](const Variant &p_key) {
|
||||
Variant key = p_key;
|
||||
if (unlikely(!_p->typed_key.validate(key, "use `operator[]`"))) {
|
||||
if (unlikely(!_p->typed_fallback)) {
|
||||
_p->typed_fallback = memnew(Variant);
|
||||
}
|
||||
VariantInternal::initialize(_p->typed_fallback, _p->typed_value.type);
|
||||
return *_p->typed_fallback;
|
||||
} else if (unlikely(_p->read_only)) {
|
||||
if (likely(_p->variant_map.has(key))) {
|
||||
*_p->read_only = _p->variant_map[key];
|
||||
} else {
|
||||
VariantInternal::initialize(_p->read_only, _p->typed_value.type);
|
||||
}
|
||||
return *_p->read_only;
|
||||
} else {
|
||||
const uint32_t old_size = _p->variant_map.size();
|
||||
Variant &value = _p->variant_map[key];
|
||||
if (_p->variant_map.size() > old_size) {
|
||||
VariantInternal::initialize(&value, _p->typed_value.type);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
const Variant &Dictionary::operator[](const Variant &p_key) const {
|
||||
Variant key = p_key;
|
||||
if (unlikely(!_p->typed_key.validate(key, "use `operator[]`"))) {
|
||||
if (unlikely(!_p->typed_fallback)) {
|
||||
_p->typed_fallback = memnew(Variant);
|
||||
}
|
||||
VariantInternal::initialize(_p->typed_fallback, _p->typed_value.type);
|
||||
return *_p->typed_fallback;
|
||||
} else {
|
||||
// Will not insert key, so no initialization is necessary.
|
||||
return _p->variant_map[key];
|
||||
}
|
||||
}
|
||||
|
||||
const Variant *Dictionary::getptr(const Variant &p_key) const {
|
||||
Variant key = p_key;
|
||||
if (unlikely(!_p->typed_key.validate(key, "getptr"))) {
|
||||
return nullptr;
|
||||
}
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(key));
|
||||
if (!E) {
|
||||
return nullptr;
|
||||
}
|
||||
return &E->value;
|
||||
}
|
||||
|
||||
// WARNING: This method does not validate the value type.
|
||||
Variant *Dictionary::getptr(const Variant &p_key) {
|
||||
Variant key = p_key;
|
||||
if (unlikely(!_p->typed_key.validate(key, "getptr"))) {
|
||||
return nullptr;
|
||||
}
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E(_p->variant_map.find(key));
|
||||
if (!E) {
|
||||
return nullptr;
|
||||
}
|
||||
if (unlikely(_p->read_only != nullptr)) {
|
||||
*_p->read_only = E->value;
|
||||
return _p->read_only;
|
||||
} else {
|
||||
return &E->value;
|
||||
}
|
||||
}
|
||||
|
||||
Variant Dictionary::get_valid(const Variant &p_key) const {
|
||||
Variant key = p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get_valid"), Variant());
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(key));
|
||||
|
||||
if (!E) {
|
||||
return Variant();
|
||||
}
|
||||
return E->value;
|
||||
}
|
||||
|
||||
Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const {
|
||||
Variant key = p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get"), p_default);
|
||||
const Variant *result = getptr(key);
|
||||
if (!result) {
|
||||
return p_default;
|
||||
}
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
Variant Dictionary::get_or_add(const Variant &p_key, const Variant &p_default) {
|
||||
Variant key = p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get"), p_default);
|
||||
const Variant *result = getptr(key);
|
||||
if (!result) {
|
||||
Variant value = p_default;
|
||||
ERR_FAIL_COND_V(!_p->typed_value.validate(value, "add"), value);
|
||||
operator[](key) = value;
|
||||
return value;
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
bool Dictionary::set(const Variant &p_key, const Variant &p_value) {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
|
||||
Variant key = p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "set"), false);
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed_value.validate(value, "set"), false);
|
||||
_p->variant_map[key] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Dictionary::size() const {
|
||||
return _p->variant_map.size();
|
||||
}
|
||||
|
||||
bool Dictionary::is_empty() const {
|
||||
return !_p->variant_map.size();
|
||||
}
|
||||
|
||||
bool Dictionary::has(const Variant &p_key) const {
|
||||
Variant key = p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "use 'has'"), false);
|
||||
return _p->variant_map.has(key);
|
||||
}
|
||||
|
||||
bool Dictionary::has_all(const Array &p_keys) const {
|
||||
for (int i = 0; i < p_keys.size(); i++) {
|
||||
Variant key = p_keys[i];
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "use 'has_all'"), false);
|
||||
if (!_p->variant_map.has(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Variant Dictionary::find_key(const Variant &p_value) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed_value.validate(value, "find_key"), Variant());
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
if (E.value == value) {
|
||||
return E.key;
|
||||
}
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool Dictionary::erase(const Variant &p_key) {
|
||||
Variant key = p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "erase"), false);
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
|
||||
return _p->variant_map.erase(key);
|
||||
}
|
||||
|
||||
bool Dictionary::operator==(const Dictionary &p_dictionary) const {
|
||||
return recursive_equal(p_dictionary, 0);
|
||||
}
|
||||
|
||||
bool Dictionary::operator!=(const Dictionary &p_dictionary) const {
|
||||
return !recursive_equal(p_dictionary, 0);
|
||||
}
|
||||
|
||||
bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_count) const {
|
||||
// Cheap checks
|
||||
if (_p == p_dictionary._p) {
|
||||
return true;
|
||||
}
|
||||
if (_p->variant_map.size() != p_dictionary._p->variant_map.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Heavy O(n) check
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return true;
|
||||
}
|
||||
recursion_count++;
|
||||
for (const KeyValue<Variant, Variant> &this_E : _p->variant_map) {
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator other_E(p_dictionary._p->variant_map.find(this_E.key));
|
||||
if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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() {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state.");
|
||||
_p->variant_map.clear();
|
||||
}
|
||||
|
||||
struct _DictionaryVariantSort {
|
||||
_FORCE_INLINE_ bool operator()(const KeyValue<Variant, Variant> &p_l, const KeyValue<Variant, Variant> &p_r) const {
|
||||
bool valid = false;
|
||||
Variant res;
|
||||
Variant::evaluate(Variant::OP_LESS, p_l.key, p_r.key, res, valid);
|
||||
if (!valid) {
|
||||
res = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
void Dictionary::sort() {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state.");
|
||||
_p->variant_map.sort_custom<_DictionaryVariantSort>();
|
||||
}
|
||||
|
||||
void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state.");
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
Variant key = E.key;
|
||||
Variant value = E.value;
|
||||
ERR_FAIL_COND(!_p->typed_key.validate(key, "merge"));
|
||||
ERR_FAIL_COND(!_p->typed_value.validate(value, "merge"));
|
||||
if (p_overwrite || !has(key)) {
|
||||
operator[](key) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary Dictionary::merged(const Dictionary &p_dictionary, bool p_overwrite) const {
|
||||
Dictionary ret = duplicate();
|
||||
ret.merge(p_dictionary, p_overwrite);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Dictionary::_unref() const {
|
||||
ERR_FAIL_NULL(_p);
|
||||
if (_p->refcount.unref()) {
|
||||
if (_p->read_only) {
|
||||
memdelete(_p->read_only);
|
||||
}
|
||||
if (_p->typed_fallback) {
|
||||
memdelete(_p->typed_fallback);
|
||||
}
|
||||
memdelete(_p);
|
||||
}
|
||||
_p = nullptr;
|
||||
}
|
||||
|
||||
uint32_t Dictionary::hash() const {
|
||||
return recursive_hash(0);
|
||||
}
|
||||
|
||||
uint32_t Dictionary::recursive_hash(int recursion_count) const {
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t h = hash_murmur3_one_32(Variant::DICTIONARY);
|
||||
|
||||
recursion_count++;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
h = hash_murmur3_one_32(E.key.recursive_hash(recursion_count), h);
|
||||
h = hash_murmur3_one_32(E.value.recursive_hash(recursion_count), h);
|
||||
}
|
||||
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
|
||||
Array Dictionary::keys() const {
|
||||
Array varr;
|
||||
if (is_typed_key()) {
|
||||
varr.set_typed(get_typed_key_builtin(), get_typed_key_class_name(), get_typed_key_script());
|
||||
}
|
||||
if (_p->variant_map.is_empty()) {
|
||||
return varr;
|
||||
}
|
||||
|
||||
varr.resize(size());
|
||||
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
varr[i] = E.key;
|
||||
i++;
|
||||
}
|
||||
|
||||
return varr;
|
||||
}
|
||||
|
||||
Array Dictionary::values() const {
|
||||
Array varr;
|
||||
if (is_typed_value()) {
|
||||
varr.set_typed(get_typed_value_builtin(), get_typed_value_class_name(), get_typed_value_script());
|
||||
}
|
||||
if (_p->variant_map.is_empty()) {
|
||||
return varr;
|
||||
}
|
||||
|
||||
varr.resize(size());
|
||||
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
varr[i] = E.value;
|
||||
i++;
|
||||
}
|
||||
|
||||
return varr;
|
||||
}
|
||||
|
||||
void Dictionary::assign(const Dictionary &p_dictionary) {
|
||||
const ContainerTypeValidate &typed_key = _p->typed_key;
|
||||
const ContainerTypeValidate &typed_key_source = p_dictionary._p->typed_key;
|
||||
|
||||
const ContainerTypeValidate &typed_value = _p->typed_value;
|
||||
const ContainerTypeValidate &typed_value_source = p_dictionary._p->typed_value;
|
||||
|
||||
if ((typed_key == typed_key_source || typed_key.type == Variant::NIL || (typed_key_source.type == Variant::OBJECT && typed_key.can_reference(typed_key_source))) &&
|
||||
(typed_value == typed_value_source || typed_value.type == Variant::NIL || (typed_value_source.type == Variant::OBJECT && typed_value.can_reference(typed_value_source)))) {
|
||||
// From same to same or,
|
||||
// from anything to variants or,
|
||||
// from subclasses to base classes.
|
||||
_p->variant_map = p_dictionary._p->variant_map;
|
||||
return;
|
||||
}
|
||||
|
||||
int size = p_dictionary._p->variant_map.size();
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator> variant_map = HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>(size);
|
||||
|
||||
Vector<Variant> key_array;
|
||||
key_array.resize(size);
|
||||
Variant *key_data = key_array.ptrw();
|
||||
|
||||
Vector<Variant> value_array;
|
||||
value_array.resize(size);
|
||||
Variant *value_data = value_array.ptrw();
|
||||
|
||||
if (typed_key == typed_key_source || typed_key.type == Variant::NIL || (typed_key_source.type == Variant::OBJECT && typed_key.can_reference(typed_key_source))) {
|
||||
// From same to same or,
|
||||
// from anything to variants or,
|
||||
// from subclasses to base classes.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *key = &E.key;
|
||||
key_data[i++] = *key;
|
||||
}
|
||||
} else if ((typed_key_source.type == Variant::NIL && typed_key.type == Variant::OBJECT) || (typed_key_source.type == Variant::OBJECT && typed_key_source.can_reference(typed_key))) {
|
||||
// From variants to objects or,
|
||||
// from base classes to subclasses.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *key = &E.key;
|
||||
if (key->get_type() != Variant::NIL && (key->get_type() != Variant::OBJECT || !typed_key.validate_object(*key, "assign"))) {
|
||||
ERR_FAIL_MSG(vformat(R"(Unable to convert key from "%s" to "%s".)", Variant::get_type_name(key->get_type()), Variant::get_type_name(typed_key.type)));
|
||||
}
|
||||
key_data[i++] = *key;
|
||||
}
|
||||
} else if (typed_key.type == Variant::OBJECT || typed_key_source.type == Variant::OBJECT) {
|
||||
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Dictionary[%s, %s]" to "Dictionary[%s, %s]".)", Variant::get_type_name(typed_key_source.type), Variant::get_type_name(typed_value_source.type),
|
||||
Variant::get_type_name(typed_key.type), Variant::get_type_name(typed_value.type)));
|
||||
} else if (typed_key_source.type == Variant::NIL && typed_key.type != Variant::OBJECT) {
|
||||
// From variants to primitives.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *key = &E.key;
|
||||
if (key->get_type() == typed_key.type) {
|
||||
key_data[i++] = *key;
|
||||
continue;
|
||||
}
|
||||
if (!Variant::can_convert_strict(key->get_type(), typed_key.type)) {
|
||||
ERR_FAIL_MSG(vformat(R"(Unable to convert key from "%s" to "%s".)", Variant::get_type_name(key->get_type()), Variant::get_type_name(typed_key.type)));
|
||||
}
|
||||
Callable::CallError ce;
|
||||
Variant::construct(typed_key.type, key_data[i++], &key, 1, ce);
|
||||
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert key from "%s" to "%s".)", Variant::get_type_name(key->get_type()), Variant::get_type_name(typed_key.type)));
|
||||
}
|
||||
} else if (Variant::can_convert_strict(typed_key_source.type, typed_key.type)) {
|
||||
// From primitives to different convertible primitives.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *key = &E.key;
|
||||
Callable::CallError ce;
|
||||
Variant::construct(typed_key.type, key_data[i++], &key, 1, ce);
|
||||
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert key from "%s" to "%s".)", Variant::get_type_name(key->get_type()), Variant::get_type_name(typed_key.type)));
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Dictionary[%s, %s]" to "Dictionary[%s, %s].)", Variant::get_type_name(typed_key_source.type), Variant::get_type_name(typed_value_source.type),
|
||||
Variant::get_type_name(typed_key.type), Variant::get_type_name(typed_value.type)));
|
||||
}
|
||||
|
||||
if (typed_value == typed_value_source || typed_value.type == Variant::NIL || (typed_value_source.type == Variant::OBJECT && typed_value.can_reference(typed_value_source))) {
|
||||
// From same to same or,
|
||||
// from anything to variants or,
|
||||
// from subclasses to base classes.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *value = &E.value;
|
||||
value_data[i++] = *value;
|
||||
}
|
||||
} else if (((typed_value_source.type == Variant::NIL && typed_value.type == Variant::OBJECT) || (typed_value_source.type == Variant::OBJECT && typed_value_source.can_reference(typed_value)))) {
|
||||
// From variants to objects or,
|
||||
// from base classes to subclasses.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *value = &E.value;
|
||||
if (value->get_type() != Variant::NIL && (value->get_type() != Variant::OBJECT || !typed_value.validate_object(*value, "assign"))) {
|
||||
ERR_FAIL_MSG(vformat(R"(Unable to convert value at key "%s" from "%s" to "%s".)", key_data[i], Variant::get_type_name(value->get_type()), Variant::get_type_name(typed_value.type)));
|
||||
}
|
||||
value_data[i++] = *value;
|
||||
}
|
||||
} else if (typed_value.type == Variant::OBJECT || typed_value_source.type == Variant::OBJECT) {
|
||||
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Dictionary[%s, %s]" to "Dictionary[%s, %s]".)", Variant::get_type_name(typed_key_source.type), Variant::get_type_name(typed_value_source.type),
|
||||
Variant::get_type_name(typed_key.type), Variant::get_type_name(typed_value.type)));
|
||||
} else if (typed_value_source.type == Variant::NIL && typed_value.type != Variant::OBJECT) {
|
||||
// From variants to primitives.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *value = &E.value;
|
||||
if (value->get_type() == typed_value.type) {
|
||||
value_data[i++] = *value;
|
||||
continue;
|
||||
}
|
||||
if (!Variant::can_convert_strict(value->get_type(), typed_value.type)) {
|
||||
ERR_FAIL_MSG(vformat(R"(Unable to convert value at key "%s" from "%s" to "%s".)", key_data[i], Variant::get_type_name(value->get_type()), Variant::get_type_name(typed_value.type)));
|
||||
}
|
||||
Callable::CallError ce;
|
||||
Variant::construct(typed_value.type, value_data[i++], &value, 1, ce);
|
||||
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert value at key "%s" from "%s" to "%s".)", key_data[i - 1], Variant::get_type_name(value->get_type()), Variant::get_type_name(typed_value.type)));
|
||||
}
|
||||
} else if (Variant::can_convert_strict(typed_value_source.type, typed_value.type)) {
|
||||
// From primitives to different convertible primitives.
|
||||
int i = 0;
|
||||
for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) {
|
||||
const Variant *value = &E.value;
|
||||
Callable::CallError ce;
|
||||
Variant::construct(typed_value.type, value_data[i++], &value, 1, ce);
|
||||
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert value at key "%s" from "%s" to "%s".)", key_data[i - 1], Variant::get_type_name(value->get_type()), Variant::get_type_name(typed_value.type)));
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Dictionary[%s, %s]" to "Dictionary[%s, %s].)", Variant::get_type_name(typed_key_source.type), Variant::get_type_name(typed_value_source.type),
|
||||
Variant::get_type_name(typed_key.type), Variant::get_type_name(typed_value.type)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
variant_map.insert(key_data[i], value_data[i]);
|
||||
}
|
||||
|
||||
_p->variant_map = variant_map;
|
||||
}
|
||||
|
||||
const Variant *Dictionary::next(const Variant *p_key) const {
|
||||
if (p_key == nullptr) {
|
||||
// caller wants to get the first element
|
||||
if (_p->variant_map.begin()) {
|
||||
return &_p->variant_map.begin()->key;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
Variant key = *p_key;
|
||||
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "next"), nullptr);
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E = _p->variant_map.find(key);
|
||||
|
||||
if (!E) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
++E;
|
||||
|
||||
if (E) {
|
||||
return &E->key;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Dictionary Dictionary::duplicate(bool p_deep) const {
|
||||
return recursive_duplicate(p_deep, RESOURCE_DEEP_DUPLICATE_NONE, 0);
|
||||
}
|
||||
|
||||
Dictionary Dictionary::duplicate_deep(ResourceDeepDuplicateMode p_deep_subresources_mode) const {
|
||||
return recursive_duplicate(true, p_deep_subresources_mode, 0);
|
||||
}
|
||||
|
||||
void Dictionary::make_read_only() {
|
||||
if (_p->read_only == nullptr) {
|
||||
_p->read_only = memnew(Variant);
|
||||
}
|
||||
}
|
||||
bool Dictionary::is_read_only() const {
|
||||
return _p->read_only != nullptr;
|
||||
}
|
||||
|
||||
Dictionary Dictionary::recursive_duplicate(bool p_deep, ResourceDeepDuplicateMode p_deep_subresources_mode, int recursion_count) const {
|
||||
Dictionary n;
|
||||
n._p->typed_key = _p->typed_key;
|
||||
n._p->typed_value = _p->typed_value;
|
||||
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return n;
|
||||
}
|
||||
|
||||
if (p_deep) {
|
||||
bool is_call_chain_end = recursion_count == 0;
|
||||
|
||||
recursion_count++;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
n[E.key.recursive_duplicate(true, p_deep_subresources_mode, recursion_count)] = E.value.recursive_duplicate(true, p_deep_subresources_mode, recursion_count);
|
||||
}
|
||||
|
||||
// Variant::recursive_duplicate() may have created a remap cache by now.
|
||||
if (is_call_chain_end) {
|
||||
Resource::_teardown_duplicate_from_variant();
|
||||
}
|
||||
} else {
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
n[E.key] = E.value;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void Dictionary::set_typed(const ContainerType &p_key_type, const ContainerType &p_value_type) {
|
||||
set_typed(p_key_type.builtin_type, p_key_type.class_name, p_key_type.script, p_value_type.builtin_type, p_value_type.class_name, p_key_type.script);
|
||||
}
|
||||
|
||||
void Dictionary::set_typed(uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state.");
|
||||
ERR_FAIL_COND_MSG(_p->variant_map.size() > 0, "Type can only be set when dictionary is empty.");
|
||||
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when dictionary has no more than one user.");
|
||||
ERR_FAIL_COND_MSG(_p->typed_key.type != Variant::NIL || _p->typed_value.type != Variant::NIL, "Type can only be set once.");
|
||||
ERR_FAIL_COND_MSG((p_key_class_name != StringName() && p_key_type != Variant::OBJECT) || (p_value_class_name != StringName() && p_value_type != Variant::OBJECT), "Class names can only be set for type OBJECT.");
|
||||
Ref<Script> key_script = p_key_script;
|
||||
ERR_FAIL_COND_MSG(key_script.is_valid() && p_key_class_name == StringName(), "Script class can only be set together with base class name.");
|
||||
Ref<Script> value_script = p_value_script;
|
||||
ERR_FAIL_COND_MSG(value_script.is_valid() && p_value_class_name == StringName(), "Script class can only be set together with base class name.");
|
||||
|
||||
_p->typed_key.type = Variant::Type(p_key_type);
|
||||
_p->typed_key.class_name = p_key_class_name;
|
||||
_p->typed_key.script = key_script;
|
||||
_p->typed_key.where = "TypedDictionary.Key";
|
||||
|
||||
_p->typed_value.type = Variant::Type(p_value_type);
|
||||
_p->typed_value.class_name = p_value_class_name;
|
||||
_p->typed_value.script = value_script;
|
||||
_p->typed_value.where = "TypedDictionary.Value";
|
||||
}
|
||||
|
||||
bool Dictionary::is_typed() const {
|
||||
return is_typed_key() || is_typed_value();
|
||||
}
|
||||
|
||||
bool Dictionary::is_typed_key() const {
|
||||
return _p->typed_key.type != Variant::NIL;
|
||||
}
|
||||
|
||||
bool Dictionary::is_typed_value() const {
|
||||
return _p->typed_value.type != Variant::NIL;
|
||||
}
|
||||
|
||||
bool Dictionary::is_same_instance(const Dictionary &p_other) const {
|
||||
return _p == p_other._p;
|
||||
}
|
||||
|
||||
bool Dictionary::is_same_typed(const Dictionary &p_other) const {
|
||||
return is_same_typed_key(p_other) && is_same_typed_value(p_other);
|
||||
}
|
||||
|
||||
bool Dictionary::is_same_typed_key(const Dictionary &p_other) const {
|
||||
return _p->typed_key == p_other._p->typed_key;
|
||||
}
|
||||
|
||||
bool Dictionary::is_same_typed_value(const Dictionary &p_other) const {
|
||||
return _p->typed_value == p_other._p->typed_value;
|
||||
}
|
||||
|
||||
ContainerType Dictionary::get_key_type() const {
|
||||
ContainerType type;
|
||||
type.builtin_type = _p->typed_key.type;
|
||||
type.class_name = _p->typed_key.class_name;
|
||||
type.script = _p->typed_key.script;
|
||||
return type;
|
||||
}
|
||||
|
||||
ContainerType Dictionary::get_value_type() const {
|
||||
ContainerType type;
|
||||
type.builtin_type = _p->typed_value.type;
|
||||
type.class_name = _p->typed_value.class_name;
|
||||
type.script = _p->typed_value.script;
|
||||
return type;
|
||||
}
|
||||
|
||||
uint32_t Dictionary::get_typed_key_builtin() const {
|
||||
return _p->typed_key.type;
|
||||
}
|
||||
|
||||
uint32_t Dictionary::get_typed_value_builtin() const {
|
||||
return _p->typed_value.type;
|
||||
}
|
||||
|
||||
StringName Dictionary::get_typed_key_class_name() const {
|
||||
return _p->typed_key.class_name;
|
||||
}
|
||||
|
||||
StringName Dictionary::get_typed_value_class_name() const {
|
||||
return _p->typed_value.class_name;
|
||||
}
|
||||
|
||||
Variant Dictionary::get_typed_key_script() const {
|
||||
return _p->typed_key.script;
|
||||
}
|
||||
|
||||
Variant Dictionary::get_typed_value_script() const {
|
||||
return _p->typed_value.script;
|
||||
}
|
||||
|
||||
const ContainerTypeValidate &Dictionary::get_key_validator() const {
|
||||
return _p->typed_key;
|
||||
}
|
||||
|
||||
const ContainerTypeValidate &Dictionary::get_value_validator() const {
|
||||
return _p->typed_value;
|
||||
}
|
||||
|
||||
void Dictionary::operator=(const Dictionary &p_dictionary) {
|
||||
if (this == &p_dictionary) {
|
||||
return;
|
||||
}
|
||||
_ref(p_dictionary);
|
||||
}
|
||||
|
||||
const void *Dictionary::id() const {
|
||||
return _p;
|
||||
}
|
||||
|
||||
Dictionary::Dictionary(const Dictionary &p_base, uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script) {
|
||||
_p = memnew(DictionaryPrivate);
|
||||
_p->refcount.init();
|
||||
set_typed(p_key_type, p_key_class_name, p_key_script, p_value_type, p_value_class_name, p_value_script);
|
||||
assign(p_base);
|
||||
}
|
||||
|
||||
Dictionary::Dictionary(const Dictionary &p_from) {
|
||||
_p = nullptr;
|
||||
_ref(p_from);
|
||||
}
|
||||
|
||||
Dictionary::Dictionary() {
|
||||
_p = memnew(DictionaryPrivate);
|
||||
_p->refcount.init();
|
||||
}
|
||||
|
||||
Dictionary::Dictionary(std::initializer_list<KeyValue<Variant, Variant>> p_init) {
|
||||
_p = memnew(DictionaryPrivate);
|
||||
_p->refcount.init();
|
||||
|
||||
for (const KeyValue<Variant, Variant> &E : p_init) {
|
||||
operator[](E.key) = E.value;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary::~Dictionary() {
|
||||
_unref();
|
||||
}
|
||||
138
core/variant/dictionary.h
Normal file
138
core/variant/dictionary.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/**************************************************************************/
|
||||
/* dictionary.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/pair.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "core/variant/variant_deep_duplicate.h"
|
||||
|
||||
class Variant;
|
||||
|
||||
struct ContainerType;
|
||||
struct ContainerTypeValidate;
|
||||
struct DictionaryPrivate;
|
||||
struct StringLikeVariantComparator;
|
||||
struct VariantHasher;
|
||||
|
||||
class Dictionary {
|
||||
mutable DictionaryPrivate *_p;
|
||||
|
||||
void _ref(const Dictionary &p_from) const;
|
||||
void _unref() const;
|
||||
|
||||
public:
|
||||
using ConstIterator = HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator;
|
||||
|
||||
ConstIterator begin() const;
|
||||
ConstIterator end() const;
|
||||
|
||||
LocalVector<Variant> get_key_list() 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;
|
||||
Variant get_or_add(const Variant &p_key, const Variant &p_default);
|
||||
bool set(const Variant &p_key, const Variant &p_value);
|
||||
|
||||
int size() const;
|
||||
bool is_empty() const;
|
||||
void clear();
|
||||
void sort();
|
||||
void merge(const Dictionary &p_dictionary, bool p_overwrite = false);
|
||||
Dictionary merged(const Dictionary &p_dictionary, bool p_overwrite = false) const;
|
||||
|
||||
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 operator==(const Dictionary &p_dictionary) const;
|
||||
bool operator!=(const Dictionary &p_dictionary) const;
|
||||
bool recursive_equal(const Dictionary &p_dictionary, int recursion_count) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
uint32_t recursive_hash(int recursion_count) const;
|
||||
void operator=(const Dictionary &p_dictionary);
|
||||
|
||||
void assign(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;
|
||||
Dictionary duplicate_deep(ResourceDeepDuplicateMode p_deep_subresources_mode = RESOURCE_DEEP_DUPLICATE_INTERNAL) const;
|
||||
Dictionary recursive_duplicate(bool p_deep, ResourceDeepDuplicateMode p_deep_subresources_mode, int recursion_count) const;
|
||||
|
||||
void set_typed(const ContainerType &p_key_type, const ContainerType &p_value_type);
|
||||
void set_typed(uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script);
|
||||
|
||||
bool is_typed() const;
|
||||
bool is_typed_key() const;
|
||||
bool is_typed_value() const;
|
||||
bool is_same_instance(const Dictionary &p_other) const;
|
||||
bool is_same_typed(const Dictionary &p_other) const;
|
||||
bool is_same_typed_key(const Dictionary &p_other) const;
|
||||
bool is_same_typed_value(const Dictionary &p_other) const;
|
||||
|
||||
ContainerType get_key_type() const;
|
||||
ContainerType get_value_type() const;
|
||||
uint32_t get_typed_key_builtin() const;
|
||||
uint32_t get_typed_value_builtin() const;
|
||||
StringName get_typed_key_class_name() const;
|
||||
StringName get_typed_value_class_name() const;
|
||||
Variant get_typed_key_script() const;
|
||||
Variant get_typed_value_script() const;
|
||||
const ContainerTypeValidate &get_key_validator() const;
|
||||
const ContainerTypeValidate &get_value_validator() const;
|
||||
|
||||
void make_read_only();
|
||||
bool is_read_only() const;
|
||||
|
||||
const void *id() const;
|
||||
|
||||
Dictionary(const Dictionary &p_base, uint32_t p_key_type, const StringName &p_key_class_name, const Variant &p_key_script, uint32_t p_value_type, const StringName &p_value_class_name, const Variant &p_value_script);
|
||||
Dictionary(const Dictionary &p_from);
|
||||
Dictionary(std::initializer_list<KeyValue<Variant, Variant>> p_init);
|
||||
Dictionary();
|
||||
~Dictionary();
|
||||
};
|
||||
337
core/variant/method_ptrcall.h
Normal file
337
core/variant/method_ptrcall.h
Normal file
@@ -0,0 +1,337 @@
|
||||
/**************************************************************************/
|
||||
/* method_ptrcall.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/templates/simple_type.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
namespace Internal {
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArgDirect {
|
||||
_FORCE_INLINE_ static const T &convert(const void *p_ptr) {
|
||||
return *reinterpret_cast<const T *>(p_ptr);
|
||||
}
|
||||
typedef T EncodeT;
|
||||
_FORCE_INLINE_ static void encode(T p_val, void *p_ptr) {
|
||||
*((T *)p_ptr) = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename S>
|
||||
struct PtrToArgConvert {
|
||||
_FORCE_INLINE_ static T convert(const void *p_ptr) {
|
||||
return static_cast<T>(*reinterpret_cast<const S *>(p_ptr));
|
||||
}
|
||||
typedef S EncodeT;
|
||||
_FORCE_INLINE_ static void encode(T p_val, void *p_ptr) {
|
||||
*((S *)p_ptr) = static_cast<S>(p_val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArgByReference {
|
||||
_FORCE_INLINE_ static const T &convert(const void *p_ptr) {
|
||||
return *reinterpret_cast<const T *>(p_ptr);
|
||||
}
|
||||
typedef T EncodeT;
|
||||
_FORCE_INLINE_ static void encode(const T &p_val, void *p_ptr) {
|
||||
*((T *)p_ptr) = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename TAlt>
|
||||
struct PtrToArgVectorConvert {
|
||||
_FORCE_INLINE_ static Vector<TAlt> convert(const void *p_ptr) {
|
||||
const Vector<T> *dvs = reinterpret_cast<const Vector<T> *>(p_ptr);
|
||||
Vector<TAlt> ret;
|
||||
int len = dvs->size();
|
||||
ret.resize(len);
|
||||
{
|
||||
const T *r = dvs->ptr();
|
||||
for (int i = 0; i < len; i++) {
|
||||
ret.write[i] = r[i];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
_FORCE_INLINE_ static void encode(const Vector<TAlt> &p_vec, void *p_ptr) {
|
||||
Vector<T> *dv = reinterpret_cast<Vector<T> *>(p_ptr);
|
||||
int len = p_vec.size();
|
||||
dv->resize(len);
|
||||
{
|
||||
T *w = dv->ptrw();
|
||||
for (int i = 0; i < len; i++) {
|
||||
w[i] = p_vec[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArgVectorFromArray {
|
||||
_FORCE_INLINE_ static Vector<T> convert(const void *p_ptr) {
|
||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr);
|
||||
Vector<T> ret;
|
||||
int len = arr->size();
|
||||
ret.resize(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
ret.write[i] = (*arr)[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
_FORCE_INLINE_ static void encode(const Vector<T> &p_vec, void *p_ptr) {
|
||||
Array *arr = reinterpret_cast<Array *>(p_ptr);
|
||||
int len = p_vec.size();
|
||||
arr->resize(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
(*arr)[i] = p_vec[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArgStringConvertByReference {
|
||||
_FORCE_INLINE_ static T convert(const void *p_ptr) {
|
||||
T s = *reinterpret_cast<const String *>(p_ptr);
|
||||
return s;
|
||||
}
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
_FORCE_INLINE_ static void encode(const T &p_vec, void *p_ptr) {
|
||||
String *arr = reinterpret_cast<String *>(p_ptr);
|
||||
*arr = String(p_vec);
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace Internal
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct PtrToArg;
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<T, std::enable_if_t<!std::is_same_v<T, GetSimpleTypeT<T>>>> : PtrToArg<GetSimpleTypeT<T>> {};
|
||||
|
||||
template <>
|
||||
struct PtrToArg<bool> : Internal::PtrToArgConvert<bool, uint8_t> {};
|
||||
// Integer types.
|
||||
template <>
|
||||
struct PtrToArg<uint8_t> : Internal::PtrToArgConvert<uint8_t, int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<int8_t> : Internal::PtrToArgConvert<int8_t, int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<uint16_t> : Internal::PtrToArgConvert<uint16_t, int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<int16_t> : Internal::PtrToArgConvert<int16_t, int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<uint32_t> : Internal::PtrToArgConvert<uint32_t, int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<int32_t> : Internal::PtrToArgConvert<int32_t, int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<int64_t> : Internal::PtrToArgDirect<int64_t> {};
|
||||
template <>
|
||||
struct PtrToArg<uint64_t> : Internal::PtrToArgDirect<uint64_t> {};
|
||||
// Float types
|
||||
template <>
|
||||
struct PtrToArg<float> : Internal::PtrToArgConvert<float, double> {};
|
||||
template <>
|
||||
struct PtrToArg<double> : Internal::PtrToArgDirect<double> {};
|
||||
|
||||
template <>
|
||||
struct PtrToArg<String> : Internal::PtrToArgDirect<String> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector2> : Internal::PtrToArgDirect<Vector2> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector2i> : Internal::PtrToArgDirect<Vector2i> {};
|
||||
template <>
|
||||
struct PtrToArg<Rect2> : Internal::PtrToArgDirect<Rect2> {};
|
||||
template <>
|
||||
struct PtrToArg<Rect2i> : Internal::PtrToArgDirect<Rect2i> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector3> : Internal::PtrToArgByReference<Vector3> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector3i> : Internal::PtrToArgByReference<Vector3i> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector4> : Internal::PtrToArgByReference<Vector4> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector4i> : Internal::PtrToArgByReference<Vector4i> {};
|
||||
template <>
|
||||
struct PtrToArg<Transform2D> : Internal::PtrToArgDirect<Transform2D> {};
|
||||
template <>
|
||||
struct PtrToArg<Projection> : Internal::PtrToArgDirect<Projection> {};
|
||||
template <>
|
||||
struct PtrToArg<Plane> : Internal::PtrToArgByReference<Plane> {};
|
||||
template <>
|
||||
struct PtrToArg<Quaternion> : Internal::PtrToArgDirect<Quaternion> {};
|
||||
template <>
|
||||
struct PtrToArg<AABB> : Internal::PtrToArgByReference<AABB> {};
|
||||
template <>
|
||||
struct PtrToArg<Basis> : Internal::PtrToArgByReference<Basis> {};
|
||||
template <>
|
||||
struct PtrToArg<Transform3D> : Internal::PtrToArgByReference<Transform3D> {};
|
||||
template <>
|
||||
struct PtrToArg<Color> : Internal::PtrToArgByReference<Color> {};
|
||||
template <>
|
||||
struct PtrToArg<StringName> : Internal::PtrToArgDirect<StringName> {};
|
||||
template <>
|
||||
struct PtrToArg<NodePath> : Internal::PtrToArgDirect<NodePath> {};
|
||||
template <>
|
||||
struct PtrToArg<RID> : Internal::PtrToArgDirect<RID> {};
|
||||
// Object doesn't need this.
|
||||
template <>
|
||||
struct PtrToArg<Callable> : Internal::PtrToArgDirect<Callable> {};
|
||||
template <>
|
||||
struct PtrToArg<Signal> : Internal::PtrToArgDirect<Signal> {};
|
||||
template <>
|
||||
struct PtrToArg<Dictionary> : Internal::PtrToArgDirect<Dictionary> {};
|
||||
template <>
|
||||
struct PtrToArg<Array> : Internal::PtrToArgDirect<Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedByteArray> : Internal::PtrToArgDirect<PackedByteArray> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedInt32Array> : Internal::PtrToArgDirect<PackedInt32Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedInt64Array> : Internal::PtrToArgDirect<PackedInt64Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedFloat32Array> : Internal::PtrToArgDirect<PackedFloat32Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedFloat64Array> : Internal::PtrToArgDirect<PackedFloat64Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedStringArray> : Internal::PtrToArgDirect<PackedStringArray> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedVector2Array> : Internal::PtrToArgDirect<PackedVector2Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedVector3Array> : Internal::PtrToArgDirect<PackedVector3Array> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedColorArray> : Internal::PtrToArgDirect<PackedColorArray> {};
|
||||
template <>
|
||||
struct PtrToArg<PackedVector4Array> : Internal::PtrToArgDirect<PackedVector4Array> {};
|
||||
template <>
|
||||
struct PtrToArg<Variant> : Internal::PtrToArgByReference<Variant> {};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<T, std::enable_if_t<std::is_enum_v<T>>> : Internal::PtrToArgConvert<T, int64_t> {};
|
||||
template <typename T>
|
||||
struct PtrToArg<BitField<T>, std::enable_if_t<std::is_enum_v<T>>> : Internal::PtrToArgConvert<BitField<T>, int64_t> {};
|
||||
|
||||
// This is for Object.
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<T *> {
|
||||
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
|
||||
return likely(p_ptr) ? *reinterpret_cast<T *const *>(p_ptr) : nullptr;
|
||||
}
|
||||
typedef Object *EncodeT;
|
||||
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
|
||||
*((T **)p_ptr) = p_var;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<const T *> {
|
||||
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
|
||||
return likely(p_ptr) ? *reinterpret_cast<T *const *>(p_ptr) : nullptr;
|
||||
}
|
||||
typedef const Object *EncodeT;
|
||||
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
|
||||
*((T **)p_ptr) = p_var;
|
||||
}
|
||||
};
|
||||
|
||||
// This is for ObjectID.
|
||||
|
||||
template <>
|
||||
struct PtrToArg<ObjectID> {
|
||||
_FORCE_INLINE_ static const ObjectID convert(const void *p_ptr) {
|
||||
return ObjectID(*reinterpret_cast<const uint64_t *>(p_ptr));
|
||||
}
|
||||
typedef uint64_t EncodeT;
|
||||
_FORCE_INLINE_ static void encode(const ObjectID &p_val, void *p_ptr) {
|
||||
*((uint64_t *)p_ptr) = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
// This is for the special cases used by Variant.
|
||||
|
||||
template <>
|
||||
struct PtrToArg<Vector<StringName>> : Internal::PtrToArgVectorConvert<String, StringName> {};
|
||||
|
||||
// For stuff that gets converted to Array vectors.
|
||||
|
||||
template <>
|
||||
struct PtrToArg<Vector<Variant>> : Internal::PtrToArgVectorFromArray<Variant> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector<RID>> : Internal::PtrToArgVectorFromArray<RID> {};
|
||||
template <>
|
||||
struct PtrToArg<Vector<Plane>> : Internal::PtrToArgVectorFromArray<Plane> {};
|
||||
|
||||
// Special case for IPAddress.
|
||||
|
||||
template <>
|
||||
struct PtrToArg<IPAddress> : Internal::PtrToArgStringConvertByReference<IPAddress> {};
|
||||
|
||||
template <>
|
||||
struct PtrToArg<Vector<Face3>> {
|
||||
_FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
|
||||
const Vector<Vector3> *dvs = reinterpret_cast<const Vector<Vector3> *>(p_ptr);
|
||||
Vector<Face3> ret;
|
||||
int len = dvs->size() / 3;
|
||||
ret.resize(len);
|
||||
{
|
||||
const Vector3 *r = dvs->ptr();
|
||||
Face3 *w = ret.ptrw();
|
||||
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;
|
||||
}
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
_FORCE_INLINE_ static void encode(const Vector<Face3> &p_vec, void *p_ptr) {
|
||||
Vector<Vector3> *arr = reinterpret_cast<Vector<Vector3> *>(p_ptr);
|
||||
int len = p_vec.size();
|
||||
arr->resize(len * 3);
|
||||
{
|
||||
const Face3 *r = p_vec.ptr();
|
||||
Vector3 *w = arr->ptrw();
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
177
core/variant/native_ptr.h
Normal file
177
core/variant/native_ptr.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/**************************************************************************/
|
||||
/* native_ptr.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/math/audio_frame.h"
|
||||
#include "core/variant/method_ptrcall.h"
|
||||
#include "core/variant/type_info.h"
|
||||
|
||||
template <typename T>
|
||||
struct GDExtensionConstPtr {
|
||||
const T *data = nullptr;
|
||||
GDExtensionConstPtr(const T *p_assign) { data = p_assign; }
|
||||
static const char *get_name() { return "const void"; }
|
||||
operator const T *() const { return data; }
|
||||
operator Variant() const { return uint64_t(data); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GDExtensionPtr {
|
||||
T *data = nullptr;
|
||||
GDExtensionPtr(T *p_assign) { data = p_assign; }
|
||||
static const char *get_name() { return "void"; }
|
||||
operator T *() const { return data; }
|
||||
operator Variant() const { return uint64_t(data); }
|
||||
};
|
||||
|
||||
#define GDVIRTUAL_NATIVE_PTR(m_type) \
|
||||
template <> \
|
||||
struct GDExtensionConstPtr<const m_type> { \
|
||||
const m_type *data = nullptr; \
|
||||
GDExtensionConstPtr() {} \
|
||||
GDExtensionConstPtr(const m_type *p_assign) { \
|
||||
data = p_assign; \
|
||||
} \
|
||||
static const char *get_name() { \
|
||||
return "const " #m_type; \
|
||||
} \
|
||||
operator const m_type *() const { \
|
||||
return data; \
|
||||
} \
|
||||
operator Variant() const { \
|
||||
return uint64_t(data); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct VariantCaster<GDExtensionConstPtr<const m_type>> { \
|
||||
static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \
|
||||
return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct VariantInternalAccessor<GDExtensionConstPtr<const m_type>> { \
|
||||
static _FORCE_INLINE_ const GDExtensionConstPtr<const m_type> &get(const Variant *v) { \
|
||||
return *reinterpret_cast<const GDExtensionConstPtr<const m_type> *>(VariantInternal::get_int(v)); \
|
||||
} \
|
||||
static _FORCE_INLINE_ void set(Variant *v, const GDExtensionConstPtr<const m_type> &p_value) { \
|
||||
*VariantInternal::get_int(v) = uint64_t(p_value.data); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GDExtensionPtr<m_type> { \
|
||||
m_type *data = nullptr; \
|
||||
GDExtensionPtr() {} \
|
||||
GDExtensionPtr(m_type *p_assign) { \
|
||||
data = p_assign; \
|
||||
} \
|
||||
static const char *get_name() { \
|
||||
return #m_type; \
|
||||
} \
|
||||
operator m_type *() const { \
|
||||
return data; \
|
||||
} \
|
||||
operator Variant() const { \
|
||||
return uint64_t(data); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct VariantCaster<GDExtensionPtr<m_type>> { \
|
||||
static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \
|
||||
return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct VariantInternalAccessor<GDExtensionPtr<m_type>> { \
|
||||
static _FORCE_INLINE_ const GDExtensionPtr<m_type> &get(const Variant *v) { \
|
||||
return *reinterpret_cast<const GDExtensionPtr<m_type> *>(VariantInternal::get_int(v)); \
|
||||
} \
|
||||
static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr<m_type> &p_value) { \
|
||||
*VariantInternal::get_int(v) = uint64_t(p_value.data); \
|
||||
} \
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<GDExtensionConstPtr<T>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDExtensionConstPtr<T>::get_name());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<GDExtensionPtr<T>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDExtensionPtr<T>::get_name());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<GDExtensionConstPtr<T>> {
|
||||
_FORCE_INLINE_ static GDExtensionConstPtr<T> convert(const void *p_ptr) {
|
||||
return GDExtensionConstPtr<T>(reinterpret_cast<const T *>(p_ptr));
|
||||
}
|
||||
typedef const T *EncodeT;
|
||||
_FORCE_INLINE_ static void encode(GDExtensionConstPtr<T> p_val, void *p_ptr) {
|
||||
*((const T **)p_ptr) = p_val.data;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct PtrToArg<GDExtensionPtr<T>> {
|
||||
_FORCE_INLINE_ static GDExtensionPtr<T> convert(const void *p_ptr) {
|
||||
return GDExtensionPtr<T>(reinterpret_cast<const T *>(p_ptr));
|
||||
}
|
||||
typedef T *EncodeT;
|
||||
_FORCE_INLINE_ static void encode(GDExtensionPtr<T> p_val, void *p_ptr) {
|
||||
*((T **)p_ptr) = p_val.data;
|
||||
}
|
||||
};
|
||||
|
||||
GDVIRTUAL_NATIVE_PTR(void)
|
||||
GDVIRTUAL_NATIVE_PTR(AudioFrame)
|
||||
GDVIRTUAL_NATIVE_PTR(bool)
|
||||
GDVIRTUAL_NATIVE_PTR(char)
|
||||
GDVIRTUAL_NATIVE_PTR(char16_t)
|
||||
GDVIRTUAL_NATIVE_PTR(char32_t)
|
||||
GDVIRTUAL_NATIVE_PTR(wchar_t)
|
||||
GDVIRTUAL_NATIVE_PTR(uint8_t)
|
||||
GDVIRTUAL_NATIVE_PTR(uint8_t *)
|
||||
GDVIRTUAL_NATIVE_PTR(int8_t)
|
||||
GDVIRTUAL_NATIVE_PTR(uint16_t)
|
||||
GDVIRTUAL_NATIVE_PTR(int16_t)
|
||||
GDVIRTUAL_NATIVE_PTR(uint32_t)
|
||||
GDVIRTUAL_NATIVE_PTR(int32_t)
|
||||
GDVIRTUAL_NATIVE_PTR(int64_t)
|
||||
GDVIRTUAL_NATIVE_PTR(uint64_t)
|
||||
GDVIRTUAL_NATIVE_PTR(float)
|
||||
GDVIRTUAL_NATIVE_PTR(double)
|
||||
246
core/variant/type_info.h
Normal file
246
core/variant/type_info.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/**************************************************************************/
|
||||
/* type_info.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/templates/simple_type.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace GodotTypeInfo {
|
||||
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,
|
||||
METADATA_INT_IS_CHAR16,
|
||||
METADATA_INT_IS_CHAR32,
|
||||
};
|
||||
}
|
||||
|
||||
// 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<T>' is instantiated.
|
||||
template <typename T, typename = void>
|
||||
struct GetTypeInfo;
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<T, std::enable_if_t<!std::is_same_v<T, GetSimpleTypeT<T>>>> : GetTypeInfo<GetSimpleTypeT<T>> {};
|
||||
|
||||
#define MAKE_TYPE_INFO(m_type, m_var_type) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_type> { \
|
||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::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<m_type> { \
|
||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||
static const GodotTypeInfo::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, GodotTypeInfo::METADATA_INT_IS_UINT8)
|
||||
MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
|
||||
MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
|
||||
MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
|
||||
MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
|
||||
MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
|
||||
MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
|
||||
MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
|
||||
MAKE_TYPE_INFO_WITH_META(char16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_CHAR16)
|
||||
MAKE_TYPE_INFO_WITH_META(char32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_CHAR32)
|
||||
MAKE_TYPE_INFO_WITH_META(float, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
|
||||
MAKE_TYPE_INFO_WITH_META(double, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
|
||||
|
||||
MAKE_TYPE_INFO(String, Variant::STRING)
|
||||
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPE_INFO(Rect2, Variant::RECT2)
|
||||
MAKE_TYPE_INFO(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPE_INFO(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPE_INFO(Rect2i, Variant::RECT2I)
|
||||
MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I)
|
||||
MAKE_TYPE_INFO(Vector4, Variant::VECTOR4)
|
||||
MAKE_TYPE_INFO(Vector4i, Variant::VECTOR4I)
|
||||
MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D)
|
||||
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(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPE_INFO(Projection, Variant::PROJECTION)
|
||||
MAKE_TYPE_INFO(Color, Variant::COLOR)
|
||||
MAKE_TYPE_INFO(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPE_INFO(RID, Variant::RID)
|
||||
MAKE_TYPE_INFO(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPE_INFO(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPE_INFO(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPE_INFO(Array, Variant::ARRAY)
|
||||
MAKE_TYPE_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
|
||||
|
||||
MAKE_TYPE_INFO(IPAddress, Variant::STRING)
|
||||
|
||||
//objectID
|
||||
template <>
|
||||
struct GetTypeInfo<ObjectID> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_INT_IS_UINT64;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_OBJECTID);
|
||||
}
|
||||
};
|
||||
|
||||
//for variant
|
||||
template <>
|
||||
struct GetTypeInfo<Variant> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::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<m_template<m_type>> { \
|
||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||
} \
|
||||
};
|
||||
|
||||
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, Face3, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::PACKED_STRING_ARRAY)
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(StringName(T::get_class_static()));
|
||||
}
|
||||
};
|
||||
|
||||
namespace GodotTypeInfo {
|
||||
namespace Internal {
|
||||
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {
|
||||
Vector<String> parts = p_qualified_name.split("::", false);
|
||||
if (parts.size() <= 2) {
|
||||
return String(".").join(parts);
|
||||
}
|
||||
// Contains namespace. We only want the class and enum names.
|
||||
return parts[parts.size() - 2] + "." + parts[parts.size() - 1];
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace GodotTypeInfo
|
||||
|
||||
#define MAKE_ENUM_TYPE_INFO(m_enum) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_enum> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::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, \
|
||||
GodotTypeInfo::Internal::enum_qualified_name_to_class_info_name(String(#m_enum))); \
|
||||
} \
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline StringName __constant_get_enum_name(T param, const String &p_constant) {
|
||||
return GetTypeInfo<T>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
#define MAKE_BITFIELD_TYPE_INFO(m_enum) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_enum> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
|
||||
GodotTypeInfo::Internal::enum_qualified_name_to_class_info_name(String(#m_enum))); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<BitField<m_enum>> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
|
||||
GodotTypeInfo::Internal::enum_qualified_name_to_class_info_name(String(#m_enum))); \
|
||||
} \
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline StringName __constant_get_bitfield_name(T param, const String &p_constant) {
|
||||
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
|
||||
}
|
||||
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
|
||||
|
||||
// No initialization by default, except for scalar types.
|
||||
template <typename T>
|
||||
struct ZeroInitializer {
|
||||
static void initialize(T &value) {
|
||||
if constexpr (std::is_scalar_v<T>) {
|
||||
value = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
232
core/variant/typed_array.h
Normal file
232
core/variant/typed_array.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/**************************************************************************/
|
||||
/* typed_array.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "core/variant/binder_common.h"
|
||||
#include "core/variant/method_ptrcall.h"
|
||||
#include "core/variant/type_info.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
template <typename T>
|
||||
class TypedArray : public Array {
|
||||
public:
|
||||
_FORCE_INLINE_ void operator=(const Array &p_array) {
|
||||
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type.");
|
||||
Array::operator=(p_array);
|
||||
}
|
||||
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
|
||||
TypedArray(Array(p_variant)) {
|
||||
}
|
||||
_FORCE_INLINE_ TypedArray(const Array &p_array) {
|
||||
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
|
||||
if (is_same_typed(p_array)) {
|
||||
Array::operator=(p_array);
|
||||
} else {
|
||||
assign(p_array);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) :
|
||||
TypedArray(Array(p_init)) {}
|
||||
_FORCE_INLINE_ TypedArray() {
|
||||
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantInternalAccessor<TypedArray<T>> {
|
||||
static _FORCE_INLINE_ TypedArray<T> get(const Variant *v) { return *VariantInternal::get_array(v); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const TypedArray<T> &p_array) { *VariantInternal::get_array(v) = p_array; }
|
||||
};
|
||||
template <typename T>
|
||||
struct VariantInternalAccessor<const TypedArray<T> &> {
|
||||
static _FORCE_INLINE_ TypedArray<T> get(const Variant *v) { return *VariantInternal::get_array(v); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const TypedArray<T> &p_array) { *VariantInternal::get_array(v) = p_array; }
|
||||
};
|
||||
|
||||
//specialization for the rest of variant types
|
||||
|
||||
#define MAKE_TYPED_ARRAY(m_type, m_variant_type) \
|
||||
template <> \
|
||||
class TypedArray<m_type> : public Array { \
|
||||
public: \
|
||||
_FORCE_INLINE_ void operator=(const Array &p_array) { \
|
||||
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type."); \
|
||||
Array::operator=(p_array); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) : \
|
||||
Array(Array(p_init), m_variant_type, StringName(), Variant()) { \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
|
||||
TypedArray(Array(p_variant)) { \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedArray(const Array &p_array) { \
|
||||
set_typed(m_variant_type, StringName(), Variant()); \
|
||||
if (is_same_typed(p_array)) { \
|
||||
Array::operator=(p_array); \
|
||||
} else { \
|
||||
assign(p_array); \
|
||||
} \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedArray() { \
|
||||
set_typed(m_variant_type, StringName(), Variant()); \
|
||||
} \
|
||||
};
|
||||
|
||||
// All Variant::OBJECT types are intentionally omitted from this list because they are handled by
|
||||
// the unspecialized TypedArray definition.
|
||||
MAKE_TYPED_ARRAY(bool, Variant::BOOL)
|
||||
MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(uint16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(uint32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(uint64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(float, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY(double, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY(String, Variant::STRING)
|
||||
MAKE_TYPED_ARRAY(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPED_ARRAY(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPED_ARRAY(Rect2, Variant::RECT2)
|
||||
MAKE_TYPED_ARRAY(Rect2i, Variant::RECT2I)
|
||||
MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
|
||||
MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
|
||||
MAKE_TYPED_ARRAY(Vector4, Variant::VECTOR4)
|
||||
MAKE_TYPED_ARRAY(Vector4i, Variant::VECTOR4I)
|
||||
MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
|
||||
MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_ARRAY(AABB, Variant::AABB)
|
||||
MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
|
||||
MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPED_ARRAY(Projection, Variant::PROJECTION)
|
||||
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
|
||||
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPED_ARRAY(RID, Variant::RID)
|
||||
MAKE_TYPED_ARRAY(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_ARRAY(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_ARRAY(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_ARRAY(Array, Variant::ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
|
||||
MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<TypedArray<T>> {
|
||||
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
|
||||
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
|
||||
}
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static void encode(TypedArray<T> p_val, void *p_ptr) {
|
||||
*(Array *)p_ptr = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<TypedArray<T>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::ARRAY;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
#define MAKE_TYPED_ARRAY_INFO(m_type, m_variant_type) \
|
||||
template <> \
|
||||
struct GetTypeInfo<TypedArray<m_type>> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::ARRAY; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type)); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_TYPED_ARRAY_INFO(bool, Variant::BOOL)
|
||||
MAKE_TYPED_ARRAY_INFO(uint8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(float, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY_INFO(double, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY_INFO(String, Variant::STRING)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPED_ARRAY_INFO(Rect2, Variant::RECT2)
|
||||
MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
|
||||
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector4, Variant::VECTOR4)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector4i, Variant::VECTOR4I)
|
||||
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
|
||||
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
|
||||
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
|
||||
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPED_ARRAY_INFO(Projection, Variant::PROJECTION)
|
||||
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
|
||||
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPED_ARRAY_INFO(RID, Variant::RID)
|
||||
MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
|
||||
|
||||
#undef MAKE_TYPED_ARRAY
|
||||
#undef MAKE_TYPED_ARRAY_INFO
|
||||
322
core/variant/typed_dictionary.h
Normal file
322
core/variant/typed_dictionary.h
Normal file
@@ -0,0 +1,322 @@
|
||||
/**************************************************************************/
|
||||
/* typed_dictionary.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/binder_common.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "core/variant/method_ptrcall.h"
|
||||
#include "core/variant/type_info.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
template <typename K, typename V>
|
||||
class TypedDictionary : public Dictionary {
|
||||
public:
|
||||
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) {
|
||||
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign a dictionary with a different element type.");
|
||||
Dictionary::operator=(p_dictionary);
|
||||
}
|
||||
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) :
|
||||
TypedDictionary(Dictionary(p_variant)) {
|
||||
}
|
||||
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) {
|
||||
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
|
||||
if (is_same_typed(p_dictionary)) {
|
||||
Dictionary::operator=(p_dictionary);
|
||||
} else {
|
||||
assign(p_dictionary);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ TypedDictionary() {
|
||||
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<K, V>> p_init) :
|
||||
Dictionary() {
|
||||
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
|
||||
for (const KeyValue<K, V> &E : p_init) {
|
||||
operator[](E.key) = E.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct VariantInternalAccessor<TypedDictionary<K, V>> {
|
||||
static _FORCE_INLINE_ TypedDictionary<K, V> get(const Variant *v) { return *VariantInternal::get_dictionary(v); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const TypedDictionary<K, V> &p_dictionary) { *VariantInternal::get_dictionary(v) = p_dictionary; }
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct VariantInternalAccessor<const TypedDictionary<K, V> &> {
|
||||
static _FORCE_INLINE_ TypedDictionary<K, V> get(const Variant *v) { return *VariantInternal::get_dictionary(v); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const TypedDictionary<K, V> &p_dictionary) { *VariantInternal::get_dictionary(v) = p_dictionary; }
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct PtrToArg<TypedDictionary<K, V>> {
|
||||
_FORCE_INLINE_ static TypedDictionary<K, V> convert(const void *p_ptr) {
|
||||
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
|
||||
}
|
||||
typedef Dictionary EncodeT;
|
||||
_FORCE_INLINE_ static void encode(TypedDictionary<K, V> p_val, void *p_ptr) {
|
||||
*(Dictionary *)p_ptr = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct GetTypeInfo<TypedDictionary<K, V>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::DICTIONARY;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for the rest of the Variant types.
|
||||
|
||||
#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
|
||||
template <typename T> \
|
||||
class TypedDictionary<T, m_type> : public Dictionary { \
|
||||
public: \
|
||||
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
|
||||
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
|
||||
Dictionary::operator=(p_dictionary); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
|
||||
TypedDictionary(Dictionary(p_variant)) { \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
|
||||
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
|
||||
if (is_same_typed(p_dictionary)) { \
|
||||
Dictionary::operator=(p_dictionary); \
|
||||
} else { \
|
||||
assign(p_dictionary); \
|
||||
} \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary() { \
|
||||
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<T, m_type>> p_init) : \
|
||||
Dictionary() { \
|
||||
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
|
||||
for (const KeyValue<T, m_type> &E : p_init) { \
|
||||
operator[](E.key) = E.value; \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
template <typename T> \
|
||||
struct GetTypeInfo<TypedDictionary<T, m_type>> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::DICTIONARY; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(Variant::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
|
||||
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::NIL ? "Variant" : Variant::get_type_name(m_variant_type))); \
|
||||
} \
|
||||
}; \
|
||||
template <typename T> \
|
||||
class TypedDictionary<m_type, T> : public Dictionary { \
|
||||
public: \
|
||||
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
|
||||
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
|
||||
Dictionary::operator=(p_dictionary); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
|
||||
TypedDictionary(Dictionary(p_variant)) { \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
|
||||
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \
|
||||
if (is_same_typed(p_dictionary)) { \
|
||||
Dictionary::operator=(p_dictionary); \
|
||||
} else { \
|
||||
assign(p_dictionary); \
|
||||
} \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary() { \
|
||||
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<m_type, T>> p_init) : \
|
||||
Dictionary() { \
|
||||
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, std::remove_pointer<T>::type::get_class_static(), Variant()); \
|
||||
for (const KeyValue<m_type, T> &E : p_init) { \
|
||||
operator[](E.key) = E.value; \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
template <typename T> \
|
||||
struct GetTypeInfo<TypedDictionary<m_type, T>> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::DICTIONARY; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(Variant::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
|
||||
vformat("%s;%s", m_variant_type == Variant::NIL ? "Variant" : Variant::get_type_name(m_variant_type), T::get_class_static())); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_TYPED_DICTIONARY_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
|
||||
template <> \
|
||||
class TypedDictionary<m_type_key, m_type_value> : public Dictionary { \
|
||||
public: \
|
||||
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
|
||||
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
|
||||
Dictionary::operator=(p_dictionary); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
|
||||
TypedDictionary(Dictionary(p_variant)) { \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
|
||||
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
|
||||
if (is_same_typed(p_dictionary)) { \
|
||||
Dictionary::operator=(p_dictionary); \
|
||||
} else { \
|
||||
assign(p_dictionary); \
|
||||
} \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary() { \
|
||||
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<m_type_key, m_type_value>> p_init) : \
|
||||
Dictionary() { \
|
||||
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
|
||||
for (const KeyValue<m_type_key, m_type_value> &E : p_init) { \
|
||||
operator[](E.key) = E.value; \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<TypedDictionary<m_type_key, m_type_value>> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::DICTIONARY; \
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return PropertyInfo(Variant::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
|
||||
vformat("%s;%s", m_variant_type_key == Variant::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key), \
|
||||
m_variant_type_value == Variant::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value))); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) \
|
||||
MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING)
|
||||
|
||||
#define MAKE_TYPED_DICTIONARY(m_type, m_variant_type) \
|
||||
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
|
||||
MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type)
|
||||
|
||||
MAKE_TYPED_DICTIONARY_NIL(Variant, Variant::NIL)
|
||||
MAKE_TYPED_DICTIONARY(bool, Variant::BOOL)
|
||||
MAKE_TYPED_DICTIONARY(uint8_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(int8_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(uint16_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(int16_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(uint32_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(int32_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(uint64_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(int64_t, Variant::INT)
|
||||
MAKE_TYPED_DICTIONARY(float, Variant::FLOAT)
|
||||
MAKE_TYPED_DICTIONARY(double, Variant::FLOAT)
|
||||
MAKE_TYPED_DICTIONARY(String, Variant::STRING)
|
||||
MAKE_TYPED_DICTIONARY(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPED_DICTIONARY(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPED_DICTIONARY(Rect2, Variant::RECT2)
|
||||
MAKE_TYPED_DICTIONARY(Rect2i, Variant::RECT2I)
|
||||
MAKE_TYPED_DICTIONARY(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPED_DICTIONARY(Vector3i, Variant::VECTOR3I)
|
||||
MAKE_TYPED_DICTIONARY(Transform2D, Variant::TRANSFORM2D)
|
||||
MAKE_TYPED_DICTIONARY(Plane, Variant::PLANE)
|
||||
MAKE_TYPED_DICTIONARY(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_DICTIONARY(AABB, Variant::AABB)
|
||||
MAKE_TYPED_DICTIONARY(Basis, Variant::BASIS)
|
||||
MAKE_TYPED_DICTIONARY(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPED_DICTIONARY(Color, Variant::COLOR)
|
||||
MAKE_TYPED_DICTIONARY(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPED_DICTIONARY(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPED_DICTIONARY(RID, Variant::RID)
|
||||
MAKE_TYPED_DICTIONARY(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_DICTIONARY(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_DICTIONARY(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_DICTIONARY(Array, Variant::ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
|
||||
MAKE_TYPED_DICTIONARY(IPAddress, Variant::STRING)
|
||||
|
||||
#undef MAKE_TYPED_DICTIONARY
|
||||
#undef MAKE_TYPED_DICTIONARY_NIL
|
||||
#undef MAKE_TYPED_DICTIONARY_EXPANDED
|
||||
#undef MAKE_TYPED_DICTIONARY_WITH_OBJECT
|
||||
3564
core/variant/variant.cpp
Normal file
3564
core/variant/variant.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1012
core/variant/variant.h
Normal file
1012
core/variant/variant.h
Normal file
File diff suppressed because it is too large
Load Diff
3001
core/variant/variant_call.cpp
Normal file
3001
core/variant/variant_call.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
core/variant/variant_callable.cpp
Normal file
90
core/variant/variant_callable.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/**************************************************************************/
|
||||
/* variant_callable.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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_callable.h"
|
||||
|
||||
#include "core/templates/hashfuncs.h"
|
||||
|
||||
bool VariantCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||
return p_a->hash() == p_b->hash();
|
||||
}
|
||||
|
||||
bool VariantCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||
return p_a->hash() < p_b->hash();
|
||||
}
|
||||
|
||||
uint32_t VariantCallable::hash() const {
|
||||
return h;
|
||||
}
|
||||
|
||||
String VariantCallable::get_as_text() const {
|
||||
return vformat("%s::%s", Variant::get_type_name(variant.get_type()), method);
|
||||
}
|
||||
|
||||
CallableCustom::CompareEqualFunc VariantCallable::get_compare_equal_func() const {
|
||||
return compare_equal;
|
||||
}
|
||||
|
||||
CallableCustom::CompareLessFunc VariantCallable::get_compare_less_func() const {
|
||||
return compare_less;
|
||||
}
|
||||
|
||||
bool VariantCallable::is_valid() const {
|
||||
return Variant::has_builtin_method(variant.get_type(), method);
|
||||
}
|
||||
|
||||
StringName VariantCallable::get_method() const {
|
||||
return method;
|
||||
}
|
||||
|
||||
ObjectID VariantCallable::get_object() const {
|
||||
return ObjectID();
|
||||
}
|
||||
|
||||
int VariantCallable::get_argument_count(bool &r_is_valid) const {
|
||||
if (!Variant::has_builtin_method(variant.get_type(), method)) {
|
||||
r_is_valid = false;
|
||||
return 0;
|
||||
}
|
||||
r_is_valid = true;
|
||||
return Variant::get_builtin_method_argument_count(variant.get_type(), method);
|
||||
}
|
||||
|
||||
void VariantCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
Variant v = variant;
|
||||
v.callp(method, p_arguments, p_argcount, r_return_value, r_call_error);
|
||||
}
|
||||
|
||||
VariantCallable::VariantCallable(const Variant &p_variant, const StringName &p_method) {
|
||||
variant = p_variant;
|
||||
method = p_method;
|
||||
h = variant.hash();
|
||||
h = hash_murmur3_one_64(Variant::get_builtin_method_hash(variant.get_type(), method), h);
|
||||
}
|
||||
56
core/variant/variant_callable.h
Normal file
56
core/variant/variant_callable.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/**************************************************************************/
|
||||
/* variant_callable.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/variant/callable.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class VariantCallable : public CallableCustom {
|
||||
Variant variant;
|
||||
StringName method;
|
||||
uint32_t h = 0;
|
||||
|
||||
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
|
||||
public:
|
||||
uint32_t hash() const override;
|
||||
String get_as_text() const override;
|
||||
CompareEqualFunc get_compare_equal_func() const override;
|
||||
CompareLessFunc get_compare_less_func() const override;
|
||||
bool is_valid() const override;
|
||||
StringName get_method() const override;
|
||||
ObjectID get_object() const override;
|
||||
int get_argument_count(bool &r_is_valid) const override;
|
||||
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||
|
||||
VariantCallable(const Variant &p_variant, const StringName &p_method);
|
||||
};
|
||||
344
core/variant/variant_construct.cpp
Normal file
344
core/variant/variant_construct.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
/**************************************************************************/
|
||||
/* variant_construct.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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_construct.h"
|
||||
|
||||
struct VariantConstructData {
|
||||
void (*construct)(Variant &r_base, const Variant **p_args, Callable::CallError &r_error) = nullptr;
|
||||
Variant::ValidatedConstructor validated_construct = nullptr;
|
||||
Variant::PTRConstructor ptr_construct = nullptr;
|
||||
Variant::Type (*get_argument_type)(int) = nullptr;
|
||||
int argument_count = 0;
|
||||
Vector<String> arg_names;
|
||||
};
|
||||
|
||||
static LocalVector<VariantConstructData> construct_data[Variant::VARIANT_MAX];
|
||||
|
||||
template <typename T>
|
||||
static void add_constructor(const Vector<String> &arg_names) {
|
||||
ERR_FAIL_COND_MSG(arg_names.size() != T::get_argument_count(), vformat("Argument names size mismatch for '%s'.", Variant::get_type_name(T::get_base_type())));
|
||||
|
||||
VariantConstructData cd;
|
||||
cd.construct = T::construct;
|
||||
cd.validated_construct = T::validated_construct;
|
||||
cd.ptr_construct = T::ptr_construct;
|
||||
cd.get_argument_type = T::get_argument_type;
|
||||
cd.argument_count = T::get_argument_count();
|
||||
cd.arg_names = arg_names;
|
||||
construct_data[T::get_base_type()].push_back(cd);
|
||||
}
|
||||
|
||||
void Variant::_register_variant_constructors() {
|
||||
add_constructor<VariantConstructNoArgsNil>(sarray());
|
||||
add_constructor<VariantConstructorNil>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<bool>>(sarray());
|
||||
add_constructor<VariantConstructor<bool, bool>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<bool, int64_t>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<bool, double>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<int64_t>>(sarray());
|
||||
add_constructor<VariantConstructor<int64_t, int64_t>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<int64_t, double>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<int64_t, bool>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromString<int64_t>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<double>>(sarray());
|
||||
add_constructor<VariantConstructor<double, double>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<double, int64_t>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<double, bool>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromString<double>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<String>>(sarray());
|
||||
add_constructor<VariantConstructor<String, String>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<String, StringName>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<String, NodePath>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Vector2>>(sarray());
|
||||
add_constructor<VariantConstructor<Vector2, Vector2>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector2, Vector2i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector2, double, double>>(sarray("x", "y"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Vector2i>>(sarray());
|
||||
add_constructor<VariantConstructor<Vector2i, Vector2i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector2i, Vector2>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector2i, int64_t, int64_t>>(sarray("x", "y"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Rect2>>(sarray());
|
||||
add_constructor<VariantConstructor<Rect2, Rect2>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Rect2, Rect2i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Rect2, Vector2, Vector2>>(sarray("position", "size"));
|
||||
add_constructor<VariantConstructor<Rect2, double, double, double, double>>(sarray("x", "y", "width", "height"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Rect2i>>(sarray());
|
||||
add_constructor<VariantConstructor<Rect2i, Rect2i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Rect2i, Rect2>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Rect2i, Vector2i, Vector2i>>(sarray("position", "size"));
|
||||
add_constructor<VariantConstructor<Rect2i, int64_t, int64_t, int64_t, int64_t>>(sarray("x", "y", "width", "height"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Vector3>>(sarray());
|
||||
add_constructor<VariantConstructor<Vector3, Vector3>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector3, Vector3i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector3, double, double, double>>(sarray("x", "y", "z"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Vector3i>>(sarray());
|
||||
add_constructor<VariantConstructor<Vector3i, Vector3i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector3i, Vector3>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector3i, int64_t, int64_t, int64_t>>(sarray("x", "y", "z"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Vector4>>(sarray());
|
||||
add_constructor<VariantConstructor<Vector4, Vector4>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector4, Vector4i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector4, double, double, double, double>>(sarray("x", "y", "z", "w"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Vector4i>>(sarray());
|
||||
add_constructor<VariantConstructor<Vector4i, Vector4i>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector4i, Vector4>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Vector4i, int64_t, int64_t, int64_t, int64_t>>(sarray("x", "y", "z", "w"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Transform2D>>(sarray());
|
||||
add_constructor<VariantConstructor<Transform2D, Transform2D>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Transform2D, float, Vector2>>(sarray("rotation", "position"));
|
||||
add_constructor<VariantConstructor<Transform2D, float, Size2, float, Vector2>>(sarray("rotation", "scale", "skew", "position"));
|
||||
add_constructor<VariantConstructor<Transform2D, Vector2, Vector2, Vector2>>(sarray("x_axis", "y_axis", "origin"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Plane>>(sarray());
|
||||
add_constructor<VariantConstructor<Plane, Plane>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Plane, Vector3>>(sarray("normal"));
|
||||
add_constructor<VariantConstructor<Plane, Vector3, double>>(sarray("normal", "d"));
|
||||
add_constructor<VariantConstructor<Plane, Vector3, Vector3>>(sarray("normal", "point"));
|
||||
add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3"));
|
||||
add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Quaternion>>(sarray());
|
||||
add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle"));
|
||||
add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
|
||||
add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
|
||||
add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<::AABB, Vector3, Vector3>>(sarray("position", "size"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Basis>>(sarray());
|
||||
add_constructor<VariantConstructor<Basis, Basis>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "angle"));
|
||||
add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Transform3D>>(sarray());
|
||||
add_constructor<VariantConstructor<Transform3D, Transform3D>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Transform3D, Basis, Vector3>>(sarray("basis", "origin"));
|
||||
add_constructor<VariantConstructor<Transform3D, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin"));
|
||||
add_constructor<VariantConstructor<Transform3D, Projection>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Projection>>(sarray());
|
||||
add_constructor<VariantConstructor<Projection, Projection>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Projection, Transform3D>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Projection, Vector4, Vector4, Vector4, Vector4>>(sarray("x_axis", "y_axis", "z_axis", "w_axis"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Color>>(sarray());
|
||||
add_constructor<VariantConstructor<Color, Color>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<Color, Color, double>>(sarray("from", "alpha"));
|
||||
add_constructor<VariantConstructor<Color, double, double, double>>(sarray("r", "g", "b"));
|
||||
add_constructor<VariantConstructor<Color, double, double, double, double>>(sarray("r", "g", "b", "a"));
|
||||
add_constructor<VariantConstructor<Color, String>>(sarray("code"));
|
||||
add_constructor<VariantConstructor<Color, String, double>>(sarray("code", "alpha"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<StringName>>(sarray());
|
||||
add_constructor<VariantConstructor<StringName, StringName>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<StringName, String>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<NodePath>>(sarray());
|
||||
add_constructor<VariantConstructor<NodePath, NodePath>>(sarray("from"));
|
||||
add_constructor<VariantConstructor<NodePath, String>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<::RID>>(sarray());
|
||||
add_constructor<VariantConstructor<::RID, ::RID>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgsObject>(sarray());
|
||||
add_constructor<VariantConstructorObject>(sarray("from"));
|
||||
add_constructor<VariantConstructorNilObject>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Callable>>(sarray());
|
||||
add_constructor<VariantConstructor<Callable, Callable>>(sarray("from"));
|
||||
add_constructor<VariantConstructorCallableArgs>(sarray("object", "method"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Signal>>(sarray());
|
||||
add_constructor<VariantConstructor<Signal, Signal>>(sarray("from"));
|
||||
add_constructor<VariantConstructorSignalArgs>(sarray("object", "signal"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Dictionary>>(sarray());
|
||||
add_constructor<VariantConstructor<Dictionary, Dictionary>>(sarray("from"));
|
||||
add_constructor<VariantConstructorTypedDictionary>(sarray("base", "key_type", "key_class_name", "key_script", "value_type", "value_class_name", "value_script"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<Array>>(sarray());
|
||||
add_constructor<VariantConstructor<Array, Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorTypedArray>(sarray("base", "type", "class_name", "script"));
|
||||
add_constructor<VariantConstructorToArray<PackedByteArray>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedInt32Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedInt64Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedFloat32Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedFloat64Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedStringArray>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedVector2Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedVector3Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedColorArray>>(sarray("from"));
|
||||
add_constructor<VariantConstructorToArray<PackedVector4Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedByteArray>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedByteArray, PackedByteArray>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedByteArray>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedInt32Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedInt32Array, PackedInt32Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedInt32Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedInt64Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedInt64Array, PackedInt64Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedInt64Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedFloat32Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedFloat32Array, PackedFloat32Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedFloat32Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedFloat64Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedFloat64Array, PackedFloat64Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedFloat64Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedStringArray>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedStringArray, PackedStringArray>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedStringArray>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedVector2Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedVector2Array, PackedVector2Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedVector2Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedVector3Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedVector3Array, PackedVector3Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedVector3Array>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedColorArray>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedColorArray, PackedColorArray>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedColorArray>>(sarray("from"));
|
||||
|
||||
add_constructor<VariantConstructNoArgs<PackedVector4Array>>(sarray());
|
||||
add_constructor<VariantConstructor<PackedVector4Array, PackedVector4Array>>(sarray("from"));
|
||||
add_constructor<VariantConstructorFromArray<PackedVector4Array>>(sarray("from"));
|
||||
}
|
||||
|
||||
void Variant::_unregister_variant_constructors() {
|
||||
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
||||
construct_data[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Variant::construct(Variant::Type p_type, Variant &base, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
|
||||
uint32_t s = construct_data[p_type].size();
|
||||
for (uint32_t i = 0; i < s; i++) {
|
||||
int argc = construct_data[p_type][i].argument_count;
|
||||
if (argc != p_argcount) {
|
||||
continue;
|
||||
}
|
||||
bool args_match = true;
|
||||
for (int j = 0; j < argc; j++) {
|
||||
if (!Variant::can_convert_strict(p_args[j]->get_type(), construct_data[p_type][i].get_argument_type(j))) {
|
||||
args_match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args_match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
construct_data[p_type][i].construct(base, p_args, r_error);
|
||||
return;
|
||||
}
|
||||
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
|
||||
}
|
||||
|
||||
int Variant::get_constructor_count(Variant::Type p_type) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
|
||||
return construct_data[p_type].size();
|
||||
}
|
||||
|
||||
Variant::ValidatedConstructor Variant::get_validated_constructor(Variant::Type p_type, int p_constructor) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
|
||||
ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), nullptr);
|
||||
return construct_data[p_type][p_constructor].validated_construct;
|
||||
}
|
||||
|
||||
Variant::PTRConstructor Variant::get_ptr_constructor(Variant::Type p_type, int p_constructor) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
|
||||
ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), nullptr);
|
||||
return construct_data[p_type][p_constructor].ptr_construct;
|
||||
}
|
||||
|
||||
int Variant::get_constructor_argument_count(Variant::Type p_type, int p_constructor) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
|
||||
ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), -1);
|
||||
return construct_data[p_type][p_constructor].argument_count;
|
||||
}
|
||||
|
||||
Variant::Type Variant::get_constructor_argument_type(Variant::Type p_type, int p_constructor, int p_argument) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::VARIANT_MAX);
|
||||
ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), Variant::VARIANT_MAX);
|
||||
return construct_data[p_type][p_constructor].get_argument_type(p_argument);
|
||||
}
|
||||
|
||||
String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constructor, int p_argument) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, String());
|
||||
ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), String());
|
||||
return construct_data[p_type][p_constructor].arg_names[p_argument];
|
||||
}
|
||||
|
||||
void Variant::get_constructor_list(Type p_type, List<MethodInfo> *r_list) {
|
||||
ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
|
||||
|
||||
MethodInfo mi;
|
||||
mi.return_val.type = p_type;
|
||||
mi.name = get_type_name(p_type);
|
||||
|
||||
for (int i = 0; i < get_constructor_count(p_type); i++) {
|
||||
int ac = get_constructor_argument_count(p_type, i);
|
||||
mi.arguments.clear();
|
||||
for (int j = 0; j < ac; j++) {
|
||||
PropertyInfo arg;
|
||||
arg.name = get_constructor_argument_name(p_type, i, j);
|
||||
arg.type = get_constructor_argument_type(p_type, i, j);
|
||||
mi.arguments.push_back(arg);
|
||||
}
|
||||
r_list->push_back(mi);
|
||||
}
|
||||
}
|
||||
814
core/variant/variant_construct.h
Normal file
814
core/variant/variant_construct.h
Normal file
@@ -0,0 +1,814 @@
|
||||
/**************************************************************************/
|
||||
/* variant_construct.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "variant.h"
|
||||
|
||||
#include "core/crypto/crypto_core.h"
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/io/compression.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/a_hash_map.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
|
||||
template <typename T>
|
||||
struct PtrConstruct {};
|
||||
|
||||
#define MAKE_PTRCONSTRUCT(m_type) \
|
||||
template <> \
|
||||
struct PtrConstruct<m_type> { \
|
||||
_FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \
|
||||
memnew_placement(p_ptr, m_type(p_value)); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_PTRCONSTRUCT(bool);
|
||||
MAKE_PTRCONSTRUCT(int64_t);
|
||||
MAKE_PTRCONSTRUCT(double);
|
||||
MAKE_PTRCONSTRUCT(String);
|
||||
MAKE_PTRCONSTRUCT(Vector2);
|
||||
MAKE_PTRCONSTRUCT(Vector2i);
|
||||
MAKE_PTRCONSTRUCT(Rect2);
|
||||
MAKE_PTRCONSTRUCT(Rect2i);
|
||||
MAKE_PTRCONSTRUCT(Vector3);
|
||||
MAKE_PTRCONSTRUCT(Vector3i);
|
||||
MAKE_PTRCONSTRUCT(Vector4);
|
||||
MAKE_PTRCONSTRUCT(Vector4i);
|
||||
MAKE_PTRCONSTRUCT(Transform2D);
|
||||
MAKE_PTRCONSTRUCT(Plane);
|
||||
MAKE_PTRCONSTRUCT(Quaternion);
|
||||
MAKE_PTRCONSTRUCT(AABB);
|
||||
MAKE_PTRCONSTRUCT(Basis);
|
||||
MAKE_PTRCONSTRUCT(Transform3D);
|
||||
MAKE_PTRCONSTRUCT(Projection);
|
||||
MAKE_PTRCONSTRUCT(Color);
|
||||
MAKE_PTRCONSTRUCT(StringName);
|
||||
MAKE_PTRCONSTRUCT(NodePath);
|
||||
MAKE_PTRCONSTRUCT(RID);
|
||||
|
||||
template <>
|
||||
struct PtrConstruct<Object *> {
|
||||
_FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) {
|
||||
*((Object **)p_ptr) = p_value;
|
||||
}
|
||||
};
|
||||
|
||||
MAKE_PTRCONSTRUCT(Callable);
|
||||
MAKE_PTRCONSTRUCT(Signal);
|
||||
MAKE_PTRCONSTRUCT(Dictionary);
|
||||
MAKE_PTRCONSTRUCT(Array);
|
||||
MAKE_PTRCONSTRUCT(PackedByteArray);
|
||||
MAKE_PTRCONSTRUCT(PackedInt32Array);
|
||||
MAKE_PTRCONSTRUCT(PackedInt64Array);
|
||||
MAKE_PTRCONSTRUCT(PackedFloat32Array);
|
||||
MAKE_PTRCONSTRUCT(PackedFloat64Array);
|
||||
MAKE_PTRCONSTRUCT(PackedStringArray);
|
||||
MAKE_PTRCONSTRUCT(PackedVector2Array);
|
||||
MAKE_PTRCONSTRUCT(PackedVector3Array);
|
||||
MAKE_PTRCONSTRUCT(PackedColorArray);
|
||||
MAKE_PTRCONSTRUCT(PackedVector4Array);
|
||||
MAKE_PTRCONSTRUCT(Variant);
|
||||
|
||||
template <typename T, typename... P>
|
||||
class VariantConstructor {
|
||||
template <size_t... Is>
|
||||
static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
base = T(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
template <size_t... Is>
|
||||
static _FORCE_INLINE_ void validated_construct_helper(T &base, const Variant **p_args, IndexSequence<Is...>) {
|
||||
base = T((*VariantGetInternalPtr<P>::get_ptr(p_args[Is]))...);
|
||||
}
|
||||
|
||||
template <size_t... Is>
|
||||
static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) {
|
||||
PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base);
|
||||
}
|
||||
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
VariantTypeChanger<T>::change(&r_ret);
|
||||
construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<T>::change(r_ret);
|
||||
validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return sizeof...(P);
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return GetTypeInfo<T>::VARIANT_TYPE;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorObject {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() == Variant::NIL) {
|
||||
VariantInternal::clear(&r_ret);
|
||||
VariantTypeChanger<Object *>::change(&r_ret);
|
||||
VariantInternal::object_reset_data(&r_ret);
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
} else if (p_args[0]->get_type() == Variant::OBJECT) {
|
||||
VariantTypeChanger<Object *>::change(&r_ret);
|
||||
VariantInternal::object_assign(&r_ret, p_args[0]);
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
} else {
|
||||
VariantInternal::clear(&r_ret);
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<Object *>::change(r_ret);
|
||||
VariantInternal::object_assign(r_ret, p_args[0]);
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::OBJECT;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::OBJECT;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorNilObject {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() != Variant::NIL) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::NIL;
|
||||
}
|
||||
|
||||
VariantInternal::clear(&r_ret);
|
||||
VariantTypeChanger<Object *>::change(&r_ret);
|
||||
VariantInternal::object_reset_data(&r_ret);
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantInternal::clear(r_ret);
|
||||
VariantTypeChanger<Object *>::change(r_ret);
|
||||
VariantInternal::object_reset_data(r_ret);
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<Object *>::construct(nullptr, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::NIL;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::OBJECT;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class VariantConstructorFromString {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (!p_args[0]->is_string()) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::STRING;
|
||||
return;
|
||||
}
|
||||
|
||||
VariantTypeChanger<T>::change(&r_ret);
|
||||
const String src_str = *p_args[0];
|
||||
|
||||
if (r_ret.get_type() == Variant::Type::INT) {
|
||||
r_ret = src_str.to_int();
|
||||
} else if (r_ret.get_type() == Variant::Type::FLOAT) {
|
||||
r_ret = src_str.to_float();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<T>::change(r_ret);
|
||||
const String &src_str = *VariantGetInternalPtr<String>::get_ptr(p_args[0]);
|
||||
T ret = Variant();
|
||||
if (r_ret->get_type() == Variant::Type::INT) {
|
||||
ret = src_str.to_int();
|
||||
} else if (r_ret->get_type() == Variant::Type::FLOAT) {
|
||||
ret = src_str.to_float();
|
||||
}
|
||||
*r_ret = ret;
|
||||
}
|
||||
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
String src_str = PtrToArg<String>::convert(p_args[0]);
|
||||
T dst_var = Variant();
|
||||
Variant type_test = Variant(dst_var);
|
||||
if (type_test.get_type() == Variant::Type::INT) {
|
||||
dst_var = src_str.to_int();
|
||||
} else if (type_test.get_type() == Variant::Type::FLOAT) {
|
||||
dst_var = src_str.to_float();
|
||||
}
|
||||
PtrConstruct<T>::construct(dst_var, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::STRING;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return GetTypeInfo<T>::VARIANT_TYPE;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorCallableArgs {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
ObjectID object_id;
|
||||
StringName method;
|
||||
|
||||
if (p_args[0]->get_type() == Variant::NIL) {
|
||||
// leave as is
|
||||
} else if (p_args[0]->get_type() == Variant::OBJECT) {
|
||||
object_id = VariantInternal::get_object_id(p_args[0]);
|
||||
} else {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::OBJECT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[1]->get_type() == Variant::STRING_NAME) {
|
||||
method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]);
|
||||
} else if (p_args[1]->get_type() == Variant::STRING) {
|
||||
method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]);
|
||||
} else {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 1;
|
||||
r_error.expected = Variant::STRING_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
VariantTypeChanger<Callable>::change(&r_ret);
|
||||
*VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method);
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<Callable>::change(r_ret);
|
||||
*VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
if (p_arg == 0) {
|
||||
return Variant::OBJECT;
|
||||
} else {
|
||||
return Variant::STRING_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::CALLABLE;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorSignalArgs {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
ObjectID object_id;
|
||||
StringName method;
|
||||
|
||||
if (p_args[0]->get_type() == Variant::NIL) {
|
||||
// leave as is
|
||||
} else if (p_args[0]->get_type() == Variant::OBJECT) {
|
||||
object_id = VariantInternal::get_object_id(p_args[0]);
|
||||
} else {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::OBJECT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[1]->get_type() == Variant::STRING_NAME) {
|
||||
method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]);
|
||||
} else if (p_args[1]->get_type() == Variant::STRING) {
|
||||
method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]);
|
||||
} else {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 1;
|
||||
r_error.expected = Variant::STRING_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
VariantTypeChanger<Signal>::change(&r_ret);
|
||||
*VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method);
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<Signal>::change(r_ret);
|
||||
*VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
if (p_arg == 0) {
|
||||
return Variant::OBJECT;
|
||||
} else {
|
||||
return Variant::STRING_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::SIGNAL;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorTypedDictionary {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() != Variant::DICTIONARY) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::DICTIONARY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[1]->get_type() != Variant::INT) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 1;
|
||||
r_error.expected = Variant::INT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[2]->get_type() != Variant::STRING_NAME) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 2;
|
||||
r_error.expected = Variant::STRING_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[4]->get_type() != Variant::INT) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 4;
|
||||
r_error.expected = Variant::INT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[5]->get_type() != Variant::STRING_NAME) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 5;
|
||||
r_error.expected = Variant::STRING_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
const Dictionary &base_dict = *VariantGetInternalPtr<Dictionary>::get_ptr(p_args[0]);
|
||||
const uint32_t key_type = p_args[1]->operator uint32_t();
|
||||
const StringName &key_class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
|
||||
const uint32_t value_type = p_args[4]->operator uint32_t();
|
||||
const StringName &value_class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[5]);
|
||||
r_ret = Dictionary(base_dict, key_type, key_class_name, *p_args[3], value_type, value_class_name, *p_args[6]);
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
const Dictionary &base_dict = *VariantGetInternalPtr<Dictionary>::get_ptr(p_args[0]);
|
||||
const uint32_t key_type = p_args[1]->operator uint32_t();
|
||||
const StringName &key_class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
|
||||
const uint32_t value_type = p_args[4]->operator uint32_t();
|
||||
const StringName &value_class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[5]);
|
||||
*r_ret = Dictionary(base_dict, key_type, key_class_name, *p_args[3], value_type, value_class_name, *p_args[6]);
|
||||
}
|
||||
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
const Dictionary &base_dict = PtrToArg<Dictionary>::convert(p_args[0]);
|
||||
const uint32_t key_type = PtrToArg<uint32_t>::convert(p_args[1]);
|
||||
const StringName &key_class_name = PtrToArg<StringName>::convert(p_args[2]);
|
||||
const Variant &key_script = PtrToArg<Variant>::convert(p_args[3]);
|
||||
const uint32_t value_type = PtrToArg<uint32_t>::convert(p_args[4]);
|
||||
const StringName &value_class_name = PtrToArg<StringName>::convert(p_args[5]);
|
||||
const Variant &value_script = PtrToArg<Variant>::convert(p_args[6]);
|
||||
Dictionary dst_arr = Dictionary(base_dict, key_type, key_class_name, key_script, value_type, value_class_name, value_script);
|
||||
|
||||
PtrConstruct<Dictionary>::construct(dst_arr, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 7;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
switch (p_arg) {
|
||||
case 0: {
|
||||
return Variant::DICTIONARY;
|
||||
} break;
|
||||
case 1: {
|
||||
return Variant::INT;
|
||||
} break;
|
||||
case 2: {
|
||||
return Variant::STRING_NAME;
|
||||
} break;
|
||||
case 3: {
|
||||
return Variant::NIL;
|
||||
} break;
|
||||
case 4: {
|
||||
return Variant::INT;
|
||||
} break;
|
||||
case 5: {
|
||||
return Variant::STRING_NAME;
|
||||
} break;
|
||||
case 6: {
|
||||
return Variant::NIL;
|
||||
} break;
|
||||
default: {
|
||||
return Variant::NIL;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::DICTIONARY;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorTypedArray {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() != Variant::ARRAY) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::ARRAY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_args[1]->get_type() != Variant::INT) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 1;
|
||||
r_error.expected = Variant::INT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p_args[2]->is_string()) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 2;
|
||||
r_error.expected = Variant::STRING_NAME;
|
||||
return;
|
||||
}
|
||||
|
||||
const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
|
||||
const uint32_t type = p_args[1]->operator uint32_t();
|
||||
r_ret = Array(base_arr, type, *p_args[2], *p_args[3]);
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
|
||||
const uint32_t type = p_args[1]->operator uint32_t();
|
||||
const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
|
||||
*r_ret = Array(base_arr, type, class_name, *p_args[3]);
|
||||
}
|
||||
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
const Array &base_arr = PtrToArg<Array>::convert(p_args[0]);
|
||||
const uint32_t type = PtrToArg<uint32_t>::convert(p_args[1]);
|
||||
const StringName &class_name = PtrToArg<StringName>::convert(p_args[2]);
|
||||
const Variant &script = PtrToArg<Variant>::convert(p_args[3]);
|
||||
Array dst_arr = Array(base_arr, type, class_name, script);
|
||||
|
||||
PtrConstruct<Array>::construct(dst_arr, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
switch (p_arg) {
|
||||
case 0: {
|
||||
return Variant::ARRAY;
|
||||
} break;
|
||||
case 1: {
|
||||
return Variant::INT;
|
||||
} break;
|
||||
case 2: {
|
||||
return Variant::STRING_NAME;
|
||||
} break;
|
||||
case 3: {
|
||||
return Variant::NIL;
|
||||
} break;
|
||||
default: {
|
||||
return Variant::NIL;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class VariantConstructorToArray {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() != GetTypeInfo<T>::VARIANT_TYPE) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = GetTypeInfo<T>::VARIANT_TYPE;
|
||||
return;
|
||||
}
|
||||
|
||||
r_ret = Array();
|
||||
Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret);
|
||||
const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]);
|
||||
|
||||
int size = src_arr.size();
|
||||
dst_arr.resize(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst_arr[i] = src_arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
*r_ret = Array();
|
||||
Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret);
|
||||
const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]);
|
||||
|
||||
int size = src_arr.size();
|
||||
dst_arr.resize(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst_arr[i] = src_arr[i];
|
||||
}
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
Array dst_arr;
|
||||
T src_arr = PtrToArg<T>::convert(p_args[0]);
|
||||
|
||||
int size = src_arr.size();
|
||||
dst_arr.resize(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst_arr[i] = src_arr[i];
|
||||
}
|
||||
|
||||
PtrConstruct<Array>::construct(dst_arr, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return GetTypeInfo<T>::VARIANT_TYPE;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class VariantConstructorFromArray {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() != Variant::ARRAY) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::ARRAY;
|
||||
return;
|
||||
}
|
||||
|
||||
VariantTypeChanger<T>::change(&r_ret);
|
||||
const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
|
||||
T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret);
|
||||
|
||||
int size = src_arr.size();
|
||||
dst_arr.resize(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst_arr.write[i] = src_arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<T>::change(r_ret);
|
||||
const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
|
||||
T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret);
|
||||
|
||||
int size = src_arr.size();
|
||||
dst_arr.resize(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst_arr.write[i] = src_arr[i];
|
||||
}
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
Array src_arr = PtrToArg<Array>::convert(p_args[0]);
|
||||
T dst_arr;
|
||||
|
||||
int size = src_arr.size();
|
||||
dst_arr.resize(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst_arr.write[i] = src_arr[i];
|
||||
}
|
||||
|
||||
PtrConstruct<T>::construct(dst_arr, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return GetTypeInfo<T>::VARIANT_TYPE;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructorNil {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
if (p_args[0]->get_type() != Variant::NIL) {
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = 0;
|
||||
r_error.expected = Variant::NIL;
|
||||
return;
|
||||
}
|
||||
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
VariantInternal::clear(&r_ret);
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantInternal::clear(r_ret);
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<Variant>::construct(Variant(), base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::NIL;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::NIL;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class VariantConstructNoArgs {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
VariantTypeChanger<T>::change_and_reset(&r_ret);
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantTypeChanger<T>::change_and_reset(r_ret);
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<T>::construct(T(), base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::NIL;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return GetTypeInfo<T>::VARIANT_TYPE;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructNoArgsNil {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
VariantInternal::clear(&r_ret);
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
VariantInternal::clear(r_ret);
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
ERR_FAIL_MSG("Cannot ptrcall nil constructor");
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::NIL;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::NIL;
|
||||
}
|
||||
};
|
||||
|
||||
class VariantConstructNoArgsObject {
|
||||
public:
|
||||
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
|
||||
r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr.
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
}
|
||||
|
||||
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
|
||||
*r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr.
|
||||
}
|
||||
static void ptr_construct(void *base, const void **p_args) {
|
||||
PtrConstruct<Object *>::construct(nullptr, base);
|
||||
}
|
||||
|
||||
static int get_argument_count() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Variant::Type get_argument_type(int p_arg) {
|
||||
return Variant::NIL;
|
||||
}
|
||||
|
||||
static Variant::Type get_base_type() {
|
||||
return Variant::OBJECT;
|
||||
}
|
||||
};
|
||||
41
core/variant/variant_deep_duplicate.h
Normal file
41
core/variant/variant_deep_duplicate.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**************************************************************************/
|
||||
/* variant_deep_duplicate.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
// This would be ideally declared nested in Variant, but that would cause circular
|
||||
// includes with Array and Dictionary, for instance.
|
||||
// Also, this enum is be exposed via Resource.
|
||||
enum ResourceDeepDuplicateMode {
|
||||
RESOURCE_DEEP_DUPLICATE_NONE,
|
||||
RESOURCE_DEEP_DUPLICATE_INTERNAL,
|
||||
RESOURCE_DEEP_DUPLICATE_ALL,
|
||||
RESOURCE_DEEP_DUPLICATE_MAX
|
||||
};
|
||||
72
core/variant/variant_destruct.cpp
Normal file
72
core/variant/variant_destruct.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/**************************************************************************/
|
||||
/* variant_destruct.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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_destruct.h"
|
||||
|
||||
static Variant::PTRDestructor destruct_pointers[Variant::VARIANT_MAX] = { nullptr };
|
||||
|
||||
template <typename T>
|
||||
static void add_destructor() {
|
||||
destruct_pointers[T::get_base_type()] = T::ptr_destruct;
|
||||
}
|
||||
|
||||
void Variant::_register_variant_destructors() {
|
||||
add_destructor<VariantDestruct<String>>();
|
||||
add_destructor<VariantDestruct<StringName>>();
|
||||
add_destructor<VariantDestruct<NodePath>>();
|
||||
add_destructor<VariantDestruct<Callable>>();
|
||||
add_destructor<VariantDestruct<Signal>>();
|
||||
add_destructor<VariantDestruct<Dictionary>>();
|
||||
add_destructor<VariantDestruct<Array>>();
|
||||
add_destructor<VariantDestruct<PackedByteArray>>();
|
||||
add_destructor<VariantDestruct<PackedInt32Array>>();
|
||||
add_destructor<VariantDestruct<PackedInt64Array>>();
|
||||
add_destructor<VariantDestruct<PackedFloat32Array>>();
|
||||
add_destructor<VariantDestruct<PackedFloat64Array>>();
|
||||
add_destructor<VariantDestruct<PackedStringArray>>();
|
||||
add_destructor<VariantDestruct<PackedVector2Array>>();
|
||||
add_destructor<VariantDestruct<PackedVector3Array>>();
|
||||
add_destructor<VariantDestruct<PackedColorArray>>();
|
||||
add_destructor<VariantDestruct<PackedVector4Array>>();
|
||||
}
|
||||
|
||||
void Variant::_unregister_variant_destructors() {
|
||||
// Nothing to be done.
|
||||
}
|
||||
|
||||
Variant::PTRDestructor Variant::get_ptr_destructor(Variant::Type p_type) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
|
||||
return destruct_pointers[p_type];
|
||||
}
|
||||
|
||||
bool Variant::has_destructor(Variant::Type p_type) {
|
||||
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
|
||||
return destruct_pointers[p_type] != nullptr;
|
||||
}
|
||||
69
core/variant/variant_destruct.h
Normal file
69
core/variant/variant_destruct.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**************************************************************************/
|
||||
/* variant_destruct.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
template <typename T>
|
||||
struct VariantDestruct {};
|
||||
|
||||
#define MAKE_PTRDESTRUCT(m_type) \
|
||||
template <> \
|
||||
struct VariantDestruct<m_type> { \
|
||||
_FORCE_INLINE_ static void ptr_destruct(void *p_ptr) { \
|
||||
reinterpret_cast<m_type *>(p_ptr)->~m_type(); \
|
||||
} \
|
||||
_FORCE_INLINE_ static Variant::Type get_base_type() { \
|
||||
return GetTypeInfo<m_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_PTRDESTRUCT(String);
|
||||
MAKE_PTRDESTRUCT(StringName);
|
||||
MAKE_PTRDESTRUCT(NodePath);
|
||||
MAKE_PTRDESTRUCT(Callable);
|
||||
MAKE_PTRDESTRUCT(Signal);
|
||||
MAKE_PTRDESTRUCT(Dictionary);
|
||||
MAKE_PTRDESTRUCT(Array);
|
||||
MAKE_PTRDESTRUCT(PackedByteArray);
|
||||
MAKE_PTRDESTRUCT(PackedInt32Array);
|
||||
MAKE_PTRDESTRUCT(PackedInt64Array);
|
||||
MAKE_PTRDESTRUCT(PackedFloat32Array);
|
||||
MAKE_PTRDESTRUCT(PackedFloat64Array);
|
||||
MAKE_PTRDESTRUCT(PackedStringArray);
|
||||
MAKE_PTRDESTRUCT(PackedVector2Array);
|
||||
MAKE_PTRDESTRUCT(PackedVector3Array);
|
||||
MAKE_PTRDESTRUCT(PackedColorArray);
|
||||
MAKE_PTRDESTRUCT(PackedVector4Array);
|
||||
|
||||
#undef MAKE_PTRDESTRUCT
|
||||
1450
core/variant/variant_internal.h
Normal file
1450
core/variant/variant_internal.h
Normal file
File diff suppressed because it is too large
Load Diff
1173
core/variant/variant_op.cpp
Normal file
1173
core/variant/variant_op.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1555
core/variant/variant_op.h
Normal file
1555
core/variant/variant_op.h
Normal file
File diff suppressed because it is too large
Load Diff
2585
core/variant/variant_parser.cpp
Normal file
2585
core/variant/variant_parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
165
core/variant/variant_parser.h
Normal file
165
core/variant/variant_parser.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************/
|
||||
/* variant_parser.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class VariantParser {
|
||||
public:
|
||||
struct Stream {
|
||||
private:
|
||||
enum { READAHEAD_SIZE = 2048 };
|
||||
char32_t readahead_buffer[READAHEAD_SIZE];
|
||||
uint32_t readahead_pointer = 0;
|
||||
uint32_t readahead_filled = 0;
|
||||
bool eof = false;
|
||||
|
||||
protected:
|
||||
bool readahead_enabled = true;
|
||||
virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) = 0;
|
||||
virtual bool _is_eof() const = 0;
|
||||
|
||||
public:
|
||||
char32_t saved = 0;
|
||||
|
||||
char32_t get_char();
|
||||
virtual bool is_utf8() const = 0;
|
||||
bool is_eof() const;
|
||||
|
||||
Stream() {}
|
||||
virtual ~Stream() {}
|
||||
};
|
||||
|
||||
struct StreamFile : public Stream {
|
||||
protected:
|
||||
virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) override;
|
||||
virtual bool _is_eof() const override;
|
||||
|
||||
public:
|
||||
Ref<FileAccess> f;
|
||||
|
||||
virtual bool is_utf8() const override;
|
||||
|
||||
StreamFile(bool p_readahead_enabled = true) { readahead_enabled = p_readahead_enabled; }
|
||||
};
|
||||
|
||||
struct StreamString : public Stream {
|
||||
String s;
|
||||
|
||||
private:
|
||||
int pos = 0;
|
||||
|
||||
protected:
|
||||
virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) override;
|
||||
virtual bool _is_eof() const override;
|
||||
|
||||
public:
|
||||
virtual bool is_utf8() const override;
|
||||
StreamString(bool p_readahead_enabled = true) { readahead_enabled = p_readahead_enabled; }
|
||||
};
|
||||
|
||||
typedef Error (*ParseResourceFunc)(void *p_self, Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
|
||||
|
||||
struct ResourceParser {
|
||||
void *userdata = nullptr;
|
||||
ParseResourceFunc func = nullptr;
|
||||
ParseResourceFunc ext_func = nullptr;
|
||||
ParseResourceFunc sub_func = nullptr;
|
||||
};
|
||||
|
||||
enum TokenType {
|
||||
TK_CURLY_BRACKET_OPEN,
|
||||
TK_CURLY_BRACKET_CLOSE,
|
||||
TK_BRACKET_OPEN,
|
||||
TK_BRACKET_CLOSE,
|
||||
TK_PARENTHESIS_OPEN,
|
||||
TK_PARENTHESIS_CLOSE,
|
||||
TK_IDENTIFIER,
|
||||
TK_STRING,
|
||||
TK_STRING_NAME,
|
||||
TK_NUMBER,
|
||||
TK_COLOR,
|
||||
TK_COLON,
|
||||
TK_COMMA,
|
||||
TK_PERIOD,
|
||||
TK_EQUAL,
|
||||
TK_EOF,
|
||||
TK_ERROR,
|
||||
TK_MAX
|
||||
};
|
||||
|
||||
enum Expecting {
|
||||
EXPECT_OBJECT,
|
||||
EXPECT_OBJECT_KEY,
|
||||
EXPECT_COLON,
|
||||
EXPECT_OBJECT_VALUE,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
Variant value;
|
||||
};
|
||||
|
||||
struct Tag {
|
||||
String name;
|
||||
HashMap<String, Variant> fields;
|
||||
};
|
||||
|
||||
private:
|
||||
static const char *tk_name[TK_MAX];
|
||||
|
||||
template <typename T>
|
||||
static Error _parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str);
|
||||
static Error _parse_byte_array(Stream *p_stream, Vector<uint8_t> &r_construct, int &line, String &r_err_str);
|
||||
static Error _parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str);
|
||||
static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
|
||||
static Error _parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
|
||||
static Error _parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
|
||||
|
||||
public:
|
||||
static Error parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
|
||||
static Error parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
|
||||
|
||||
static Error parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
|
||||
static Error get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str);
|
||||
static Error parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser = nullptr);
|
||||
};
|
||||
|
||||
class VariantWriter {
|
||||
public:
|
||||
typedef Error (*StoreStringFunc)(void *ud, const String &p_string);
|
||||
typedef String (*EncodeResourceFunc)(void *ud, const Ref<Resource> &p_resource);
|
||||
|
||||
static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0, bool p_compat = true);
|
||||
static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr, bool p_compat = true);
|
||||
};
|
||||
2033
core/variant/variant_setget.cpp
Normal file
2033
core/variant/variant_setget.cpp
Normal file
File diff suppressed because it is too large
Load Diff
360
core/variant/variant_setget.h
Normal file
360
core/variant/variant_setget.h
Normal file
@@ -0,0 +1,360 @@
|
||||
/**************************************************************************/
|
||||
/* variant_setget.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "variant.h"
|
||||
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/variant/variant_internal.h"
|
||||
|
||||
/**** NAMED SETTERS AND GETTERS ****/
|
||||
|
||||
#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_member = PtrToArg<m_member_type>::convert(member); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == Variant::FLOAT) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \
|
||||
valid = true; \
|
||||
} else if (value->get_type() == Variant::INT) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_member = PtrToArg<m_member_type>::convert(member); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_custom = PtrToArg<m_member_type>::convert(member); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == Variant::FLOAT) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \
|
||||
valid = true; \
|
||||
} else if (value->get_type() == Variant::INT) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_custom = PtrToArg<m_member_type>::convert(member); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_setter(PtrToArg<m_member_type>::convert(member)); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == Variant::FLOAT) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \
|
||||
valid = true; \
|
||||
} else if (value->get_type() == Variant::INT) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_setter(PtrToArg<m_member_type>::convert(member)); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \
|
||||
struct VariantSetGet_##m_base_type##_##m_member { \
|
||||
static void get(const Variant *base, Variant *member) { \
|
||||
VariantTypeAdjust<m_member_type>::adjust(member); \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \
|
||||
} \
|
||||
static inline void validated_get(const Variant *base, Variant *member) { \
|
||||
*VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \
|
||||
} \
|
||||
static void ptr_get(const void *base, void *member) { \
|
||||
PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \
|
||||
} \
|
||||
static void set(Variant *base, const Variant *value, bool &valid) { \
|
||||
if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
|
||||
valid = true; \
|
||||
} else { \
|
||||
valid = false; \
|
||||
} \
|
||||
} \
|
||||
static inline void validated_set(Variant *base, const Variant *value) { \
|
||||
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
|
||||
} \
|
||||
static void ptr_set(void *base, const void *member) { \
|
||||
m_base_type b = PtrToArg<m_base_type>::convert(base); \
|
||||
b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \
|
||||
PtrToArg<m_base_type>::encode(b, base); \
|
||||
} \
|
||||
static Variant::Type get_type() { \
|
||||
return GetTypeInfo<m_member_type>::VARIANT_TYPE; \
|
||||
} \
|
||||
};
|
||||
|
||||
SETGET_NUMBER_STRUCT(Vector2, double, x)
|
||||
SETGET_NUMBER_STRUCT(Vector2, double, y)
|
||||
|
||||
SETGET_NUMBER_STRUCT(Vector2i, int64_t, x)
|
||||
SETGET_NUMBER_STRUCT(Vector2i, int64_t, y)
|
||||
|
||||
SETGET_NUMBER_STRUCT(Vector3, double, x)
|
||||
SETGET_NUMBER_STRUCT(Vector3, double, y)
|
||||
SETGET_NUMBER_STRUCT(Vector3, double, z)
|
||||
|
||||
SETGET_NUMBER_STRUCT(Vector3i, int64_t, x)
|
||||
SETGET_NUMBER_STRUCT(Vector3i, int64_t, y)
|
||||
SETGET_NUMBER_STRUCT(Vector3i, int64_t, z)
|
||||
|
||||
SETGET_NUMBER_STRUCT(Vector4, double, x)
|
||||
SETGET_NUMBER_STRUCT(Vector4, double, y)
|
||||
SETGET_NUMBER_STRUCT(Vector4, double, z)
|
||||
SETGET_NUMBER_STRUCT(Vector4, double, w)
|
||||
|
||||
SETGET_NUMBER_STRUCT(Vector4i, int64_t, x)
|
||||
SETGET_NUMBER_STRUCT(Vector4i, int64_t, y)
|
||||
SETGET_NUMBER_STRUCT(Vector4i, int64_t, z)
|
||||
SETGET_NUMBER_STRUCT(Vector4i, int64_t, w)
|
||||
|
||||
SETGET_STRUCT(Rect2, Vector2, position)
|
||||
SETGET_STRUCT(Rect2, Vector2, size)
|
||||
SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end)
|
||||
|
||||
SETGET_STRUCT(Rect2i, Vector2i, position)
|
||||
SETGET_STRUCT(Rect2i, Vector2i, size)
|
||||
SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end)
|
||||
|
||||
SETGET_STRUCT(AABB, Vector3, position)
|
||||
SETGET_STRUCT(AABB, Vector3, size)
|
||||
SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end)
|
||||
|
||||
SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, columns[0])
|
||||
SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, columns[1])
|
||||
SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, columns[2])
|
||||
|
||||
SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x)
|
||||
SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y)
|
||||
SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z)
|
||||
SETGET_STRUCT(Plane, Vector3, normal)
|
||||
SETGET_NUMBER_STRUCT(Plane, double, d)
|
||||
|
||||
SETGET_NUMBER_STRUCT(Quaternion, double, x)
|
||||
SETGET_NUMBER_STRUCT(Quaternion, double, y)
|
||||
SETGET_NUMBER_STRUCT(Quaternion, double, z)
|
||||
SETGET_NUMBER_STRUCT(Quaternion, double, w)
|
||||
|
||||
SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_column, get_column, 0)
|
||||
SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_column, get_column, 1)
|
||||
SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_column, get_column, 2)
|
||||
|
||||
SETGET_STRUCT(Transform3D, Basis, basis)
|
||||
SETGET_STRUCT(Transform3D, Vector3, origin)
|
||||
|
||||
SETGET_STRUCT_CUSTOM(Projection, Vector4, x, columns[0])
|
||||
SETGET_STRUCT_CUSTOM(Projection, Vector4, y, columns[1])
|
||||
SETGET_STRUCT_CUSTOM(Projection, Vector4, z, columns[2])
|
||||
SETGET_STRUCT_CUSTOM(Projection, Vector4, w, columns[3])
|
||||
|
||||
SETGET_NUMBER_STRUCT(Color, double, r)
|
||||
SETGET_NUMBER_STRUCT(Color, double, g)
|
||||
SETGET_NUMBER_STRUCT(Color, double, b)
|
||||
SETGET_NUMBER_STRUCT(Color, double, a)
|
||||
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8)
|
||||
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v)
|
||||
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, double, ok_hsl_h, set_ok_hsl_h, get_ok_hsl_h)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, double, ok_hsl_s, set_ok_hsl_s, get_ok_hsl_s)
|
||||
SETGET_NUMBER_STRUCT_FUNC(Color, double, ok_hsl_l, set_ok_hsl_l, get_ok_hsl_l)
|
||||
1946
core/variant/variant_utility.cpp
Normal file
1946
core/variant/variant_utility.cpp
Normal file
File diff suppressed because it is too large
Load Diff
156
core/variant/variant_utility.h
Normal file
156
core/variant/variant_utility.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/**************************************************************************/
|
||||
/* variant_utility.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "variant.h"
|
||||
|
||||
struct VariantUtilityFunctions {
|
||||
// Math
|
||||
static double sin(double arg);
|
||||
static double cos(double arg);
|
||||
static double tan(double arg);
|
||||
static double sinh(double arg);
|
||||
static double cosh(double arg);
|
||||
static double tanh(double arg);
|
||||
static double asin(double arg);
|
||||
static double acos(double arg);
|
||||
static double atan(double arg);
|
||||
static double atan2(double y, double x);
|
||||
static double asinh(double arg);
|
||||
static double acosh(double arg);
|
||||
static double atanh(double arg);
|
||||
static double sqrt(double x);
|
||||
static double fmod(double b, double r);
|
||||
static double fposmod(double b, double r);
|
||||
static int64_t posmod(int64_t b, int64_t r);
|
||||
static Variant floor(const Variant &x, Callable::CallError &r_error);
|
||||
static double floorf(double x);
|
||||
static int64_t floori(double x);
|
||||
static Variant ceil(const Variant &x, Callable::CallError &r_error);
|
||||
static double ceilf(double x);
|
||||
static int64_t ceili(double x);
|
||||
static Variant round(const Variant &x, Callable::CallError &r_error);
|
||||
static double roundf(double x);
|
||||
static int64_t roundi(double x);
|
||||
static Variant abs(const Variant &x, Callable::CallError &r_error);
|
||||
static double absf(double x);
|
||||
static int64_t absi(int64_t x);
|
||||
static Variant sign(const Variant &x, Callable::CallError &r_error);
|
||||
static double signf(double x);
|
||||
static int64_t signi(int64_t x);
|
||||
static double pow(double x, double y);
|
||||
static double log(double x);
|
||||
static double exp(double x);
|
||||
static bool is_nan(double x);
|
||||
static bool is_inf(double x);
|
||||
static bool is_equal_approx(double x, double y);
|
||||
static bool is_zero_approx(double x);
|
||||
static bool is_finite(double x);
|
||||
static double ease(float x, float curve);
|
||||
static int step_decimals(float step);
|
||||
static Variant snapped(const Variant &x, const Variant &step, Callable::CallError &r_error);
|
||||
static double snappedf(double x, double step);
|
||||
static int64_t snappedi(double x, int64_t step);
|
||||
static Variant lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error);
|
||||
static double lerpf(double from, double to, double weight);
|
||||
static double cubic_interpolate(double from, double to, double pre, double post, double weight);
|
||||
static double cubic_interpolate_angle(double from, double to, double pre, double post, double weight);
|
||||
static double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
|
||||
double to_t, double pre_t, double post_t);
|
||||
static double cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
|
||||
double to_t, double pre_t, double post_t);
|
||||
static double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t);
|
||||
static double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t);
|
||||
static double angle_difference(double from, double to);
|
||||
static double lerp_angle(double from, double to, double weight);
|
||||
static double inverse_lerp(double from, double to, double weight);
|
||||
static double remap(double value, double istart, double istop, double ostart, double ostop);
|
||||
static double smoothstep(double from, double to, double val);
|
||||
static double move_toward(double from, double to, double delta);
|
||||
static double rotate_toward(double from, double to, double delta);
|
||||
static double deg_to_rad(double angle_deg);
|
||||
static double rad_to_deg(double angle_rad);
|
||||
static double linear_to_db(double linear);
|
||||
static double db_to_linear(double db);
|
||||
static Variant wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error);
|
||||
static int64_t wrapi(int64_t value, int64_t min, int64_t max);
|
||||
static double wrapf(double value, double min, double max);
|
||||
static double pingpong(double value, double length);
|
||||
static Variant max(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
static double maxf(double x, double y);
|
||||
static int64_t maxi(int64_t x, int64_t y);
|
||||
static Variant min(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
static double minf(double x, double y);
|
||||
static int64_t mini(int64_t x, int64_t y);
|
||||
static Variant clamp(const Variant &x, const Variant &min, const Variant &max, Callable::CallError &r_error);
|
||||
static double clampf(double x, double min, double max);
|
||||
static int64_t clampi(int64_t x, int64_t min, int64_t max);
|
||||
static int64_t nearest_po2(int64_t x);
|
||||
// Random
|
||||
static void randomize();
|
||||
static int64_t randi();
|
||||
static double randf();
|
||||
static double randfn(double mean, double deviation);
|
||||
static int64_t randi_range(int64_t from, int64_t to);
|
||||
static double randf_range(double from, double to);
|
||||
static void seed(int64_t s);
|
||||
static PackedInt64Array rand_from_seed(int64_t seed);
|
||||
// Utility
|
||||
static Variant weakref(const Variant &obj, Callable::CallError &r_error);
|
||||
static int64_t _typeof(const Variant &obj);
|
||||
static Variant type_convert(const Variant &p_variant, const Variant::Type p_type);
|
||||
static String str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static String error_string(Error error);
|
||||
static String type_string(Variant::Type p_type);
|
||||
static void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void _print_verbose(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void push_error(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static void push_warning(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
|
||||
static String var_to_str(const Variant &p_var);
|
||||
static Variant str_to_var(const String &p_var);
|
||||
static PackedByteArray var_to_bytes(const Variant &p_var);
|
||||
static PackedByteArray var_to_bytes_with_objects(const Variant &p_var);
|
||||
static Variant bytes_to_var(const PackedByteArray &p_arr);
|
||||
static Variant bytes_to_var_with_objects(const PackedByteArray &p_arr);
|
||||
static int64_t hash(const Variant &p_arr);
|
||||
static Object *instance_from_id(int64_t p_id);
|
||||
static bool is_instance_id_valid(int64_t p_id);
|
||||
static bool is_instance_valid(const Variant &p_instance);
|
||||
static uint64_t rid_allocate_id();
|
||||
static RID rid_from_int64(uint64_t p_base);
|
||||
static bool is_same(const Variant &p_a, const Variant &p_b);
|
||||
static String join_string(const Variant **p_args, int p_arg_count);
|
||||
};
|
||||
Reference in New Issue
Block a user