diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/color.cpp | 8 | ||||
| -rw-r--r-- | core/hash_map.h | 33 | ||||
| -rw-r--r-- | core/hashfuncs.h | 34 | ||||
| -rw-r--r-- | core/math/camera_matrix.cpp | 2 | ||||
| -rw-r--r-- | core/oa_hash_map.h | 593 | ||||
| -rw-r--r-- | core/os/file_access.h | 2 | ||||
| -rw-r--r-- | core/variant.cpp | 161 | ||||
| -rw-r--r-- | core/variant.h | 2 | ||||
| -rw-r--r-- | core/variant_op.cpp | 219 |
9 files changed, 845 insertions, 209 deletions
diff --git a/core/color.cpp b/core/color.cpp index dd8b13c047..78b11a84df 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -250,6 +250,14 @@ Color Color::html(const String &p_color) { return Color(); if (color[0] == '#') color = color.substr(1, color.length() - 1); + if (color.length() == 3 || color.length() == 4) { + String exp_color; + for (int i = 0; i < color.length(); i++) { + exp_color += color[i]; + exp_color += color[i]; + } + color = exp_color; + } bool alpha = false; diff --git a/core/hash_map.h b/core/hash_map.h index 37391a4c83..e100d7a904 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -37,39 +37,6 @@ #include "os/memory.h" #include "ustring.h" -struct HashMapHasherDefault { - static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } - static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } - static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } - - static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); } - static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_djb2_one_float(p_double); } - static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; } - //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } -}; - -template <typename T> -struct HashMapComparatorDefault { - static bool compare(const T &p_lhs, const T &p_rhs) { - return p_lhs == p_rhs; - } - - bool compare(const float &p_lhs, const float &p_rhs) { - return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); - } - - bool compare(const double &p_lhs, const double &p_rhs) { - return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); - } -}; - /** * @class HashMap * @author Juan Linietsky <reduzio@gmail.com> diff --git a/core/hashfuncs.h b/core/hashfuncs.h index 56d40f1dd7..2880cc451e 100644 --- a/core/hashfuncs.h +++ b/core/hashfuncs.h @@ -33,6 +33,7 @@ #include "math_defs.h" #include "math_funcs.h" #include "typedefs.h" +#include "ustring.h" /** * Hashing functions @@ -128,4 +129,37 @@ static inline uint64_t make_uint64_t(T p_in) { return _u._u64; } +struct HashMapHasherDefault { + static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } + static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } + static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } + + static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); } + static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); } + static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_djb2_one_float(p_double); } + static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; } + static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; } + static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; } + static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; } + static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; } + static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; } + static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; } + //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } +}; + +template <typename T> +struct HashMapComparatorDefault { + static bool compare(const T &p_lhs, const T &p_rhs) { + return p_lhs == p_rhs; + } + + bool compare(const float &p_lhs, const float &p_rhs) { + return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); + } + + bool compare(const double &p_lhs, const double &p_rhs) { + return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); + } +}; + #endif diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 7132b6573e..2c587762e8 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -577,7 +577,7 @@ real_t CameraMatrix::get_fov() const { if ((matrix[8] == 0) && (matrix[9] == 0)) { return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; } else { - // our frustum is asymetrical need to calculate the left planes angle seperately.. + // our frustum is asymmetrical need to calculate the left planes angle separately.. Plane left_plane = Plane(matrix[3] + matrix[0], matrix[7] + matrix[4], matrix[11] + matrix[8], diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h new file mode 100644 index 0000000000..66a1e348a1 --- /dev/null +++ b/core/oa_hash_map.h @@ -0,0 +1,593 @@ +/*************************************************************************/ +/* oa_hash_map.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 OA_HASH_MAP_H +#define OA_HASH_MAP_H + +#include "hashfuncs.h" +#include "math_funcs.h" +#include "os/copymem.h" +#include "os/memory.h" + +// uncomment this to disable intial local storage. +#define OA_HASH_MAP_INITIAL_LOCAL_STORAGE + +/** + * This class implements a hash map datastructure that uses open addressing with + * local probing. + * + * It can give huge performance improvements over a chained HashMap because of + * the increased data locality. + * + * Because of that locality property it's important to not use "large" value + * types as the "TData" type. If TData values are too big it can cause more + * cache misses then chaining. If larger values are needed then storing those + * in a separate array and using pointers or indices to reference them is the + * better solution. + * + * This hash map also implements real-time incremental rehashing. + * + */ +template <class TKey, class TData, + uint16_t INITIAL_NUM_ELEMENTS = 64, + class Hasher = HashMapHasherDefault, + class Comparator = HashMapComparatorDefault<TKey> > +class OAHashMap { + +private: +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + TData local_data[INITIAL_NUM_ELEMENTS]; + TKey local_keys[INITIAL_NUM_ELEMENTS]; + uint32_t local_hashes[INITIAL_NUM_ELEMENTS]; + uint8_t local_flags[INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)]; +#endif + + struct { + TData *data; + TKey *keys; + uint32_t *hashes; + + // This is actually an array of bits, 4 bit pairs per octet. + // | ba ba ba ba | ba ba ba ba | .... + // + // if a is set it means that there is an element present. + // if b is set it means that an element was deleted. This is needed for + // the local probing to work without relocating any succeeding and + // colliding entries. + uint8_t *flags; + + uint32_t capacity; + } table, old_table; + + bool is_rehashing; + uint32_t rehash_position; + uint32_t rehash_amount; + + uint32_t elements; + + /* Methods */ + + // returns true if the value already existed, false if it's a new entry + bool _raw_set_with_hash(uint32_t p_hash, const TKey &p_key, const TData &p_data) { + for (int i = 0; i < table.capacity; i++) { + + int pos = (p_hash + i) % table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset)); + bool is_deleted_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1)); + + if (is_filled_flag) { + if (table.hashes[pos] == p_hash && Comparator::compare(table.keys[pos], p_key)) { + table.data[pos] = p_data; + return true; + } + continue; + } + + table.keys[pos] = p_key; + table.data[pos] = p_data; + table.hashes[pos] = p_hash; + + table.flags[flags_pos] |= (1 << (2 * flags_pos_offset)); + table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset + 1)); + + return false; + } + return false; + } + +public: + _FORCE_INLINE_ uint32_t get_capacity() const { return table.capacity; } + _FORCE_INLINE_ uint32_t get_num_elements() const { return elements; } + + void set(const TKey &p_key, const TData &p_data) { + + uint32_t hash = Hasher::hash(p_key); + + // We don't progress the rehashing if the table just got resized + // to keep the cost of this function low. + if (is_rehashing) { + + // rehash progress + + for (int i = 0; i <= rehash_amount && rehash_position < old_table.capacity; rehash_position++) { + + int flags_pos = rehash_position / 4; + int flags_pos_offset = rehash_position % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + _raw_set_with_hash(old_table.hashes[rehash_position], old_table.keys[rehash_position], old_table.data[rehash_position]); + + old_table.keys[rehash_position].~TKey(); + old_table.data[rehash_position].~TData(); + + memnew_placement(&old_table.keys[rehash_position], TKey); + memnew_placement(&old_table.data[rehash_position], TData); + + old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); + old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); + } + } + + if (rehash_position >= old_table.capacity) { + + // wohooo, we can get rid of the old table. + is_rehashing = false; + +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + if (old_table.data == local_data) { + // Everything is local, so no cleanup :P + } else +#endif + { + memdelete_arr(old_table.data); + memdelete_arr(old_table.keys); + memdelete_arr(old_table.hashes); + memdelete_arr(old_table.flags); + } + } + } + + // Table is almost full, resize and start rehashing process. + if (elements >= table.capacity * 0.7) { + + old_table.capacity = table.capacity; + old_table.data = table.data; + old_table.flags = table.flags; + old_table.hashes = table.hashes; + old_table.keys = table.keys; + + table.capacity = old_table.capacity * 2; + + table.data = memnew_arr(TData, table.capacity); + table.flags = memnew_arr(uint8_t, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0)); + table.hashes = memnew_arr(uint32_t, table.capacity); + table.keys = memnew_arr(TKey, table.capacity); + + zeromem(table.flags, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0)); + + is_rehashing = true; + rehash_position = 0; + rehash_amount = (elements * 2) / (table.capacity * 0.7 - old_table.capacity); + } + + if (!_raw_set_with_hash(hash, p_key, p_data)) + elements++; + } + + /** + * returns true if the value was found, false otherwise. + * + * if r_data is not NULL then the value will be written to the object + * it points to. + */ + bool lookup(const TKey &p_key, TData *r_data) { + + uint32_t hash = Hasher::hash(p_key); + + bool check_old_table = is_rehashing; + bool check_new_table = true; + + // search for the key and return the value associated with it + // + // if we're rehashing we need to check both the old and the + // current table. If we find a value in the old table we still + // need to continue searching in the new table as it might have + // been added after + + TData *value = NULL; + + for (int i = 0; i < table.capacity; i++) { + + if (!check_new_table && !check_old_table) { + + break; + } + + // if we're rehashing check the old table + if (check_old_table && i < old_table.capacity) { + + int pos = (hash + i) % old_table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) { + value = &old_table.data[pos]; + check_old_table = false; + } + } else if (!is_deleted_flag) { + + // we hit an empty field here, we don't + // need to further check this old table + // because we know it's not in here. + + check_old_table = false; + } + } + + if (check_new_table) { + + int pos = (hash + i) % table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) { + if (r_data != NULL) + *r_data = table.data[pos]; + return true; + } + continue; + } else if (is_deleted_flag) { + continue; + } else if (value != NULL) { + + // We found a value in the old table + if (r_data != NULL) + *r_data = *value; + return true; + } else { + check_new_table = false; + } + } + } + + if (value != NULL) { + if (r_data != NULL) + *r_data = *value; + return true; + } + return false; + } + + _FORCE_INLINE_ bool has(const TKey &p_key) { + return lookup(p_key, NULL); + } + + void remove(const TKey &p_key) { + uint32_t hash = Hasher::hash(p_key); + + bool check_old_table = is_rehashing; + bool check_new_table = true; + + for (int i = 0; i < table.capacity; i++) { + + if (!check_new_table && !check_old_table) { + return; + } + + // if we're rehashing check the old table + if (check_old_table && i < old_table.capacity) { + + int pos = (hash + i) % old_table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) { + old_table.keys[pos].~TKey(); + old_table.data[pos].~TData(); + + memnew_placement(&old_table.keys[pos], TKey); + memnew_placement(&old_table.data[pos], TData); + + old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); + old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); + + elements--; + return; + } + } else if (!is_deleted_flag) { + + // we hit an empty field here, we don't + // need to further check this old table + // because we know it's not in here. + + check_old_table = false; + } + } + + if (check_new_table) { + + int pos = (hash + i) % table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) { + table.keys[pos].~TKey(); + table.data[pos].~TData(); + + memnew_placement(&table.keys[pos], TKey); + memnew_placement(&table.data[pos], TData); + + table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); + table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); + + // don't return here, this value might still be in the old table + // if it was already relocated. + + elements--; + return; + } + continue; + } else if (is_deleted_flag) { + continue; + } else { + check_new_table = false; + } + } + } + } + + struct Iterator { + bool valid; + + uint32_t hash; + + const TKey *key; + const TData *data; + + private: + friend class OAHashMap; + bool was_from_old_table; + }; + + Iterator iter() const { + Iterator it; + + it.valid = false; + it.was_from_old_table = false; + + bool check_old_table = is_rehashing; + + for (int i = 0; i < table.capacity; i++) { + + // if we're rehashing check the old table first + if (check_old_table && i < old_table.capacity) { + + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = old_table.hashes[pos]; + it.data = &old_table.data[pos]; + it.key = &old_table.keys[pos]; + + it.was_from_old_table = true; + + return it; + } + } + + { + + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = table.hashes[pos]; + it.data = &table.data[pos]; + it.key = &table.keys[pos]; + + return it; + } + } + } + + return it; + } + + Iterator next_iter(const Iterator &p_iter) const { + if (!p_iter.valid) { + return p_iter; + } + + Iterator it; + + it.valid = false; + it.was_from_old_table = false; + + bool check_old_table = is_rehashing; + + // we use this to skip the first check or not + bool was_from_old_table = p_iter.was_from_old_table; + + int prev_index = (p_iter.data - (p_iter.was_from_old_table ? old_table.data : table.data)); + + if (!was_from_old_table) { + prev_index++; + } + + for (int i = prev_index; i < table.capacity; i++) { + + // if we're rehashing check the old table first + if (check_old_table && i < old_table.capacity && !was_from_old_table) { + + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = old_table.hashes[pos]; + it.data = &old_table.data[pos]; + it.key = &old_table.keys[pos]; + + it.was_from_old_table = true; + + return it; + } + } + + was_from_old_table = false; + + { + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = table.hashes[pos]; + it.data = &table.data[pos]; + it.key = &table.keys[pos]; + + return it; + } + } + } + + return it; + } + + OAHashMap(uint32_t p_initial_capacity = INITIAL_NUM_ELEMENTS) { + +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + + if (p_initial_capacity <= INITIAL_NUM_ELEMENTS) { + table.data = local_data; + table.keys = local_keys; + table.hashes = local_hashes; + table.flags = local_flags; + + zeromem(table.flags, INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)); + + table.capacity = INITIAL_NUM_ELEMENTS; + elements = 0; + } else +#endif + { + table.data = memnew_arr(TData, p_initial_capacity); + table.keys = memnew_arr(TKey, p_initial_capacity); + table.hashes = memnew_arr(uint32_t, p_initial_capacity); + table.flags = memnew_arr(uint8_t, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0)); + + zeromem(table.flags, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0)); + + table.capacity = p_initial_capacity; + elements = 0; + } + + is_rehashing = false; + rehash_position = 0; + } + + ~OAHashMap() { +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + if (table.capacity <= INITIAL_NUM_ELEMENTS) { + return; // Everything is local, so no cleanup :P + } +#endif + if (is_rehashing) { + +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + if (old_table.data == local_data) { + // Everything is local, so no cleanup :P + } else +#endif + { + memdelete_arr(old_table.data); + memdelete_arr(old_table.keys); + memdelete_arr(old_table.hashes); + memdelete_arr(old_table.flags); + } + } + + memdelete_arr(table.data); + memdelete_arr(table.keys); + memdelete_arr(table.hashes); + memdelete_arr(table.flags); + } +}; + +#endif diff --git a/core/os/file_access.h b/core/os/file_access.h index 151c41c263..63692cb290 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -140,7 +140,7 @@ public: virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType - virtual Error _chmod(const String &p_path, int p_mod) {} + virtual Error _chmod(const String &p_path, int p_mod) { return FAILED; } static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. static FileAccess *create_for_path(const String &p_path); diff --git a/core/variant.cpp b/core/variant.cpp index 10d86152ee..52bdd4e22d 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -903,9 +903,6 @@ bool Variant::is_one() const { void Variant::reference(const Variant &p_variant) { - if (this == &p_variant) - return; - clear(); type = p_variant.type; @@ -924,17 +921,14 @@ void Variant::reference(const Variant &p_variant) { case INT: { _data._int = p_variant._data._int; - } break; case REAL: { _data._real = p_variant._data._real; - } break; case STRING: { memnew_placement(_data._mem, String(*reinterpret_cast<const String *>(p_variant._data._mem))); - } break; // math types @@ -942,33 +936,24 @@ void Variant::reference(const Variant &p_variant) { case VECTOR2: { memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem))); - } break; case RECT2: { memnew_placement(_data._mem, Rect2(*reinterpret_cast<const Rect2 *>(p_variant._data._mem))); - } break; case TRANSFORM2D: { _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); - } break; case VECTOR3: { memnew_placement(_data._mem, Vector3(*reinterpret_cast<const Vector3 *>(p_variant._data._mem))); - } break; case PLANE: { memnew_placement(_data._mem, Plane(*reinterpret_cast<const Plane *>(p_variant._data._mem))); - } break; - /* - case QUAT: { - - } break;*/ case RECT3: { _data._rect3 = memnew(Rect3(*p_variant._data._rect3)); @@ -986,7 +971,6 @@ void Variant::reference(const Variant &p_variant) { case TRANSFORM: { _data._transform = memnew(Transform(*p_variant._data._transform)); - } break; // misc types @@ -1058,6 +1042,7 @@ void Variant::reference(const Variant &p_variant) { default: {} } } + void Variant::zero() { switch (type) { case NIL: break; @@ -1073,6 +1058,7 @@ void Variant::zero() { default: this->clear(); break; } } + void Variant::clear() { switch (type) { @@ -1092,12 +1078,10 @@ void Variant::clear() { case TRANSFORM2D: { memdelete(_data._transform2d); - } break; case RECT3: { memdelete(_data._rect3); - } break; case BASIS: { @@ -1106,14 +1090,12 @@ void Variant::clear() { case TRANSFORM: { memdelete(_data._transform); - } break; // misc types case NODE_PATH: { reinterpret_cast<NodePath *>(_data._mem)->~NodePath(); - } break; case OBJECT: { @@ -1127,48 +1109,39 @@ void Variant::clear() { case DICTIONARY: { reinterpret_cast<Dictionary *>(_data._mem)->~Dictionary(); - } break; case ARRAY: { reinterpret_cast<Array *>(_data._mem)->~Array(); - } break; // arrays case POOL_BYTE_ARRAY: { reinterpret_cast<PoolVector<uint8_t> *>(_data._mem)->~PoolVector<uint8_t>(); - } break; case POOL_INT_ARRAY: { reinterpret_cast<PoolVector<int> *>(_data._mem)->~PoolVector<int>(); - } break; case POOL_REAL_ARRAY: { reinterpret_cast<PoolVector<real_t> *>(_data._mem)->~PoolVector<real_t>(); - } break; case POOL_STRING_ARRAY: { reinterpret_cast<PoolVector<String> *>(_data._mem)->~PoolVector<String>(); - } break; case POOL_VECTOR2_ARRAY: { reinterpret_cast<PoolVector<Vector2> *>(_data._mem)->~PoolVector<Vector2>(); - } break; case POOL_VECTOR3_ARRAY: { reinterpret_cast<PoolVector<Vector3> *>(_data._mem)->~PoolVector<Vector3>(); - } break; case POOL_COLOR_ARRAY: { reinterpret_cast<PoolVector<Color> *>(_data._mem)->~PoolVector<Color>(); - } break; default: {} /* not needed */ } @@ -2496,7 +2469,135 @@ Variant::Variant(const Vector<Color> &p_array) { void Variant::operator=(const Variant &p_variant) { - reference(p_variant); + if (this == &p_variant) + return; + + if (type != p_variant.type) { + reference(p_variant); + return; + } + + switch (p_variant.type) { + case NIL: { + + // none + } break; + + // atomic types + case BOOL: { + + _data._bool = p_variant._data._bool; + } break; + case INT: { + + _data._int = p_variant._data._int; + } break; + case REAL: { + + _data._real = p_variant._data._real; + } break; + case STRING: { + + *reinterpret_cast<String *>(_data._mem) = *reinterpret_cast<const String *>(p_variant._data._mem); + } break; + + // math types + + case VECTOR2: { + + *reinterpret_cast<Vector2 *>(_data._mem) = *reinterpret_cast<const Vector2 *>(p_variant._data._mem); + } break; + case RECT2: { + + *reinterpret_cast<Rect2 *>(_data._mem) = *reinterpret_cast<const Rect2 *>(p_variant._data._mem); + } break; + case TRANSFORM2D: { + + *_data._transform2d = *(p_variant._data._transform2d); + } break; + case VECTOR3: { + + *reinterpret_cast<Vector3 *>(_data._mem) = *reinterpret_cast<const Vector3 *>(p_variant._data._mem); + } break; + case PLANE: { + + *reinterpret_cast<Plane *>(_data._mem) = *reinterpret_cast<const Plane *>(p_variant._data._mem); + } break; + + case RECT3: { + + *_data._rect3 = *(p_variant._data._rect3); + } break; + case QUAT: { + + *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem); + } break; + case BASIS: { + + *_data._basis = *(p_variant._data._basis); + } break; + case TRANSFORM: { + + *_data._transform = *(p_variant._data._transform); + } break; + + // misc types + case COLOR: { + + *reinterpret_cast<Color *>(_data._mem) = *reinterpret_cast<const Color *>(p_variant._data._mem); + } break; + case _RID: { + + *reinterpret_cast<RID *>(_data._mem) = *reinterpret_cast<const RID *>(p_variant._data._mem); + } break; + case OBJECT: { + + *reinterpret_cast<ObjData *>(_data._mem) = p_variant._get_obj(); + } break; + case NODE_PATH: { + + *reinterpret_cast<NodePath *>(_data._mem) = *reinterpret_cast<const NodePath *>(p_variant._data._mem); + } break; + case DICTIONARY: { + + *reinterpret_cast<Dictionary *>(_data._mem) = *reinterpret_cast<const Dictionary *>(p_variant._data._mem); + } break; + case ARRAY: { + + *reinterpret_cast<Array *>(_data._mem) = *reinterpret_cast<const Array *>(p_variant._data._mem); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + + *reinterpret_cast<PoolVector<uint8_t> *>(_data._mem) = *reinterpret_cast<const PoolVector<uint8_t> *>(p_variant._data._mem); + } break; + case POOL_INT_ARRAY: { + + *reinterpret_cast<PoolVector<int> *>(_data._mem) = *reinterpret_cast<const PoolVector<int> *>(p_variant._data._mem); + } break; + case POOL_REAL_ARRAY: { + + *reinterpret_cast<PoolVector<real_t> *>(_data._mem) = *reinterpret_cast<const PoolVector<real_t> *>(p_variant._data._mem); + } break; + case POOL_STRING_ARRAY: { + + *reinterpret_cast<PoolVector<String> *>(_data._mem) = *reinterpret_cast<const PoolVector<String> *>(p_variant._data._mem); + } break; + case POOL_VECTOR2_ARRAY: { + + *reinterpret_cast<PoolVector<Vector2> *>(_data._mem) = *reinterpret_cast<const PoolVector<Vector2> *>(p_variant._data._mem); + } break; + case POOL_VECTOR3_ARRAY: { + + *reinterpret_cast<PoolVector<Vector3> *>(_data._mem) = *reinterpret_cast<const PoolVector<Vector3> *>(p_variant._data._mem); + } break; + case POOL_COLOR_ARRAY: { + + *reinterpret_cast<PoolVector<Color> *>(_data._mem) = *reinterpret_cast<const PoolVector<Color> *>(p_variant._data._mem); + } break; + default: {} + } } Variant::Variant(const IP_Address &p_address) { diff --git a/core/variant.h b/core/variant.h index edc86dedd4..5ea540a63f 100644 --- a/core/variant.h +++ b/core/variant.h @@ -390,7 +390,7 @@ public: uint32_t hash() const; bool hash_compare(const Variant &p_variant) const; - bool booleanize(bool &valid) const; + bool booleanize() const; void static_assign(const Variant &p_variant); static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index d67466556d..5d47936679 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -143,56 +143,13 @@ Variant::operator bool() const { - bool b; - return booleanize(b); + return booleanize(); } -bool Variant::booleanize(bool &r_valid) const { - - r_valid = true; - switch (type) { - case NIL: - return false; - case BOOL: - return _data._bool; - case INT: - return _data._int; - case REAL: - return _data._real; - case STRING: - return (*reinterpret_cast<const String *>(_data._mem)) != ""; - case VECTOR2: - case RECT2: - case TRANSFORM2D: - case VECTOR3: - case PLANE: - case RECT3: - case QUAT: - case BASIS: - case TRANSFORM: - case COLOR: - case _RID: - return (*reinterpret_cast<const RID *>(_data._mem)).is_valid(); - case OBJECT: - return _get_obj().obj; - case NODE_PATH: - return (*reinterpret_cast<const NodePath *>(_data._mem)) != NodePath(); - case DICTIONARY: - case ARRAY: - case POOL_BYTE_ARRAY: - case POOL_INT_ARRAY: - case POOL_REAL_ARRAY: - case POOL_STRING_ARRAY: - case POOL_VECTOR2_ARRAY: - case POOL_VECTOR3_ARRAY: - case POOL_COLOR_ARRAY: - r_valid = false; - return false; - default: { - } - } - - return false; +// We consider all unitialized or empty types to be false based on the type's +// zeroiness. +bool Variant::booleanize() const { + return !is_zero(); } #define _RETURN(m_what) \ @@ -403,12 +360,6 @@ bool Variant::booleanize(bool &r_valid) const { _RETURN(sum); \ } -#define DEFAULT_OP_FAIL(m_name) \ - case m_name: { \ - r_valid = false; \ - return; \ - } - void Variant::evaluate(const Operator &p_op, const Variant &p_a, const Variant &p_b, Variant &r_ret, bool &r_valid) { @@ -421,11 +372,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, if (p_b.type == NIL) _RETURN(true); if (p_b.type == OBJECT) _RETURN(p_b._get_obj().obj == NULL); - _RETURN(false); + _RETURN_FAIL; } CASE_TYPE(math, OP_EQUAL, BOOL) { - if (p_b.type != BOOL) _RETURN(false); + if (p_b.type != BOOL) + _RETURN_FAIL; _RETURN(p_a._data._bool == p_b._data._bool); } @@ -434,11 +386,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN((p_a._get_obj().obj == p_b._get_obj().obj)); if (p_b.type == NIL) _RETURN(p_a._get_obj().obj == NULL); + _RETURN_FAIL; } CASE_TYPE(math, OP_EQUAL, DICTIONARY) { if (p_b.type != DICTIONARY) - _RETURN(false); + _RETURN_FAIL; const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem); const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem); @@ -448,7 +401,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_EQUAL, ARRAY) { if (p_b.type != ARRAY) - _RETURN(false); + _RETURN_FAIL; const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); @@ -495,11 +448,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, if (p_b.type == NIL) _RETURN(false); if (p_b.type == OBJECT) _RETURN(p_b._get_obj().obj != NULL); - _RETURN(true); + _RETURN_FAIL; } CASE_TYPE(math, OP_NOT_EQUAL, BOOL) { - if (p_b.type != BOOL) _RETURN(true); + if (p_b.type != BOOL) + _RETURN_FAIL; _RETURN(p_a._data._bool != p_b._data._bool); } @@ -508,11 +462,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN((p_a._get_obj().obj != p_b._get_obj().obj)); if (p_b.type == NIL) _RETURN(p_a._get_obj().obj != NULL); + _RETURN_FAIL; } CASE_TYPE(math, OP_NOT_EQUAL, DICTIONARY) { if (p_b.type != DICTIONARY) - _RETURN(true); + _RETURN_FAIL; const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem); const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem); @@ -522,7 +477,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_NOT_EQUAL, ARRAY) { if (p_b.type != ARRAY) - _RETURN(true); + _RETURN_FAIL; const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); @@ -580,13 +535,14 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, } CASE_TYPE(math, OP_LESS, OBJECT) { - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj < p_b._get_obj().obj)); + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj < p_b._get_obj().obj)); } CASE_TYPE(math, OP_LESS, ARRAY) { if (p_b.type != ARRAY) - _RETURN(false); + _RETURN_FAIL; const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); @@ -633,8 +589,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_LESS_EQUAL, p_a.type) { CASE_TYPE(math, OP_LESS_EQUAL, OBJECT) { - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj <= p_b._get_obj().obj)); + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj <= p_b._get_obj().obj)); } DEFAULT_OP_NUM(math, OP_LESS_EQUAL, INT, <=, _int); @@ -682,13 +639,14 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, } CASE_TYPE(math, OP_GREATER, OBJECT) { - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj > p_b._get_obj().obj)); + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj > p_b._get_obj().obj)); } CASE_TYPE(math, OP_GREATER, ARRAY) { if (p_b.type != ARRAY) - _RETURN(false); + _RETURN_FAIL; const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); @@ -735,8 +693,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_GREATER_EQUAL, p_a.type) { CASE_TYPE(math, OP_GREATER_EQUAL, OBJECT) { - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj >= p_b._get_obj().obj)); + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj >= p_b._get_obj().obj)); } DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, INT, >=, _int); @@ -771,10 +730,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_ADD, p_a.type) { CASE_TYPE(math, OP_ADD, ARRAY) { - if (p_a.type != p_b.type) { - r_valid = false; - return; - } + if (p_a.type != p_b.type) + _RETURN_FAIL; + const Array &array_a = *reinterpret_cast<const Array *>(p_a._data._mem); const Array &array_b = *reinterpret_cast<const Array *>(p_b._data._mem); Array sum; @@ -853,65 +811,54 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_MULTIPLY, p_a.type) { CASE_TYPE(math, OP_MULTIPLY, TRANSFORM2D) { - if (p_b.type == TRANSFORM2D) { - _RETURN(*p_a._data._transform2d * *p_b._data._transform2d); - }; - if (p_b.type == VECTOR2) { - _RETURN(p_a._data._transform2d->xform(*(const Vector2 *)p_b._data._mem)); - }; - r_valid = false; - return; + switch (p_b.type) { + case TRANSFORM2D: { + _RETURN(*p_a._data._transform2d * *p_b._data._transform2d); + } + case VECTOR2: { + _RETURN(p_a._data._transform2d->xform(*(const Vector2 *)p_b._data._mem)); + } + default: _RETURN_FAIL; + } } CASE_TYPE(math, OP_MULTIPLY, QUAT) { switch (p_b.type) { case VECTOR3: { - _RETURN(reinterpret_cast<const Quat *>(p_a._data._mem)->xform(*(const Vector3 *)p_b._data._mem)); - } break; + } case QUAT: { - _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * *reinterpret_cast<const Quat *>(p_b._data._mem)); - } break; + } case REAL: { _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * p_b._data._real); - } break; - default: {} - }; - r_valid = false; - return; + } + default: _RETURN_FAIL; + } } CASE_TYPE(math, OP_MULTIPLY, BASIS) { switch (p_b.type) { case VECTOR3: { - _RETURN(p_a._data._basis->xform(*(const Vector3 *)p_b._data._mem)); - }; + } case BASIS: { - _RETURN(*p_a._data._basis * *p_b._data._basis); - }; - default: {} - }; - r_valid = false; - return; + } + default: _RETURN_FAIL; + } } CASE_TYPE(math, OP_MULTIPLY, TRANSFORM) { switch (p_b.type) { case VECTOR3: { - _RETURN(p_a._data._transform->xform(*(const Vector3 *)p_b._data._mem)); - }; + } case TRANSFORM: { - _RETURN(*p_a._data._transform * *p_b._data._transform); - }; - default: {} - }; - r_valid = false; - return; + } + default: _RETURN_FAIL; + } } DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, INT, *, _int); @@ -943,18 +890,15 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_DIVIDE, p_a.type) { CASE_TYPE(math, OP_DIVIDE, QUAT) { - if (p_b.type != REAL) { - r_valid = false; - return; - } + if (p_b.type != REAL) + _RETURN_FAIL; #ifdef DEBUG_ENABLED if (p_b._data._real == 0) { r_valid = false; _RETURN("Division By Zero"); } #endif - _RETURN( - *reinterpret_cast<const Quat *>(p_a._data._mem) / p_b._data._real); + _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) / p_b._data._real); } DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, INT, _int); @@ -1054,9 +998,8 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_MODULE, p_a.type) { CASE_TYPE(math, OP_MODULE, INT) { - if (p_b.type != INT) { + if (p_b.type != INT) _RETURN_FAIL; - } #ifdef DEBUG_ENABLED if (p_b._data._int == 0) { r_valid = false; @@ -1067,15 +1010,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, } CASE_TYPE(math, OP_MODULE, STRING) { - const String *format = - reinterpret_cast<const String *>(p_a._data._mem); + const String *format = reinterpret_cast<const String *>(p_a._data._mem); String result; bool error; if (p_b.type == ARRAY) { // e.g. "frog %s %d" % ["fish", 12] - const Array *args = - reinterpret_cast<const Array *>(p_b._data._mem); + const Array *args = reinterpret_cast<const Array *>(p_b._data._mem); result = format->sprintf(*args, &error); } else { // e.g. "frog %d" % 12 @@ -1127,6 +1068,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; _RETURN(p_a._data._int << p_b._data._int); } + CASE_TYPE_ALL_BUT_INT(math, OP_SHIFT_LEFT) _RETURN_FAIL; } @@ -1137,6 +1079,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; _RETURN(p_a._data._int >> p_b._data._int); } + CASE_TYPE_ALL_BUT_INT(math, OP_SHIFT_RIGHT) _RETURN_FAIL; } @@ -1147,6 +1090,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; _RETURN(p_a._data._int & p_b._data._int); } + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_AND) _RETURN_FAIL; } @@ -1157,6 +1101,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; _RETURN(p_a._data._int | p_b._data._int); } + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_OR) _RETURN_FAIL; } @@ -1167,6 +1112,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; _RETURN(p_a._data._int ^ p_b._data._int); } + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_XOR) _RETURN_FAIL; } @@ -1175,18 +1121,15 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_BIT_NEGATE, INT) { _RETURN(~p_a._data._int); } + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_NEGATE) _RETURN_FAIL; } SWITCH_OP(math, OP_AND, p_a.type) { CASE_TYPE_ALL(math, OP_AND) { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - bool r = p_b.booleanize(r_valid); - if (!r_valid) - return; + bool l = p_a.booleanize(); + bool r = p_b.booleanize(); _RETURN(l && r); } @@ -1194,12 +1137,8 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_OR, p_a.type) { CASE_TYPE_ALL(math, OP_OR) { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - bool r = p_b.booleanize(r_valid); - if (!r_valid) - return; + bool l = p_a.booleanize(); + bool r = p_b.booleanize(); _RETURN(l || r); } @@ -1207,12 +1146,8 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_XOR, p_a.type) { CASE_TYPE_ALL(math, OP_XOR) { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - bool r = p_b.booleanize(r_valid); - if (!r_valid) - return; + bool l = p_a.booleanize(); + bool r = p_b.booleanize(); _RETURN((l || r) && !(l && r)); } @@ -1220,9 +1155,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_NOT, p_a.type) { CASE_TYPE_ALL(math, OP_NOT) { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; + bool l = p_a.booleanize(); _RETURN(!l); } } @@ -2676,7 +2609,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { return true; } break; case VECTOR2: { - int64_t to = reinterpret_cast<const Vector3 *>(_data._mem)->y; + int64_t to = reinterpret_cast<const Vector2 *>(_data._mem)->y; int64_t idx = r_iter; idx++; |