feat: godot-engine-source-4.3-stable
This commit is contained in:
parent
c59a7dcade
commit
7125d019b5
11149 changed files with 5070401 additions and 0 deletions
7
engine/core/variant/SCsub
Normal file
7
engine/core/variant/SCsub
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
|
||||
env_variant = env.Clone()
|
||||
|
||||
env_variant.add_source_files(env.core_sources, "*.cpp")
|
||||
840
engine/core/variant/array.cpp
Normal file
840
engine/core/variant/array.cpp
Normal file
|
|
@ -0,0 +1,840 @@
|
|||
/**************************************************************************/
|
||||
/* 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/class_db.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/templates/hashfuncs.h"
|
||||
#include "core/templates/search_array.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "core/variant/callable.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class ArrayPrivate {
|
||||
public:
|
||||
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;
|
||||
};
|
||||
|
||||
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(), _p->read_only);
|
||||
}
|
||||
|
||||
Array::ConstIterator Array::end() const {
|
||||
return ConstIterator(_p->array.ptr() + _p->array.size(), _p->read_only);
|
||||
}
|
||||
|
||||
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 {
|
||||
if (unlikely(_p->read_only)) {
|
||||
*_p->read_only = _p->array[p_idx];
|
||||
return *_p->read_only;
|
||||
}
|
||||
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(value);
|
||||
}
|
||||
|
||||
void Array::append_array(const Array &p_array) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
|
||||
Vector<Variant> validated_array = p_array._p->array;
|
||||
for (int i = 0; i < validated_array.size(); ++i) {
|
||||
ERR_FAIL_COND(!_p->typed.validate(validated_array.write[i], "append_array"));
|
||||
}
|
||||
|
||||
_p->array.append_array(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_zeroed(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);
|
||||
return _p->array.insert(p_pos, value);
|
||||
}
|
||||
|
||||
void Array::fill(const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND(!_p->typed.validate(value, "fill"));
|
||||
_p->array.fill(value);
|
||||
}
|
||||
|
||||
void Array::erase(const Variant &p_value) {
|
||||
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
|
||||
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.size() == 0) {
|
||||
return -1;
|
||||
}
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "find"), -1);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = p_from; i < size(); i++) {
|
||||
if (StringLikeVariantComparator::compare(_p->array[i], value)) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Array::rfind(const Variant &p_value, int p_from) const {
|
||||
if (_p->array.size() == 0) {
|
||||
return -1;
|
||||
}
|
||||
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::count(const Variant &p_value) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0);
|
||||
if (_p->array.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amount = 0;
|
||||
for (int i = 0; i < _p->array.size(); i++) {
|
||||
if (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.");
|
||||
_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"));
|
||||
|
||||
operator[](p_idx) = 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, 0);
|
||||
}
|
||||
|
||||
Array Array::recursive_duplicate(bool p_deep, 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) {
|
||||
recursion_count++;
|
||||
int element_count = size();
|
||||
new_arr.resize(element_count);
|
||||
for (int i = 0; i < element_count; i++) {
|
||||
new_arr[i] = get(i).recursive_duplicate(true, recursion_count);
|
||||
}
|
||||
} 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);
|
||||
|
||||
for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
|
||||
result[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];
|
||||
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(), "Error calling method from 'filter': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
|
||||
}
|
||||
|
||||
if (result.operator bool()) {
|
||||
new_arr[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];
|
||||
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(), "Error calling method from 'map': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
|
||||
}
|
||||
|
||||
new_arr[i] = result;
|
||||
}
|
||||
|
||||
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(), "Error calling method from 'reduce': " + 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, "Error calling method from 'any': " + 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, "Error calling method from 'all': " + 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);
|
||||
const Variant tmp = data[j];
|
||||
data[j] = data[i];
|
||||
data[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
SearchArray<Variant, _ArrayVariantSort> avs;
|
||||
return avs.bisect(_p->array.ptrw(), _p->array.size(), value, p_before);
|
||||
}
|
||||
|
||||
int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) 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, 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 {
|
||||
Variant minval;
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (i == 0) {
|
||||
minval = get(i);
|
||||
} else {
|
||||
bool valid;
|
||||
Variant ret;
|
||||
Variant test = get(i);
|
||||
Variant::evaluate(Variant::OP_LESS, test, minval, ret, valid);
|
||||
if (!valid) {
|
||||
return Variant(); //not a valid comparison
|
||||
}
|
||||
if (bool(ret)) {
|
||||
//is less
|
||||
minval = test;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minval;
|
||||
}
|
||||
|
||||
Variant Array::max() const {
|
||||
Variant maxval;
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (i == 0) {
|
||||
maxval = get(i);
|
||||
} else {
|
||||
bool valid;
|
||||
Variant ret;
|
||||
Variant test = get(i);
|
||||
Variant::evaluate(Variant::OP_GREATER, test, maxval, ret, valid);
|
||||
if (!valid) {
|
||||
return Variant(); //not a valid comparison
|
||||
}
|
||||
if (bool(ret)) {
|
||||
//is less
|
||||
maxval = test;
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxval;
|
||||
}
|
||||
|
||||
const void *Array::id() const {
|
||||
return _p;
|
||||
}
|
||||
|
||||
Array::Array(const Array &p_from, 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(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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
_p = memnew(ArrayPrivate);
|
||||
_p->refcount.init();
|
||||
}
|
||||
|
||||
Array::~Array() {
|
||||
_unref();
|
||||
}
|
||||
202
engine/core/variant/array.h
Normal file
202
engine/core/variant/array.h
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
class Variant;
|
||||
class ArrayPrivate;
|
||||
class Object;
|
||||
class StringName;
|
||||
class Callable;
|
||||
|
||||
class Array {
|
||||
mutable ArrayPrivate *_p;
|
||||
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, Variant *p_read_only = nullptr) :
|
||||
element_ptr(p_element_ptr), read_only(p_read_only) {}
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_other) :
|
||||
element_ptr(p_other.element_ptr), read_only(p_other.read_only) {}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator &operator=(const ConstIterator &p_other) {
|
||||
element_ptr = p_other.element_ptr;
|
||||
read_only = p_other.read_only;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const Variant *element_ptr = nullptr;
|
||||
Variant *read_only = 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, read_only);
|
||||
}
|
||||
|
||||
private:
|
||||
Variant *element_ptr = nullptr;
|
||||
Variant *read_only = nullptr;
|
||||
};
|
||||
|
||||
Iterator begin();
|
||||
Iterator end();
|
||||
|
||||
ConstIterator begin() const;
|
||||
ConstIterator end() const;
|
||||
|
||||
void _ref(const Array &p_from) 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 rfind(const Variant &p_value, 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 recursive_duplicate(bool p_deep, 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(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;
|
||||
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;
|
||||
|
||||
Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
|
||||
Array(const Array &p_from);
|
||||
Array();
|
||||
~Array();
|
||||
};
|
||||
|
||||
#endif // ARRAY_H
|
||||
1030
engine/core/variant/binder_common.h
Normal file
1030
engine/core/variant/binder_common.h
Normal file
File diff suppressed because it is too large
Load diff
584
engine/core/variant/callable.cpp
Normal file
584
engine/core/variant/callable.cpp
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
/**************************************************************************/
|
||||
/* 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;
|
||||
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_null()) {
|
||||
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, int &r_argcount) const {
|
||||
if (!is_null() && is_custom()) {
|
||||
custom->get_bound_arguments(r_arguments, r_argcount);
|
||||
} else {
|
||||
r_arguments.clear();
|
||||
r_argcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Array Callable::get_bound_arguments() const {
|
||||
Vector<Variant> arr;
|
||||
int ac;
|
||||
get_bound_arguments_ref(arr, ac);
|
||||
Array ret;
|
||||
ret.resize(arr.size());
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
ret[i] = arr[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (is_custom()) {
|
||||
if (p_callable.is_custom()) {
|
||||
if (custom == p_callable.custom) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (custom->ref_count.unref()) {
|
||||
memdelete(custom);
|
||||
custom = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_callable.is_custom()) {
|
||||
method = StringName();
|
||||
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::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() && 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, int &r_argcount) const {
|
||||
r_arguments = Vector<Variant>();
|
||||
r_argcount = 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
208
engine/core/variant/callable.h
Normal file
208
engine/core/variant/callable.h
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CALLABLE_H
|
||||
#define CALLABLE_H
|
||||
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/list.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, int &r_argcount) const; // Internal engine use, the exposed one is below.
|
||||
Array get_bound_arguments() 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);
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
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, int &r_argcount) 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;
|
||||
|
||||
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;
|
||||
|
||||
Array get_connections() const;
|
||||
Signal(const Object *p_object, const StringName &p_name);
|
||||
Signal(ObjectID p_object, const StringName &p_name);
|
||||
Signal() {}
|
||||
};
|
||||
|
||||
struct CallableComparator {
|
||||
const Callable &func;
|
||||
|
||||
bool operator()(const Variant &p_l, const Variant &p_r) const;
|
||||
};
|
||||
|
||||
#endif // CALLABLE_H
|
||||
287
engine/core/variant/callable_bind.cpp
Normal file
287
engine/core/variant/callable_bind.cpp
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/**************************************************************************/
|
||||
/* 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() + binds.size();
|
||||
}
|
||||
|
||||
void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
|
||||
Vector<Variant> sub_args;
|
||||
int sub_count;
|
||||
callable.get_bound_arguments_ref(sub_args, sub_count);
|
||||
|
||||
if (sub_count == 0) {
|
||||
r_arguments = binds;
|
||||
r_argcount = binds.size();
|
||||
return;
|
||||
}
|
||||
|
||||
int new_count = sub_count + binds.size();
|
||||
r_argcount = new_count;
|
||||
|
||||
if (new_count <= 0) {
|
||||
// Removed more arguments than it adds.
|
||||
r_arguments = Vector<Variant>();
|
||||
return;
|
||||
}
|
||||
|
||||
r_arguments.resize(new_count);
|
||||
|
||||
if (sub_count > 0) {
|
||||
for (int i = 0; i < sub_count; i++) {
|
||||
r_arguments.write[i] = sub_args[i];
|
||||
}
|
||||
for (int i = 0; i < binds.size(); i++) {
|
||||
r_arguments.write[i + sub_count] = binds[i];
|
||||
}
|
||||
r_argcount = new_count;
|
||||
} else {
|
||||
for (int i = 0; i < binds.size() + sub_count; i++) {
|
||||
r_arguments.write[i] = binds[i - sub_count];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() - argcount;
|
||||
}
|
||||
|
||||
void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
|
||||
Vector<Variant> sub_args;
|
||||
int sub_count;
|
||||
callable.get_bound_arguments_ref(sub_args, sub_count);
|
||||
|
||||
r_argcount = sub_args.size() - argcount;
|
||||
|
||||
if (argcount >= sub_args.size()) {
|
||||
r_arguments = Vector<Variant>();
|
||||
} else {
|
||||
sub_args.resize(sub_args.size() - argcount);
|
||||
r_arguments = sub_args;
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
}
|
||||
96
engine/core/variant/callable_bind.h
Normal file
96
engine/core/variant/callable_bind.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CALLABLE_BIND_H
|
||||
#define CALLABLE_BIND_H
|
||||
|
||||
#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, int &r_argcount) 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, int &r_argcount) const override;
|
||||
|
||||
Callable get_callable() { return callable; }
|
||||
int get_unbinds() { return argcount; }
|
||||
|
||||
CallableCustomUnbind(const Callable &p_callable, int p_argcount);
|
||||
virtual ~CallableCustomUnbind();
|
||||
};
|
||||
|
||||
#endif // CALLABLE_BIND_H
|
||||
146
engine/core/variant/container_type_validate.h
Normal file
146
engine/core/variant/container_type_validate.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CONTAINER_TYPE_VALIDATE_H
|
||||
#define CONTAINER_TYPE_VALIDATE_H
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
struct ContainerTypeValidate {
|
||||
Variant::Type type = Variant::NIL;
|
||||
StringName class_name;
|
||||
Ref<Script> script;
|
||||
const char *where = "container";
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
// Coerces String and StringName into each other and int into float when needed.
|
||||
_FORCE_INLINE_ bool validate(Variant &inout_variant, const char *p_operation = "use") 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;
|
||||
}
|
||||
|
||||
ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(inout_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
|
||||
}
|
||||
|
||||
if (type != Variant::OBJECT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return validate_object(inout_variant, p_operation);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool validate_object(const Variant &p_variant, const char *p_operation = "use") 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);
|
||||
ERR_FAIL_NULL_V_MSG(object, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
|
||||
#else
|
||||
Object *object = p_variant;
|
||||
if (object == nullptr) {
|
||||
return true; //fine
|
||||
}
|
||||
#endif
|
||||
if (class_name == StringName()) {
|
||||
return true; // All good, no class type requested.
|
||||
}
|
||||
|
||||
StringName obj_class = object->get_class_name();
|
||||
if (obj_class != class_name) {
|
||||
ERR_FAIL_COND_V_MSG(!ClassDB::is_parent_class(object->get_class_name(), class_name), false, "Attempted to " + String(p_operation) + " an object of type '" + object->get_class() + "' into a " + where + ", which does not inherit from '" + String(class_name) + "'.");
|
||||
}
|
||||
|
||||
if (script.is_null()) {
|
||||
return true; // All good, no script requested.
|
||||
}
|
||||
|
||||
Ref<Script> other_script = object->get_script();
|
||||
|
||||
// Check base script..
|
||||
ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
|
||||
ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONTAINER_TYPE_VALIDATE_H
|
||||
413
engine/core/variant/dictionary.cpp
Normal file
413
engine/core/variant/dictionary.cpp
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
/**************************************************************************/
|
||||
/* 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/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;
|
||||
};
|
||||
|
||||
void Dictionary::get_key_list(List<Variant> *p_keys) const {
|
||||
if (_p->variant_map.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
p_keys->push_back(E.key);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Variant &Dictionary::operator[](const Variant &p_key) {
|
||||
if (unlikely(_p->read_only)) {
|
||||
if (p_key.get_type() == Variant::STRING_NAME) {
|
||||
const StringName *sn = VariantInternal::get_string_name(&p_key);
|
||||
const String &key = sn->operator String();
|
||||
if (likely(_p->variant_map.has(key))) {
|
||||
*_p->read_only = _p->variant_map[key];
|
||||
} else {
|
||||
*_p->read_only = Variant();
|
||||
}
|
||||
} else if (likely(_p->variant_map.has(p_key))) {
|
||||
*_p->read_only = _p->variant_map[p_key];
|
||||
} else {
|
||||
*_p->read_only = Variant();
|
||||
}
|
||||
|
||||
return *_p->read_only;
|
||||
} else {
|
||||
if (p_key.get_type() == Variant::STRING_NAME) {
|
||||
const StringName *sn = VariantInternal::get_string_name(&p_key);
|
||||
return _p->variant_map[sn->operator String()];
|
||||
} else {
|
||||
return _p->variant_map[p_key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Variant &Dictionary::operator[](const Variant &p_key) const {
|
||||
// Will not insert key, so no conversion is necessary.
|
||||
return _p->variant_map[p_key];
|
||||
}
|
||||
|
||||
const Variant *Dictionary::getptr(const Variant &p_key) const {
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(p_key));
|
||||
if (!E) {
|
||||
return nullptr;
|
||||
}
|
||||
return &E->value;
|
||||
}
|
||||
|
||||
Variant *Dictionary::getptr(const Variant &p_key) {
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E(_p->variant_map.find(p_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 {
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(p_key));
|
||||
|
||||
if (!E) {
|
||||
return Variant();
|
||||
}
|
||||
return E->value;
|
||||
}
|
||||
|
||||
Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const {
|
||||
const Variant *result = getptr(p_key);
|
||||
if (!result) {
|
||||
return p_default;
|
||||
}
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
Variant Dictionary::get_or_add(const Variant &p_key, const Variant &p_default) {
|
||||
const Variant *result = getptr(p_key);
|
||||
if (!result) {
|
||||
operator[](p_key) = p_default;
|
||||
return p_default;
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
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 {
|
||||
return _p->variant_map.has(p_key);
|
||||
}
|
||||
|
||||
bool Dictionary::has_all(const Array &p_keys) const {
|
||||
for (int i = 0; i < p_keys.size(); i++) {
|
||||
if (!has(p_keys[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Variant Dictionary::find_key(const Variant &p_value) const {
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
if (E.value == p_value) {
|
||||
return E.key;
|
||||
}
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool Dictionary::erase(const Variant &p_key) {
|
||||
ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
|
||||
return _p->variant_map.erase(p_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();
|
||||
}
|
||||
|
||||
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) {
|
||||
if (p_overwrite || !has(E.key)) {
|
||||
operator[](E.key) = E.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);
|
||||
}
|
||||
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 (_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 (_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E = _p->variant_map.find(*p_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, 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, int recursion_count) const {
|
||||
Dictionary n;
|
||||
|
||||
if (recursion_count > MAX_RECURSION) {
|
||||
ERR_PRINT("Max recursion reached");
|
||||
return n;
|
||||
}
|
||||
|
||||
if (p_deep) {
|
||||
recursion_count++;
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
n[E.key.recursive_duplicate(true, recursion_count)] = E.value.recursive_duplicate(true, recursion_count);
|
||||
}
|
||||
} else {
|
||||
for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
|
||||
n[E.key] = E.value;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
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_from) {
|
||||
_p = nullptr;
|
||||
_ref(p_from);
|
||||
}
|
||||
|
||||
Dictionary::Dictionary() {
|
||||
_p = memnew(DictionaryPrivate);
|
||||
_p->refcount.init();
|
||||
}
|
||||
|
||||
Dictionary::~Dictionary() {
|
||||
_unref();
|
||||
}
|
||||
101
engine/core/variant/dictionary.h
Normal file
101
engine/core/variant/dictionary.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/variant/array.h"
|
||||
|
||||
class Variant;
|
||||
|
||||
struct DictionaryPrivate;
|
||||
|
||||
class Dictionary {
|
||||
mutable DictionaryPrivate *_p;
|
||||
|
||||
void _ref(const Dictionary &p_from) const;
|
||||
void _unref() const;
|
||||
|
||||
public:
|
||||
void get_key_list(List<Variant> *p_keys) const;
|
||||
Variant get_key_at_index(int p_index) const;
|
||||
Variant get_value_at_index(int p_index) const;
|
||||
|
||||
Variant &operator[](const Variant &p_key);
|
||||
const Variant &operator[](const Variant &p_key) const;
|
||||
|
||||
const Variant *getptr(const Variant &p_key) const;
|
||||
Variant *getptr(const Variant &p_key);
|
||||
|
||||
Variant get_valid(const Variant &p_key) const;
|
||||
Variant get(const Variant &p_key, const Variant &p_default) const;
|
||||
Variant get_or_add(const Variant &p_key, const Variant &p_default);
|
||||
|
||||
int size() const;
|
||||
bool is_empty() const;
|
||||
void clear();
|
||||
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);
|
||||
|
||||
const Variant *next(const Variant *p_key = nullptr) const;
|
||||
|
||||
Array keys() const;
|
||||
Array values() const;
|
||||
|
||||
Dictionary duplicate(bool p_deep = false) const;
|
||||
Dictionary recursive_duplicate(bool p_deep, int recursion_count) const;
|
||||
|
||||
void make_read_only();
|
||||
bool is_read_only() const;
|
||||
|
||||
const void *id() const;
|
||||
|
||||
Dictionary(const Dictionary &p_from);
|
||||
Dictionary();
|
||||
~Dictionary();
|
||||
};
|
||||
|
||||
#endif // DICTIONARY_H
|
||||
462
engine/core/variant/method_ptrcall.h
Normal file
462
engine/core/variant/method_ptrcall.h
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef METHOD_PTRCALL_H
|
||||
#define METHOD_PTRCALL_H
|
||||
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg {};
|
||||
|
||||
#define MAKE_PTRARG(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*((m_type *)p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*((m_type *)p_ptr) = p_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAKE_PTRARGCONV(m_type, m_conv) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
||||
} \
|
||||
typedef m_conv EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
||||
} \
|
||||
typedef m_conv EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
||||
*((m_type *)p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
||||
*((m_type *)p_ptr) = p_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_PTRARGCONV(bool, uint8_t);
|
||||
// Integer types.
|
||||
MAKE_PTRARGCONV(uint8_t, int64_t);
|
||||
MAKE_PTRARGCONV(int8_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint16_t, int64_t);
|
||||
MAKE_PTRARGCONV(int16_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint32_t, int64_t);
|
||||
MAKE_PTRARGCONV(int32_t, int64_t);
|
||||
MAKE_PTRARG(int64_t);
|
||||
MAKE_PTRARG(uint64_t);
|
||||
// Float types
|
||||
MAKE_PTRARGCONV(float, double);
|
||||
MAKE_PTRARG(double);
|
||||
|
||||
MAKE_PTRARG(String);
|
||||
MAKE_PTRARG(Vector2);
|
||||
MAKE_PTRARG(Vector2i);
|
||||
MAKE_PTRARG(Rect2);
|
||||
MAKE_PTRARG(Rect2i);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector3);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector3i);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector4);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector4i);
|
||||
MAKE_PTRARG(Transform2D);
|
||||
MAKE_PTRARG(Projection);
|
||||
MAKE_PTRARG_BY_REFERENCE(Plane);
|
||||
MAKE_PTRARG(Quaternion);
|
||||
MAKE_PTRARG_BY_REFERENCE(AABB);
|
||||
MAKE_PTRARG_BY_REFERENCE(Basis);
|
||||
MAKE_PTRARG_BY_REFERENCE(Transform3D);
|
||||
MAKE_PTRARG_BY_REFERENCE(Color);
|
||||
MAKE_PTRARG(StringName);
|
||||
MAKE_PTRARG(NodePath);
|
||||
MAKE_PTRARG(RID);
|
||||
// Object doesn't need this.
|
||||
MAKE_PTRARG(Callable);
|
||||
MAKE_PTRARG(Signal);
|
||||
MAKE_PTRARG(Dictionary);
|
||||
MAKE_PTRARG(Array);
|
||||
MAKE_PTRARG(PackedByteArray);
|
||||
MAKE_PTRARG(PackedInt32Array);
|
||||
MAKE_PTRARG(PackedInt64Array);
|
||||
MAKE_PTRARG(PackedFloat32Array);
|
||||
MAKE_PTRARG(PackedFloat64Array);
|
||||
MAKE_PTRARG(PackedStringArray);
|
||||
MAKE_PTRARG(PackedVector2Array);
|
||||
MAKE_PTRARG(PackedVector3Array);
|
||||
MAKE_PTRARG(PackedColorArray);
|
||||
MAKE_PTRARG(PackedVector4Array);
|
||||
MAKE_PTRARG_BY_REFERENCE(Variant);
|
||||
|
||||
// This is for Object.
|
||||
|
||||
template <typename T>
|
||||
struct PtrToArg<T *> {
|
||||
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
|
||||
return likely(p_ptr) ? const_cast<T *>(*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.
|
||||
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
#define MAKE_VECARG(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<Vector<m_type>> { \
|
||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
||||
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
|
||||
Vector<m_type> ret; \
|
||||
int len = dvs->size(); \
|
||||
ret.resize(len); \
|
||||
{ \
|
||||
const m_type *r = dvs->ptr(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
ret.write[i] = r[i]; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
_FORCE_INLINE_ static void encode(const Vector<m_type> &p_vec, void *p_ptr) { \
|
||||
Vector<m_type> *dv = reinterpret_cast<Vector<m_type> *>(p_ptr); \
|
||||
int len = p_vec.size(); \
|
||||
dv->resize(len); \
|
||||
{ \
|
||||
m_type *w = dv->ptrw(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
w[i] = p_vec[i]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const Vector<m_type> &> { \
|
||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
||||
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
|
||||
Vector<m_type> ret; \
|
||||
int len = dvs->size(); \
|
||||
ret.resize(len); \
|
||||
{ \
|
||||
const m_type *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.
|
||||
#define MAKE_VECARG_ALT(m_type, m_type_alt) \
|
||||
template <> \
|
||||
struct PtrToArg<Vector<m_type_alt>> { \
|
||||
_FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
|
||||
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
|
||||
Vector<m_type_alt> ret; \
|
||||
int len = dvs->size(); \
|
||||
ret.resize(len); \
|
||||
{ \
|
||||
const m_type *r = dvs->ptr(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
ret.write[i] = r[i]; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
_FORCE_INLINE_ static void encode(const Vector<m_type_alt> &p_vec, void *p_ptr) { \
|
||||
Vector<m_type> *dv = reinterpret_cast<Vector<m_type> *>(p_ptr); \
|
||||
int len = p_vec.size(); \
|
||||
dv->resize(len); \
|
||||
{ \
|
||||
m_type *w = dv->ptrw(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
w[i] = p_vec[i]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const Vector<m_type_alt> &> { \
|
||||
_FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
|
||||
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
|
||||
Vector<m_type_alt> ret; \
|
||||
int len = dvs->size(); \
|
||||
ret.resize(len); \
|
||||
{ \
|
||||
const m_type *r = dvs->ptr(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
ret.write[i] = r[i]; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_VECARG_ALT(String, StringName);
|
||||
|
||||
// For stuff that gets converted to Array vectors.
|
||||
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
#define MAKE_VECARR(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<Vector<m_type>> { \
|
||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
|
||||
Vector<m_type> ret; \
|
||||
int len = arr->size(); \
|
||||
ret.resize(len); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
ret.write[i] = (*arr)[i]; \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
_FORCE_INLINE_ static void encode(const Vector<m_type> &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 <> \
|
||||
struct PtrToArg<const Vector<m_type> &> { \
|
||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
|
||||
Vector<m_type> ret; \
|
||||
int len = arr->size(); \
|
||||
ret.resize(len); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
ret.write[i] = (*arr)[i]; \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_VECARR(Variant);
|
||||
MAKE_VECARR(RID);
|
||||
MAKE_VECARR(Plane);
|
||||
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
#define MAKE_DVECARR(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<Vector<m_type>> { \
|
||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
|
||||
Vector<m_type> ret; \
|
||||
int len = arr->size(); \
|
||||
ret.resize(len); \
|
||||
{ \
|
||||
m_type *w = ret.ptrw(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
w[i] = (*arr)[i]; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
_FORCE_INLINE_ static void encode(const Vector<m_type> &p_vec, void *p_ptr) { \
|
||||
Array *arr = reinterpret_cast<Array *>(p_ptr); \
|
||||
int len = p_vec.size(); \
|
||||
arr->resize(len); \
|
||||
{ \
|
||||
const m_type *r = p_vec.ptr(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
(*arr)[i] = r[i]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const Vector<m_type> &> { \
|
||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
|
||||
Vector<m_type> ret; \
|
||||
int len = arr->size(); \
|
||||
ret.resize(len); \
|
||||
{ \
|
||||
m_type *w = ret.ptrw(); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
w[i] = (*arr)[i]; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Special case for IPAddress.
|
||||
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
m_type s = *reinterpret_cast<const String *>(p_ptr); \
|
||||
return s; \
|
||||
} \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_vec, void *p_ptr) { \
|
||||
String *arr = reinterpret_cast<String *>(p_ptr); \
|
||||
*arr = p_vec; \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
m_type s = *reinterpret_cast<const String *>(p_ptr); \
|
||||
return s; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_STRINGCONV_BY_REFERENCE(IPAddress);
|
||||
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
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;
|
||||
}
|
||||
_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];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// No EncodeT because direct pointer conversion not possible.
|
||||
template <>
|
||||
struct PtrToArg<const 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;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // METHOD_PTRCALL_H
|
||||
156
engine/core/variant/native_ptr.h
Normal file
156
engine/core/variant/native_ptr.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef NATIVE_PTR_H
|
||||
#define NATIVE_PTR_H
|
||||
|
||||
#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::NIL;
|
||||
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::NIL;
|
||||
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)
|
||||
|
||||
#endif // NATIVE_PTR_H
|
||||
339
engine/core/variant/type_info.h
Normal file
339
engine/core/variant/type_info.h
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TYPE_INFO_H
|
||||
#define TYPE_INFO_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
|
||||
};
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
#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()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const 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()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const 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(char16_t, Variant::INT)
|
||||
MAKE_TYPE_INFO(char32_t, Variant::INT)
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GetTypeInfo<const 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()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const 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 godot {
|
||||
namespace details {
|
||||
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 details
|
||||
} // namespace godot
|
||||
|
||||
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_impl> { \
|
||||
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, \
|
||||
godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_ENUM_TYPE_INFO(m_enum) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
|
||||
|
||||
template <typename T>
|
||||
inline StringName __constant_get_enum_name(T param, const String &p_constant) {
|
||||
if constexpr (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
|
||||
ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's enum: " + p_constant);
|
||||
}
|
||||
return GetTypeInfo<T>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class BitField {
|
||||
int64_t value = 0;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ BitField<T> &set_flag(T p_flag) {
|
||||
value |= (int64_t)p_flag;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & (int64_t)p_flag; }
|
||||
_FORCE_INLINE_ bool is_empty() const { return value == 0; }
|
||||
_FORCE_INLINE_ void clear_flag(T p_flag) { value &= ~(int64_t)p_flag; }
|
||||
_FORCE_INLINE_ void clear() { value = 0; }
|
||||
_FORCE_INLINE_ constexpr BitField() = default;
|
||||
_FORCE_INLINE_ constexpr BitField(int64_t p_value) { value = p_value; }
|
||||
_FORCE_INLINE_ constexpr BitField(T p_value) { value = (int64_t)p_value; }
|
||||
_FORCE_INLINE_ operator int64_t() const { return value; }
|
||||
_FORCE_INLINE_ operator Variant() const { return value; }
|
||||
_FORCE_INLINE_ BitField<T> operator^(const BitField<T> &p_b) const { return BitField<T>(value ^ p_b.value); }
|
||||
};
|
||||
|
||||
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_impl> { \
|
||||
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, \
|
||||
godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<BitField<m_impl>> { \
|
||||
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, \
|
||||
godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_BITFIELD_TYPE_INFO(m_enum) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
|
||||
|
||||
template <typename T>
|
||||
inline StringName __constant_get_bitfield_name(T param, const String &p_constant) {
|
||||
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
|
||||
ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's bitfield: " + p_constant);
|
||||
}
|
||||
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
|
||||
}
|
||||
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
|
||||
|
||||
template <typename T>
|
||||
struct ZeroInitializer {
|
||||
static void initialize(T &value) {} //no initialization by default
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ZeroInitializer<bool> {
|
||||
static void initialize(bool &value) { value = false; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ZeroInitializer<T *> {
|
||||
static void initialize(T *&value) { value = nullptr; }
|
||||
};
|
||||
|
||||
#define ZERO_INITIALIZER_NUMBER(m_type) \
|
||||
template <> \
|
||||
struct ZeroInitializer<m_type> { \
|
||||
static void initialize(m_type &value) { value = 0; } \
|
||||
};
|
||||
|
||||
ZERO_INITIALIZER_NUMBER(uint8_t)
|
||||
ZERO_INITIALIZER_NUMBER(int8_t)
|
||||
ZERO_INITIALIZER_NUMBER(uint16_t)
|
||||
ZERO_INITIALIZER_NUMBER(int16_t)
|
||||
ZERO_INITIALIZER_NUMBER(uint32_t)
|
||||
ZERO_INITIALIZER_NUMBER(int32_t)
|
||||
ZERO_INITIALIZER_NUMBER(uint64_t)
|
||||
ZERO_INITIALIZER_NUMBER(int64_t)
|
||||
ZERO_INITIALIZER_NUMBER(char16_t)
|
||||
ZERO_INITIALIZER_NUMBER(char32_t)
|
||||
ZERO_INITIALIZER_NUMBER(float)
|
||||
ZERO_INITIALIZER_NUMBER(double)
|
||||
|
||||
#endif // TYPE_INFO_H
|
||||
255
engine/core/variant/typed_array.h
Normal file
255
engine/core/variant/typed_array.h
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TYPED_ARRAY_H
|
||||
#define TYPED_ARRAY_H
|
||||
|
||||
#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.");
|
||||
_ref(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)) {
|
||||
_ref(p_array);
|
||||
} else {
|
||||
assign(p_array);
|
||||
}
|
||||
}
|
||||
_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."); \
|
||||
_ref(p_array); \
|
||||
} \
|
||||
_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)) { \
|
||||
_ref(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 PtrToArg<const TypedArray<T> &> {
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
|
||||
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const 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)); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const 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
|
||||
|
||||
#endif // TYPED_ARRAY_H
|
||||
3711
engine/core/variant/variant.cpp
Normal file
3711
engine/core/variant/variant.cpp
Normal file
File diff suppressed because it is too large
Load diff
941
engine/core/variant/variant.h
Normal file
941
engine/core/variant/variant.h
Normal file
|
|
@ -0,0 +1,941 @@
|
|||
/**************************************************************************/
|
||||
/* variant.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_H
|
||||
#define VARIANT_H
|
||||
|
||||
#include "core/core_string_names.h"
|
||||
#include "core/input/input_enums.h"
|
||||
#include "core/io/ip_address.h"
|
||||
#include "core/math/aabb.h"
|
||||
#include "core/math/basis.h"
|
||||
#include "core/math/color.h"
|
||||
#include "core/math/face3.h"
|
||||
#include "core/math/plane.h"
|
||||
#include "core/math/projection.h"
|
||||
#include "core/math/quaternion.h"
|
||||
#include "core/math/rect2.h"
|
||||
#include "core/math/rect2i.h"
|
||||
#include "core/math/transform_2d.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector2i.h"
|
||||
#include "core/math/vector3.h"
|
||||
#include "core/math/vector3i.h"
|
||||
#include "core/math/vector4.h"
|
||||
#include "core/math/vector4i.h"
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/string/node_path.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/paged_allocator.h"
|
||||
#include "core/templates/rid.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "core/variant/callable.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
|
||||
class Object;
|
||||
|
||||
struct PropertyInfo;
|
||||
struct MethodInfo;
|
||||
|
||||
typedef Vector<uint8_t> PackedByteArray;
|
||||
typedef Vector<int32_t> PackedInt32Array;
|
||||
typedef Vector<int64_t> PackedInt64Array;
|
||||
typedef Vector<float> PackedFloat32Array;
|
||||
typedef Vector<double> PackedFloat64Array;
|
||||
typedef Vector<real_t> PackedRealArray;
|
||||
typedef Vector<String> PackedStringArray;
|
||||
typedef Vector<Vector2> PackedVector2Array;
|
||||
typedef Vector<Vector3> PackedVector3Array;
|
||||
typedef Vector<Color> PackedColorArray;
|
||||
typedef Vector<Vector4> PackedVector4Array;
|
||||
|
||||
class Variant {
|
||||
public:
|
||||
// If this changes the table in variant_op must be updated
|
||||
enum Type {
|
||||
NIL,
|
||||
|
||||
// atomic types
|
||||
BOOL,
|
||||
INT,
|
||||
FLOAT,
|
||||
STRING,
|
||||
|
||||
// math types
|
||||
VECTOR2,
|
||||
VECTOR2I,
|
||||
RECT2,
|
||||
RECT2I,
|
||||
VECTOR3,
|
||||
VECTOR3I,
|
||||
TRANSFORM2D,
|
||||
VECTOR4,
|
||||
VECTOR4I,
|
||||
PLANE,
|
||||
QUATERNION,
|
||||
AABB,
|
||||
BASIS,
|
||||
TRANSFORM3D,
|
||||
PROJECTION,
|
||||
|
||||
// misc types
|
||||
COLOR,
|
||||
STRING_NAME,
|
||||
NODE_PATH,
|
||||
RID,
|
||||
OBJECT,
|
||||
CALLABLE,
|
||||
SIGNAL,
|
||||
DICTIONARY,
|
||||
ARRAY,
|
||||
|
||||
// typed arrays
|
||||
PACKED_BYTE_ARRAY,
|
||||
PACKED_INT32_ARRAY,
|
||||
PACKED_INT64_ARRAY,
|
||||
PACKED_FLOAT32_ARRAY,
|
||||
PACKED_FLOAT64_ARRAY,
|
||||
PACKED_STRING_ARRAY,
|
||||
PACKED_VECTOR2_ARRAY,
|
||||
PACKED_VECTOR3_ARRAY,
|
||||
PACKED_COLOR_ARRAY,
|
||||
PACKED_VECTOR4_ARRAY,
|
||||
|
||||
VARIANT_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
// Maximum recursion depth allowed when serializing variants.
|
||||
MAX_RECURSION_DEPTH = 1024,
|
||||
};
|
||||
|
||||
private:
|
||||
struct Pools {
|
||||
union BucketSmall {
|
||||
BucketSmall() {}
|
||||
~BucketSmall() {}
|
||||
Transform2D _transform2d;
|
||||
::AABB _aabb;
|
||||
};
|
||||
union BucketMedium {
|
||||
BucketMedium() {}
|
||||
~BucketMedium() {}
|
||||
Basis _basis;
|
||||
Transform3D _transform3d;
|
||||
};
|
||||
union BucketLarge {
|
||||
BucketLarge() {}
|
||||
~BucketLarge() {}
|
||||
Projection _projection;
|
||||
};
|
||||
|
||||
static PagedAllocator<BucketSmall, true> _bucket_small;
|
||||
static PagedAllocator<BucketMedium, true> _bucket_medium;
|
||||
static PagedAllocator<BucketLarge, true> _bucket_large;
|
||||
};
|
||||
|
||||
friend struct _VariantCall;
|
||||
friend class VariantInternal;
|
||||
// Variant takes 24 bytes when real_t is float, and 40 bytes if double.
|
||||
// It only allocates extra memory for AABB/Transform2D (24, 48 if double),
|
||||
// Basis/Transform3D (48, 96 if double), Projection (64, 128 if double),
|
||||
// and PackedArray/Array/Dictionary (platform-dependent).
|
||||
|
||||
Type type = NIL;
|
||||
|
||||
struct ObjData {
|
||||
ObjectID id;
|
||||
Object *obj = nullptr;
|
||||
};
|
||||
|
||||
/* array helpers */
|
||||
struct PackedArrayRefBase {
|
||||
SafeRefCount refcount;
|
||||
_FORCE_INLINE_ PackedArrayRefBase *reference() {
|
||||
if (refcount.ref()) {
|
||||
return this;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
static _FORCE_INLINE_ PackedArrayRefBase *reference_from(PackedArrayRefBase *p_base, PackedArrayRefBase *p_from) {
|
||||
if (p_base == p_from) {
|
||||
return p_base; //same thing, do nothing
|
||||
}
|
||||
|
||||
if (p_from->reference()) {
|
||||
if (p_base->refcount.unref()) {
|
||||
memdelete(p_base);
|
||||
}
|
||||
return p_from;
|
||||
} else {
|
||||
return p_base; //keep, could not reference new
|
||||
}
|
||||
}
|
||||
static _FORCE_INLINE_ void destroy(PackedArrayRefBase *p_array) {
|
||||
if (p_array->refcount.unref()) {
|
||||
memdelete(p_array);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ virtual ~PackedArrayRefBase() {} //needs virtual destructor, but make inline
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PackedArrayRef : public PackedArrayRefBase {
|
||||
Vector<T> array;
|
||||
static _FORCE_INLINE_ PackedArrayRef<T> *create() {
|
||||
return memnew(PackedArrayRef<T>);
|
||||
}
|
||||
static _FORCE_INLINE_ PackedArrayRef<T> *create(const Vector<T> &p_from) {
|
||||
return memnew(PackedArrayRef<T>(p_from));
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ const Vector<T> &get_array(PackedArrayRefBase *p_base) {
|
||||
return static_cast<PackedArrayRef<T> *>(p_base)->array;
|
||||
}
|
||||
static _FORCE_INLINE_ Vector<T> *get_array_ptr(const PackedArrayRefBase *p_base) {
|
||||
return &const_cast<PackedArrayRef<T> *>(static_cast<const PackedArrayRef<T> *>(p_base))->array;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ PackedArrayRef(const Vector<T> &p_from) {
|
||||
array = p_from;
|
||||
refcount.init();
|
||||
}
|
||||
_FORCE_INLINE_ PackedArrayRef() {
|
||||
refcount.init();
|
||||
}
|
||||
};
|
||||
|
||||
/* end of array helpers */
|
||||
_ALWAYS_INLINE_ ObjData &_get_obj();
|
||||
_ALWAYS_INLINE_ const ObjData &_get_obj() const;
|
||||
|
||||
union {
|
||||
bool _bool;
|
||||
int64_t _int;
|
||||
double _float;
|
||||
Transform2D *_transform2d;
|
||||
::AABB *_aabb;
|
||||
Basis *_basis;
|
||||
Transform3D *_transform3d;
|
||||
Projection *_projection;
|
||||
PackedArrayRefBase *packed_array;
|
||||
void *_ptr; //generic pointer
|
||||
uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]{ 0 };
|
||||
} _data alignas(8);
|
||||
|
||||
void reference(const Variant &p_variant);
|
||||
static bool initialize_ref(Object *p_object);
|
||||
|
||||
void _clear_internal();
|
||||
|
||||
_FORCE_INLINE_ void clear() {
|
||||
static const bool needs_deinit[Variant::VARIANT_MAX] = {
|
||||
false, //NIL,
|
||||
false, //BOOL,
|
||||
false, //INT,
|
||||
false, //FLOAT,
|
||||
true, //STRING,
|
||||
false, //VECTOR2,
|
||||
false, //VECTOR2I,
|
||||
false, //RECT2,
|
||||
false, //RECT2I,
|
||||
false, //VECTOR3,
|
||||
false, //VECTOR3I,
|
||||
true, //TRANSFORM2D,
|
||||
false, //VECTOR4,
|
||||
false, //VECTOR4I,
|
||||
false, //PLANE,
|
||||
false, //QUATERNION,
|
||||
true, //AABB,
|
||||
true, //BASIS,
|
||||
true, //TRANSFORM,
|
||||
true, //PROJECTION,
|
||||
|
||||
// misc types
|
||||
false, //COLOR,
|
||||
true, //STRING_NAME,
|
||||
true, //NODE_PATH,
|
||||
false, //RID,
|
||||
true, //OBJECT,
|
||||
true, //CALLABLE,
|
||||
true, //SIGNAL,
|
||||
true, //DICTIONARY,
|
||||
true, //ARRAY,
|
||||
|
||||
// typed arrays
|
||||
true, //PACKED_BYTE_ARRAY,
|
||||
true, //PACKED_INT32_ARRAY,
|
||||
true, //PACKED_INT64_ARRAY,
|
||||
true, //PACKED_FLOAT32_ARRAY,
|
||||
true, //PACKED_FLOAT64_ARRAY,
|
||||
true, //PACKED_STRING_ARRAY,
|
||||
true, //PACKED_VECTOR2_ARRAY,
|
||||
true, //PACKED_VECTOR3_ARRAY,
|
||||
true, //PACKED_COLOR_ARRAY,
|
||||
true, //PACKED_VECTOR4_ARRAY,
|
||||
};
|
||||
|
||||
if (unlikely(needs_deinit[type])) { // Make it fast for types that don't need deinit.
|
||||
_clear_internal();
|
||||
}
|
||||
type = NIL;
|
||||
}
|
||||
|
||||
static void _register_variant_operators();
|
||||
static void _unregister_variant_operators();
|
||||
static void _register_variant_methods();
|
||||
static void _unregister_variant_methods();
|
||||
static void _register_variant_setters_getters();
|
||||
static void _unregister_variant_setters_getters();
|
||||
static void _register_variant_constructors();
|
||||
static void _unregister_variant_destructors();
|
||||
static void _register_variant_destructors();
|
||||
static void _unregister_variant_constructors();
|
||||
static void _register_variant_utility_functions();
|
||||
static void _unregister_variant_utility_functions();
|
||||
|
||||
void _variant_call_error(const String &p_method, Callable::CallError &error);
|
||||
|
||||
// Avoid accidental conversion. If you reached this point, it's because you most likely forgot to dereference
|
||||
// a Variant pointer (so add * like this: *variant_pointer).
|
||||
|
||||
Variant(const Variant *) {}
|
||||
Variant(const Variant **) {}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ Type get_type() const {
|
||||
return type;
|
||||
}
|
||||
static String get_type_name(Variant::Type p_type);
|
||||
static bool can_convert(Type p_type_from, Type p_type_to);
|
||||
static bool can_convert_strict(Type p_type_from, Type p_type_to);
|
||||
static bool is_type_shared(Variant::Type p_type);
|
||||
|
||||
bool is_ref_counted() const;
|
||||
_FORCE_INLINE_ bool is_num() const {
|
||||
return type == INT || type == FLOAT;
|
||||
}
|
||||
_FORCE_INLINE_ bool is_string() const {
|
||||
return type == STRING || type == STRING_NAME;
|
||||
}
|
||||
_FORCE_INLINE_ bool is_array() const {
|
||||
return type >= ARRAY;
|
||||
}
|
||||
bool is_shared() const;
|
||||
bool is_zero() const;
|
||||
bool is_one() const;
|
||||
bool is_null() const;
|
||||
bool is_read_only() const;
|
||||
|
||||
// Make sure Variant is not implicitly cast when accessing it with bracket notation (GH-49469).
|
||||
Variant &operator[](const Variant &p_key) = delete;
|
||||
const Variant &operator[](const Variant &p_key) const = delete;
|
||||
|
||||
operator bool() const;
|
||||
operator int64_t() const;
|
||||
operator int32_t() const;
|
||||
operator int16_t() const;
|
||||
operator int8_t() const;
|
||||
operator uint64_t() const;
|
||||
operator uint32_t() const;
|
||||
operator uint16_t() const;
|
||||
operator uint8_t() const;
|
||||
|
||||
operator ObjectID() const;
|
||||
|
||||
operator char32_t() const;
|
||||
operator float() const;
|
||||
operator double() const;
|
||||
operator String() const;
|
||||
operator StringName() const;
|
||||
operator Vector2() const;
|
||||
operator Vector2i() const;
|
||||
operator Rect2() const;
|
||||
operator Rect2i() const;
|
||||
operator Vector3() const;
|
||||
operator Vector3i() const;
|
||||
operator Vector4() const;
|
||||
operator Vector4i() const;
|
||||
operator Plane() const;
|
||||
operator ::AABB() const;
|
||||
operator Quaternion() const;
|
||||
operator Basis() const;
|
||||
operator Transform2D() const;
|
||||
operator Transform3D() const;
|
||||
operator Projection() const;
|
||||
|
||||
operator Color() const;
|
||||
operator NodePath() const;
|
||||
operator ::RID() const;
|
||||
|
||||
operator Object *() const;
|
||||
|
||||
operator Callable() const;
|
||||
operator Signal() const;
|
||||
|
||||
operator Dictionary() const;
|
||||
operator Array() const;
|
||||
|
||||
operator PackedByteArray() const;
|
||||
operator PackedInt32Array() const;
|
||||
operator PackedInt64Array() const;
|
||||
operator PackedFloat32Array() const;
|
||||
operator PackedFloat64Array() const;
|
||||
operator PackedStringArray() const;
|
||||
operator PackedVector3Array() const;
|
||||
operator PackedVector2Array() const;
|
||||
operator PackedColorArray() const;
|
||||
operator PackedVector4Array() const;
|
||||
|
||||
operator Vector<::RID>() const;
|
||||
operator Vector<Plane>() const;
|
||||
operator Vector<Face3>() const;
|
||||
operator Vector<Variant>() const;
|
||||
operator Vector<StringName>() const;
|
||||
|
||||
// some core type enums to convert to
|
||||
operator Side() const;
|
||||
operator Orientation() const;
|
||||
|
||||
operator IPAddress() const;
|
||||
|
||||
Object *get_validated_object() const;
|
||||
Object *get_validated_object_with_check(bool &r_previously_freed) const;
|
||||
|
||||
Variant(bool p_bool);
|
||||
Variant(int64_t p_int64);
|
||||
Variant(int32_t p_int32);
|
||||
Variant(int16_t p_int16);
|
||||
Variant(int8_t p_int8);
|
||||
Variant(uint64_t p_uint64);
|
||||
Variant(uint32_t p_uint32);
|
||||
Variant(uint16_t p_uint16);
|
||||
Variant(uint8_t p_uint8);
|
||||
Variant(float p_float);
|
||||
Variant(double p_double);
|
||||
Variant(const ObjectID &p_id);
|
||||
Variant(const String &p_string);
|
||||
Variant(const StringName &p_string);
|
||||
Variant(const char *const p_cstring);
|
||||
Variant(const char32_t *p_wstring);
|
||||
Variant(const Vector2 &p_vector2);
|
||||
Variant(const Vector2i &p_vector2i);
|
||||
Variant(const Rect2 &p_rect2);
|
||||
Variant(const Rect2i &p_rect2i);
|
||||
Variant(const Vector3 &p_vector3);
|
||||
Variant(const Vector3i &p_vector3i);
|
||||
Variant(const Vector4 &p_vector4);
|
||||
Variant(const Vector4i &p_vector4i);
|
||||
Variant(const Plane &p_plane);
|
||||
Variant(const ::AABB &p_aabb);
|
||||
Variant(const Quaternion &p_quat);
|
||||
Variant(const Basis &p_matrix);
|
||||
Variant(const Transform2D &p_transform);
|
||||
Variant(const Transform3D &p_transform);
|
||||
Variant(const Projection &p_projection);
|
||||
Variant(const Color &p_color);
|
||||
Variant(const NodePath &p_node_path);
|
||||
Variant(const ::RID &p_rid);
|
||||
Variant(const Object *p_object);
|
||||
Variant(const Callable &p_callable);
|
||||
Variant(const Signal &p_signal);
|
||||
Variant(const Dictionary &p_dictionary);
|
||||
|
||||
Variant(const Array &p_array);
|
||||
Variant(const PackedByteArray &p_byte_array);
|
||||
Variant(const PackedInt32Array &p_int32_array);
|
||||
Variant(const PackedInt64Array &p_int64_array);
|
||||
Variant(const PackedFloat32Array &p_float32_array);
|
||||
Variant(const PackedFloat64Array &p_float64_array);
|
||||
Variant(const PackedStringArray &p_string_array);
|
||||
Variant(const PackedVector2Array &p_vector2_array);
|
||||
Variant(const PackedVector3Array &p_vector3_array);
|
||||
Variant(const PackedColorArray &p_color_array);
|
||||
Variant(const PackedVector4Array &p_vector4_array);
|
||||
|
||||
Variant(const Vector<::RID> &p_array); // helper
|
||||
Variant(const Vector<Plane> &p_array); // helper
|
||||
Variant(const Vector<Face3> &p_face_array);
|
||||
Variant(const Vector<Variant> &p_array);
|
||||
Variant(const Vector<StringName> &p_array);
|
||||
|
||||
Variant(const IPAddress &p_address);
|
||||
|
||||
#define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \
|
||||
Variant(m_enum p_value) : \
|
||||
type(INT) { \
|
||||
_data._int = (int64_t)p_value; \
|
||||
}
|
||||
|
||||
// Only enum classes that need to be bound need this to be defined.
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(EulerOrder)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(Key)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(KeyLocation)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(MIDIMessage)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(MouseButton)
|
||||
|
||||
#undef VARIANT_ENUM_CLASS_CONSTRUCTOR
|
||||
|
||||
// If this changes the table in variant_op must be updated
|
||||
enum Operator {
|
||||
//comparison
|
||||
OP_EQUAL,
|
||||
OP_NOT_EQUAL,
|
||||
OP_LESS,
|
||||
OP_LESS_EQUAL,
|
||||
OP_GREATER,
|
||||
OP_GREATER_EQUAL,
|
||||
//mathematic
|
||||
OP_ADD,
|
||||
OP_SUBTRACT,
|
||||
OP_MULTIPLY,
|
||||
OP_DIVIDE,
|
||||
OP_NEGATE,
|
||||
OP_POSITIVE,
|
||||
OP_MODULE,
|
||||
OP_POWER,
|
||||
//bitwise
|
||||
OP_SHIFT_LEFT,
|
||||
OP_SHIFT_RIGHT,
|
||||
OP_BIT_AND,
|
||||
OP_BIT_OR,
|
||||
OP_BIT_XOR,
|
||||
OP_BIT_NEGATE,
|
||||
//logic
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
OP_XOR,
|
||||
OP_NOT,
|
||||
//containment
|
||||
OP_IN,
|
||||
OP_MAX
|
||||
|
||||
};
|
||||
|
||||
static String get_operator_name(Operator p_op);
|
||||
static void evaluate(const Operator &p_op, const Variant &p_a, const Variant &p_b, Variant &r_ret, bool &r_valid);
|
||||
static _FORCE_INLINE_ Variant evaluate(const Operator &p_op, const Variant &p_a, const Variant &p_b) {
|
||||
bool valid = true;
|
||||
Variant res;
|
||||
evaluate(p_op, p_a, p_b, res, valid);
|
||||
return res;
|
||||
}
|
||||
|
||||
static Variant::Type get_operator_return_type(Operator p_operator, Type p_type_a, Type p_type_b);
|
||||
typedef void (*ValidatedOperatorEvaluator)(const Variant *left, const Variant *right, Variant *r_ret);
|
||||
static ValidatedOperatorEvaluator get_validated_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b);
|
||||
typedef void (*PTROperatorEvaluator)(const void *left, const void *right, void *r_ret);
|
||||
static PTROperatorEvaluator get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b);
|
||||
|
||||
void zero();
|
||||
Variant duplicate(bool p_deep = false) const;
|
||||
Variant recursive_duplicate(bool p_deep, int recursion_count) const;
|
||||
|
||||
/* Built-In Methods */
|
||||
|
||||
typedef void (*ValidatedBuiltInMethod)(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret);
|
||||
typedef void (*PTRBuiltInMethod)(void *p_base, const void **p_args, void *r_ret, int p_argcount);
|
||||
|
||||
static bool has_builtin_method(Variant::Type p_type, const StringName &p_method);
|
||||
|
||||
static ValidatedBuiltInMethod get_validated_builtin_method(Variant::Type p_type, const StringName &p_method);
|
||||
static PTRBuiltInMethod get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method);
|
||||
|
||||
static MethodInfo get_builtin_method_info(Variant::Type p_type, const StringName &p_method);
|
||||
static int get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method);
|
||||
static Variant::Type get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument);
|
||||
static String get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument);
|
||||
static Vector<Variant> get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method);
|
||||
static bool has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method);
|
||||
static Variant::Type get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method);
|
||||
static bool is_builtin_method_const(Variant::Type p_type, const StringName &p_method);
|
||||
static bool is_builtin_method_static(Variant::Type p_type, const StringName &p_method);
|
||||
static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method);
|
||||
static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list);
|
||||
static int get_builtin_method_count(Variant::Type p_type);
|
||||
static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method);
|
||||
|
||||
void callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
|
||||
|
||||
template <typename... VarArgs>
|
||||
Variant call(const StringName &p_method, VarArgs... p_args) {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +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];
|
||||
}
|
||||
Callable::CallError cerr;
|
||||
Variant ret;
|
||||
callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), ret, cerr);
|
||||
if (cerr.error != Callable::CallError::CALL_OK) {
|
||||
_variant_call_error(p_method, cerr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
|
||||
static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
|
||||
|
||||
static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
|
||||
static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
|
||||
static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
|
||||
|
||||
//dynamic (includes Object)
|
||||
void get_method_list(List<MethodInfo> *p_list) const;
|
||||
bool has_method(const StringName &p_method) const;
|
||||
|
||||
/* Constructors */
|
||||
|
||||
typedef void (*ValidatedConstructor)(Variant *r_base, const Variant **p_args);
|
||||
typedef void (*PTRConstructor)(void *base, const void **p_args);
|
||||
|
||||
static int get_constructor_count(Variant::Type p_type);
|
||||
static ValidatedConstructor get_validated_constructor(Variant::Type p_type, int p_constructor);
|
||||
static PTRConstructor get_ptr_constructor(Variant::Type p_type, int p_constructor);
|
||||
static int get_constructor_argument_count(Variant::Type p_type, int p_constructor);
|
||||
static Variant::Type get_constructor_argument_type(Variant::Type p_type, int p_constructor, int p_argument);
|
||||
static String get_constructor_argument_name(Variant::Type p_type, int p_constructor, int p_argument);
|
||||
static void construct(Variant::Type, Variant &base, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
|
||||
static void get_constructor_list(Type p_type, List<MethodInfo> *r_list); //convenience
|
||||
|
||||
/* Destructors */
|
||||
|
||||
// Only ptrcall is available.
|
||||
typedef void (*PTRDestructor)(void *base);
|
||||
|
||||
static PTRDestructor get_ptr_destructor(Variant::Type p_type);
|
||||
static bool has_destructor(Variant::Type p_type);
|
||||
|
||||
/* Properties */
|
||||
|
||||
void set_named(const StringName &p_member, const Variant &p_value, bool &r_valid);
|
||||
Variant get_named(const StringName &p_member, bool &r_valid) const;
|
||||
|
||||
typedef void (*ValidatedSetter)(Variant *base, const Variant *value);
|
||||
typedef void (*ValidatedGetter)(const Variant *base, Variant *value);
|
||||
|
||||
static bool has_member(Variant::Type p_type, const StringName &p_member);
|
||||
static Variant::Type get_member_type(Variant::Type p_type, const StringName &p_member);
|
||||
static void get_member_list(Type p_type, List<StringName> *r_members);
|
||||
static int get_member_count(Type p_type);
|
||||
|
||||
static ValidatedSetter get_member_validated_setter(Variant::Type p_type, const StringName &p_member);
|
||||
static ValidatedGetter get_member_validated_getter(Variant::Type p_type, const StringName &p_member);
|
||||
|
||||
typedef void (*PTRSetter)(void *base, const void *value);
|
||||
typedef void (*PTRGetter)(const void *base, void *value);
|
||||
|
||||
static PTRSetter get_member_ptr_setter(Variant::Type p_type, const StringName &p_member);
|
||||
static PTRGetter get_member_ptr_getter(Variant::Type p_type, const StringName &p_member);
|
||||
|
||||
/* Indexing */
|
||||
|
||||
static bool has_indexing(Variant::Type p_type);
|
||||
static Variant::Type get_indexed_element_type(Variant::Type p_type);
|
||||
static uint32_t get_indexed_element_usage(Variant::Type p_type);
|
||||
|
||||
typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool *oob);
|
||||
typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool *oob);
|
||||
|
||||
static ValidatedIndexedSetter get_member_validated_indexed_setter(Variant::Type p_type);
|
||||
static ValidatedIndexedGetter get_member_validated_indexed_getter(Variant::Type p_type);
|
||||
|
||||
typedef void (*PTRIndexedSetter)(void *base, int64_t index, const void *value);
|
||||
typedef void (*PTRIndexedGetter)(const void *base, int64_t index, void *value);
|
||||
|
||||
static PTRIndexedSetter get_member_ptr_indexed_setter(Variant::Type p_type);
|
||||
static PTRIndexedGetter get_member_ptr_indexed_getter(Variant::Type p_type);
|
||||
|
||||
void set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob);
|
||||
Variant get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const;
|
||||
|
||||
uint64_t get_indexed_size() const;
|
||||
|
||||
/* Keying */
|
||||
|
||||
static bool is_keyed(Variant::Type p_type);
|
||||
|
||||
typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool *valid);
|
||||
typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool *valid);
|
||||
typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool *valid);
|
||||
|
||||
static ValidatedKeyedSetter get_member_validated_keyed_setter(Variant::Type p_type);
|
||||
static ValidatedKeyedGetter get_member_validated_keyed_getter(Variant::Type p_type);
|
||||
static ValidatedKeyedChecker get_member_validated_keyed_checker(Variant::Type p_type);
|
||||
|
||||
typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
|
||||
typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
|
||||
typedef uint32_t (*PTRKeyedChecker)(const void *base, const void *key);
|
||||
|
||||
static PTRKeyedSetter get_member_ptr_keyed_setter(Variant::Type p_type);
|
||||
static PTRKeyedGetter get_member_ptr_keyed_getter(Variant::Type p_type);
|
||||
static PTRKeyedChecker get_member_ptr_keyed_checker(Variant::Type p_type);
|
||||
|
||||
void set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid);
|
||||
Variant get_keyed(const Variant &p_key, bool &r_valid) const;
|
||||
bool has_key(const Variant &p_key, bool &r_valid) const;
|
||||
|
||||
/* Generic */
|
||||
enum VariantSetError {
|
||||
SET_OK,
|
||||
SET_KEYED_ERR,
|
||||
SET_NAMED_ERR,
|
||||
SET_INDEXED_ERR
|
||||
};
|
||||
enum VariantGetError {
|
||||
GET_OK,
|
||||
GET_KEYED_ERR,
|
||||
GET_NAMED_ERR,
|
||||
GET_INDEXED_ERR
|
||||
};
|
||||
void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr, VariantSetError *err_code = nullptr);
|
||||
Variant get(const Variant &p_index, bool *r_valid = nullptr, VariantGetError *err_code = nullptr) const;
|
||||
bool in(const Variant &p_index, bool *r_valid = nullptr) const;
|
||||
|
||||
bool iter_init(Variant &r_iter, bool &r_valid) const;
|
||||
bool iter_next(Variant &r_iter, bool &r_valid) const;
|
||||
Variant iter_get(const Variant &r_iter, bool &r_valid) const;
|
||||
|
||||
void get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
static void call_utility_function(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
static bool has_utility_function(const StringName &p_name);
|
||||
|
||||
typedef void (*ValidatedUtilityFunction)(Variant *r_ret, const Variant **p_args, int p_argcount);
|
||||
typedef void (*PTRUtilityFunction)(void *r_ret, const void **p_args, int p_argcount);
|
||||
|
||||
static ValidatedUtilityFunction get_validated_utility_function(const StringName &p_name);
|
||||
static PTRUtilityFunction get_ptr_utility_function(const StringName &p_name);
|
||||
|
||||
enum UtilityFunctionType {
|
||||
UTILITY_FUNC_TYPE_MATH,
|
||||
UTILITY_FUNC_TYPE_RANDOM,
|
||||
UTILITY_FUNC_TYPE_GENERAL,
|
||||
};
|
||||
|
||||
static UtilityFunctionType get_utility_function_type(const StringName &p_name);
|
||||
|
||||
static MethodInfo get_utility_function_info(const StringName &p_name);
|
||||
static int get_utility_function_argument_count(const StringName &p_name);
|
||||
static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg);
|
||||
static String get_utility_function_argument_name(const StringName &p_name, int p_arg);
|
||||
static bool has_utility_function_return_value(const StringName &p_name);
|
||||
static Variant::Type get_utility_function_return_type(const StringName &p_name);
|
||||
static bool is_utility_function_vararg(const StringName &p_name);
|
||||
static uint32_t get_utility_function_hash(const StringName &p_name);
|
||||
|
||||
static void get_utility_function_list(List<StringName> *r_functions);
|
||||
static int get_utility_function_count();
|
||||
|
||||
//argsVariant call()
|
||||
|
||||
bool operator==(const Variant &p_variant) const;
|
||||
bool operator!=(const Variant &p_variant) const;
|
||||
bool operator<(const Variant &p_variant) const;
|
||||
uint32_t hash() const;
|
||||
uint32_t recursive_hash(int recursion_count) const;
|
||||
|
||||
// By default, performs a semantic comparison. Otherwise, numeric/binary comparison (if appropriate).
|
||||
bool hash_compare(const Variant &p_variant, int recursion_count = 0, bool semantic_comparison = true) const;
|
||||
bool identity_compare(const Variant &p_variant) const;
|
||||
bool booleanize() const;
|
||||
String stringify(int recursion_count = 0) const;
|
||||
String to_json_string() const;
|
||||
|
||||
void static_assign(const Variant &p_variant);
|
||||
static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
|
||||
static int get_constants_count_for_type(Variant::Type p_type);
|
||||
static bool has_constant(Variant::Type p_type, const StringName &p_value);
|
||||
static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr);
|
||||
|
||||
static void get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums);
|
||||
static void get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List<StringName> *p_enumerations);
|
||||
static int get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid = nullptr);
|
||||
|
||||
typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
|
||||
typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);
|
||||
|
||||
String get_construct_string() const;
|
||||
static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = nullptr, void *p_construct_ud = nullptr);
|
||||
|
||||
void operator=(const Variant &p_variant); // only this is enough for all the other types
|
||||
|
||||
static void register_types();
|
||||
static void unregister_types();
|
||||
|
||||
Variant(const Variant &p_variant);
|
||||
_FORCE_INLINE_ Variant() :
|
||||
type(NIL) {}
|
||||
_FORCE_INLINE_ ~Variant() {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
//typedef Dictionary Dictionary; no
|
||||
//typedef Array Array;
|
||||
|
||||
template <typename... VarArgs>
|
||||
Vector<Variant> varray(VarArgs... p_args) {
|
||||
Vector<Variant> v;
|
||||
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
|
||||
uint32_t argc = sizeof...(p_args);
|
||||
|
||||
if (argc > 0) {
|
||||
v.resize(argc);
|
||||
Variant *vw = v.ptrw();
|
||||
|
||||
for (uint32_t i = 0; i < argc; i++) {
|
||||
vw[i] = args[i];
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
struct VariantHasher {
|
||||
static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); }
|
||||
};
|
||||
|
||||
struct VariantComparator {
|
||||
static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
|
||||
};
|
||||
|
||||
struct StringLikeVariantComparator {
|
||||
static bool compare(const Variant &p_lhs, const Variant &p_rhs);
|
||||
};
|
||||
|
||||
Variant::ObjData &Variant::_get_obj() {
|
||||
return *reinterpret_cast<ObjData *>(&_data._mem[0]);
|
||||
}
|
||||
|
||||
const Variant::ObjData &Variant::_get_obj() const {
|
||||
return *reinterpret_cast<const ObjData *>(&_data._mem[0]);
|
||||
}
|
||||
|
||||
template <typename... VarArgs>
|
||||
String vformat(const String &p_text, const VarArgs... p_args) {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
|
||||
Array args_array;
|
||||
args_array.resize(sizeof...(p_args));
|
||||
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
|
||||
args_array[i] = args[i];
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
String fmt = p_text.sprintf(args_array, &error);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(error, String(), String("Formatting error in string \"") + p_text + "\": " + fmt + ".");
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
template <typename... VarArgs>
|
||||
Variant Callable::call(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];
|
||||
}
|
||||
|
||||
Variant ret;
|
||||
CallError ce;
|
||||
callp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), ret, ce);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... VarArgs>
|
||||
Callable Callable::bind(VarArgs... p_args) const {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +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 bindp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
Variant &Array::Iterator::operator*() const {
|
||||
if (unlikely(read_only)) {
|
||||
*read_only = *element_ptr;
|
||||
return *read_only;
|
||||
}
|
||||
return *element_ptr;
|
||||
}
|
||||
|
||||
Variant *Array::Iterator::operator->() const {
|
||||
if (unlikely(read_only)) {
|
||||
*read_only = *element_ptr;
|
||||
return read_only;
|
||||
}
|
||||
return element_ptr;
|
||||
}
|
||||
|
||||
Array::Iterator &Array::Iterator::operator++() {
|
||||
element_ptr++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Array::Iterator &Array::Iterator::operator--() {
|
||||
element_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Variant &Array::ConstIterator::operator*() const {
|
||||
if (unlikely(read_only)) {
|
||||
*read_only = *element_ptr;
|
||||
return *read_only;
|
||||
}
|
||||
return *element_ptr;
|
||||
}
|
||||
|
||||
const Variant *Array::ConstIterator::operator->() const {
|
||||
if (unlikely(read_only)) {
|
||||
*read_only = *element_ptr;
|
||||
return read_only;
|
||||
}
|
||||
return element_ptr;
|
||||
}
|
||||
|
||||
Array::ConstIterator &Array::ConstIterator::operator++() {
|
||||
element_ptr++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Array::ConstIterator &Array::ConstIterator::operator--() {
|
||||
element_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // VARIANT_H
|
||||
2774
engine/core/variant/variant_call.cpp
Normal file
2774
engine/core/variant/variant_call.cpp
Normal file
File diff suppressed because it is too large
Load diff
90
engine/core/variant/variant_callable.cpp
Normal file
90
engine/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 (Callable)", 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);
|
||||
}
|
||||
59
engine/core/variant/variant_callable.h
Normal file
59
engine/core/variant/variant_callable.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_CALLABLE_H
|
||||
#define VARIANT_CALLABLE_H
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
#endif // VARIANT_CALLABLE_H
|
||||
373
engine/core/variant/variant_construct.cpp
Normal file
373
engine/core/variant/variant_construct.cpp
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
/**************************************************************************/
|
||||
/* 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(), "Argument names size mismatch for " + 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<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 VariantInternal::refcounted_object_assign(Variant *v, const RefCounted *rc) {
|
||||
if (!rc || !const_cast<RefCounted *>(rc)->init_ref()) {
|
||||
v->_get_obj().obj = nullptr;
|
||||
v->_get_obj().id = ObjectID();
|
||||
return;
|
||||
}
|
||||
|
||||
v->_get_obj().obj = const_cast<RefCounted *>(rc);
|
||||
v->_get_obj().id = rc->get_instance_id();
|
||||
}
|
||||
|
||||
void VariantInternal::object_assign(Variant *v, const Object *o) {
|
||||
if (o) {
|
||||
if (o->is_ref_counted()) {
|
||||
RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(o));
|
||||
if (!ref_counted->init_ref()) {
|
||||
v->_get_obj().obj = nullptr;
|
||||
v->_get_obj().id = ObjectID();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
v->_get_obj().obj = const_cast<Object *>(o);
|
||||
v->_get_obj().id = o->get_instance_id();
|
||||
} else {
|
||||
v->_get_obj().obj = nullptr;
|
||||
v->_get_obj().id = ObjectID();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
713
engine/core/variant/variant_construct.h
Normal file
713
engine/core/variant/variant_construct.h
Normal file
|
|
@ -0,0 +1,713 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_CONSTRUCT_H
|
||||
#define VARIANT_CONSTRUCT_H
|
||||
|
||||
#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/local_vector.h"
|
||||
#include "core/templates/oa_hash_map.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_METHODS_ENABLED
|
||||
base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
base = T(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
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_assign_null(&r_ret);
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
} else if (p_args[0]->get_type() == Variant::OBJECT) {
|
||||
VariantInternal::clear(&r_ret);
|
||||
VariantTypeChanger<Object *>::change(&r_ret);
|
||||
VariantInternal::object_assign(&r_ret, p_args[0]);
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
} else {
|
||||
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) {
|
||||
VariantInternal::clear(r_ret);
|
||||
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_assign_null(&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_assign_null(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]->get_type() != Variant::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 = *VariantGetInternalPtr<String>::get_ptr(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 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]->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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // VARIANT_CONSTRUCT_H
|
||||
74
engine/core/variant/variant_destruct.cpp
Normal file
74
engine/core/variant/variant_destruct.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**************************************************************************/
|
||||
/* 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"
|
||||
|
||||
#include "core/templates/local_vector.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;
|
||||
}
|
||||
72
engine/core/variant/variant_destruct.h
Normal file
72
engine/core/variant/variant_destruct.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_DESTRUCT_H
|
||||
#define VARIANT_DESTRUCT_H
|
||||
|
||||
#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
|
||||
|
||||
#endif // VARIANT_DESTRUCT_H
|
||||
1583
engine/core/variant/variant_internal.h
Normal file
1583
engine/core/variant/variant_internal.h
Normal file
File diff suppressed because it is too large
Load diff
1170
engine/core/variant/variant_op.cpp
Normal file
1170
engine/core/variant/variant_op.cpp
Normal file
File diff suppressed because it is too large
Load diff
1544
engine/core/variant/variant_op.h
Normal file
1544
engine/core/variant/variant_op.h
Normal file
File diff suppressed because it is too large
Load diff
2304
engine/core/variant/variant_parser.cpp
Normal file
2304
engine/core/variant/variant_parser.cpp
Normal file
File diff suppressed because it is too large
Load diff
168
engine/core/variant/variant_parser.h
Normal file
168
engine/core/variant/variant_parser.h
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_PARSER_H
|
||||
#define VARIANT_PARSER_H
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
#endif // VARIANT_PARSER_H
|
||||
2017
engine/core/variant/variant_setget.cpp
Normal file
2017
engine/core/variant/variant_setget.cpp
Normal file
File diff suppressed because it is too large
Load diff
350
engine/core/variant/variant_setget.h
Normal file
350
engine/core/variant/variant_setget.h
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_SETGET_H
|
||||
#define VARIANT_SETGET_H
|
||||
|
||||
#include "variant.h"
|
||||
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/templates/local_vector.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)
|
||||
|
||||
#endif // VARIANT_SETGET_H
|
||||
1993
engine/core/variant/variant_utility.cpp
Normal file
1993
engine/core/variant/variant_utility.cpp
Normal file
File diff suppressed because it is too large
Load diff
159
engine/core/variant/variant_utility.h
Normal file
159
engine/core/variant/variant_utility.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VARIANT_UTILITY_H
|
||||
#define VARIANT_UTILITY_H
|
||||
|
||||
#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);
|
||||
#undef print_verbose
|
||||
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);
|
||||
};
|
||||
|
||||
#endif // VARIANT_UTILITY_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue