summaryrefslogtreecommitdiff
path: root/core/variant
diff options
context:
space:
mode:
Diffstat (limited to 'core/variant')
-rw-r--r--core/variant/array.cpp73
-rw-r--r--core/variant/array.h3
-rw-r--r--core/variant/callable.cpp20
-rw-r--r--core/variant/callable.h10
-rw-r--r--core/variant/method_ptrcall.h4
-rw-r--r--core/variant/type_info.h2
-rw-r--r--core/variant/variant.cpp8
-rw-r--r--core/variant/variant.h4
-rw-r--r--core/variant/variant_call.cpp82
-rw-r--r--core/variant/variant_op.cpp16
-rw-r--r--core/variant/variant_utility.cpp5
11 files changed, 215 insertions, 12 deletions
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 2fb2dd4a30..3c7e2a0719 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -361,6 +361,79 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { // l
return new_arr;
}
+Array Array::filter(const Callable &p_callable) const {
+ Array new_arr;
+ new_arr.resize(size());
+ int accepted_count = 0;
+
+ for (int i = 0; i < size(); i++) {
+ const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *));
+ argptrs[0] = &get(i);
+
+ Variant result;
+ Callable::CallError ce;
+ p_callable.call(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());
+
+ for (int i = 0; i < size(); i++) {
+ const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *));
+ argptrs[0] = &get(i);
+
+ Variant result;
+ Callable::CallError ce;
+ p_callable.call(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;
+ }
+
+ for (int i = start; i < size(); i++) {
+ const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * 2);
+ argptrs[0] = &ret;
+ argptrs[1] = &get(i);
+
+ Variant result;
+ Callable::CallError ce;
+ p_callable.call(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;
+}
+
struct _ArrayVariantSort {
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
bool valid = false;
diff --git a/core/variant/array.h b/core/variant/array.h
index 5ce977ee4b..540dcb1f4e 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -101,6 +101,9 @@ public:
Array duplicate(bool p_deep = false) const;
Array slice(int p_begin, int p_end, 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 operator<(const Array &p_array) const;
bool operator<=(const Array &p_array) const;
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index a1d9c5ed2f..e06b3e07ef 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -54,6 +54,20 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu
}
}
+void Callable::rpc(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;
+ } else if (!is_custom()) {
+ r_call_error.error = CallError::CALL_ERROR_INVALID_METHOD;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ } else {
+ custom->rpc(p_id, p_arguments, p_argcount, r_call_error);
+ }
+}
+
Callable Callable::bind(const Variant **p_arguments, int p_argcount) const {
Vector<Variant> args;
args.resize(p_argcount);
@@ -283,6 +297,12 @@ Callable::~Callable() {
}
}
+void 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;
+}
+
const Callable *CallableCustom::get_base_comparator() const {
return nullptr;
}
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 090fd888e2..20d0804292 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -44,9 +44,9 @@ class CallableCustom;
// 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 {
- //needs to be max 16 bytes in 64 bits
- StringName method;
+ alignas(8) StringName method;
union {
uint64_t object = 0;
CallableCustom *custom;
@@ -70,6 +70,8 @@ public:
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferred(const Variant **p_arguments, int p_argcount) const;
+ void rpc(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;
}
@@ -124,6 +126,7 @@ public:
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual ObjectID get_object() const = 0; //must always be able to provide an object
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
+ virtual void 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;
CallableCustom();
@@ -135,8 +138,9 @@ public:
// 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 {
- StringName name;
+ alignas(8) StringName name;
ObjectID object;
public:
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index c294592b63..e91029f330 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -364,7 +364,7 @@ MAKE_VECARR(Plane);
} \
}
-// Special case for IP_Address.
+// Special case for IPAddress.
#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \
template <> \
@@ -387,7 +387,7 @@ MAKE_VECARR(Plane);
} \
}
-MAKE_STRINGCONV_BY_REFERENCE(IP_Address);
+MAKE_STRINGCONV_BY_REFERENCE(IPAddress);
template <>
struct PtrToArg<Vector<Face3>> {
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index f61ff29b8f..d5b6d85dfb 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -168,7 +168,7 @@ 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(IP_Address, Variant::STRING)
+MAKE_TYPE_INFO(IPAddress, Variant::STRING)
//objectID
template <>
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 015cee09a7..333dd8e8d1 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -2346,15 +2346,15 @@ Variant::operator Orientation() const {
return (Orientation) operator int();
}
-Variant::operator IP_Address() const {
+Variant::operator IPAddress() const {
if (type == PACKED_FLOAT32_ARRAY || type == PACKED_INT32_ARRAY || type == PACKED_FLOAT64_ARRAY || type == PACKED_INT64_ARRAY || type == PACKED_BYTE_ARRAY) {
Vector<int> addr = operator Vector<int>();
if (addr.size() == 4) {
- return IP_Address(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
+ return IPAddress(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
}
}
- return IP_Address(operator String());
+ return IPAddress(operator String());
}
Variant::Variant(bool p_bool) {
@@ -2831,7 +2831,7 @@ void Variant::operator=(const Variant &p_variant) {
}
}
-Variant::Variant(const IP_Address &p_address) {
+Variant::Variant(const IPAddress &p_address) {
type = STRING;
memnew_placement(_data._mem, String(p_address));
}
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 0acafc64fa..7f3c3477fc 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -359,7 +359,7 @@ public:
operator Side() const;
operator Orientation() const;
- operator IP_Address() const;
+ operator IPAddress() const;
Object *get_validated_object() const;
Object *get_validated_object_with_check(bool &r_previously_freed) const;
@@ -421,7 +421,7 @@ public:
Variant(const Vector<::RID> &p_array); // helper
Variant(const Vector<Vector2> &p_array); // helper
- Variant(const IP_Address &p_address);
+ Variant(const IPAddress &p_address);
// If this changes the table in variant_op must be updated
enum Operator {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index deaccc6304..efaaa8cd19 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -493,6 +493,58 @@ static _FORCE_INLINE_ void vc_ptrcall(void (*method)(T *, P...), void *p_base, c
} \
};
+#define VARARG_CLASS1(m_class, m_method_name, m_method_ptr, m_arg_type) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ m_method_ptr(base, p_args, p_argcount, r_ret, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ Callable::CallError ce; \
+ m_method_ptr(base, p_args, p_argcount, *r_ret, ce); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ LocalVector<Variant> vars; \
+ vars.resize(p_argcount); \
+ LocalVector<const Variant *> vars_ptrs; \
+ vars_ptrs.resize(p_argcount); \
+ for (int i = 0; i < p_argcount; i++) { \
+ vars[i] = PtrToArg<Variant>::convert(p_args[i]); \
+ vars_ptrs[i] = &vars[i]; \
+ } \
+ Variant base = PtrToArg<m_class>::convert(p_base); \
+ Variant ret; \
+ Callable::CallError ce; \
+ m_method_ptr(&base, (const Variant **)&vars_ptrs[0], p_argcount, ret, ce); \
+ } \
+ static int get_argument_count() { \
+ return 1; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return m_arg_type; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return false; \
+ } \
+ static bool is_const() { \
+ return true; \
+ } \
+ static bool is_static() { \
+ return false; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
struct _VariantCall {
static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) {
String s;
@@ -792,6 +844,27 @@ struct _VariantCall {
callable->call_deferred(p_args, p_argcount);
}
+ static void func_Callable_rpc(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->rpc(0, p_args, p_argcount, r_error);
+ }
+
+ static void func_Callable_rpc_id(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ if (p_argcount == 0) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ r_error.expected = 1;
+
+ } else if (p_args[0]->get_type() != Variant::INT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ } else {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->rpc(*p_args[0], &p_args[1], p_argcount - 1, r_error);
+ }
+ }
+
static void func_Callable_bind(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
r_ret = callable->bind(p_args, p_argcount);
@@ -1219,6 +1292,10 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \
register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>());
+#define bind_custom1(m_type, m_name, m_method, m_arg_type, m_arg_name) \
+ VARARG_CLASS1(m_type, m_name, m_method, m_arg_type) \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(m_arg_name), Vector<Variant>());
+
static void _register_variant_builtin_methods() {
_VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX);
@@ -1532,6 +1609,8 @@ static void _register_variant_builtin_methods() {
bind_custom(Callable, call, _VariantCall::func_Callable_call, true, Variant);
bind_custom(Callable, call_deferred, _VariantCall::func_Callable_call_deferred, false, Variant);
+ bind_custom(Callable, rpc, _VariantCall::func_Callable_rpc, false, Variant);
+ bind_custom1(Callable, rpc_id, _VariantCall::func_Callable_rpc_id, Variant::INT, "peer_id");
bind_custom(Callable, bind, _VariantCall::func_Callable_bind, true, Callable);
/* Signal */
@@ -1666,6 +1745,9 @@ static void _register_variant_builtin_methods() {
bind_method(Array, reverse, sarray(), varray());
bind_method(Array, duplicate, sarray("deep"), varray(false));
bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
+ bind_method(Array, filter, sarray("method"), varray());
+ bind_method(Array, map, sarray("method"), varray());
+ bind_method(Array, reduce, sarray("method", "accum"), varray(Variant()));
bind_method(Array, max, sarray(), varray());
bind_method(Array, min, sarray(), varray());
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 6cbc98d14d..8cfa793c0e 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -257,6 +257,14 @@ public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+
+#if defined(DEBUG_ENABLED)
+ if (b < 0 || a < 0) {
+ *r_ret = "Invalid operands for bit shifting. Only positive operands are supported.";
+ r_valid = false;
+ return;
+ }
+#endif
*r_ret = a << b;
r_valid = true;
}
@@ -276,6 +284,14 @@ public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+
+#if defined(DEBUG_ENABLED)
+ if (b < 0 || a < 0) {
+ *r_ret = "Invalid operands for bit shifting. Only positive operands are supported.";
+ r_valid = false;
+ return;
+ }
+#endif
*r_ret = a >> b;
r_valid = true;
}
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index f154ab1ed6..553f2b23a2 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -93,6 +93,10 @@ struct VariantUtilityFunctions {
return Math::fposmod(b, r);
}
+ static inline int64_t posmod(int64_t b, int64_t r) {
+ return Math::posmod(b, r);
+ }
+
static inline double floor(double x) {
return Math::floor(x);
}
@@ -1154,6 +1158,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(posmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);