diff --git a/compile_linux.sh b/compile_linux.sh index 5a441fb..9f4fc43 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -27,6 +27,7 @@ ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/safe_refcount.cpp ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/transform_2d.cpp -o sfw/core/transform_2d.o ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/transform.cpp -o sfw/core/transform.o ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/ustring.cpp -o sfw/core/ustring.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/string_name.cpp -o sfw/core/string_name.o ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/vector2.cpp -o sfw/core/vector2.o ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/vector2i.cpp -o sfw/core/vector2i.o ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -c sfw/core/vector3.cpp -o sfw/core/vector3.o @@ -67,7 +68,8 @@ ccache g++ -Wall -lm -ldl -lpthread -lX11 -D_REENTRANT -g sfw/core/aabb.o sfw/c sfw/core/face3.o sfw/core/logger.o sfw/core/math_funcs.o \ sfw/core/memory.o sfw/core/pcg.o sfw/core/plane.o sfw/core/projection.o sfw/core/quaternion.o sfw/core/random_pcg.o \ sfw/core/rect2.o sfw/core/rect2i.o sfw/core/safe_refcount.o sfw/core/transform_2d.o sfw/core/transform.o \ - sfw/core/ustring.o sfw/core/vector2.o sfw/core/vector2i.o sfw/core/vector3.o \ + sfw/core/ustring.o sfw/core/string_name.o \ + sfw/core/vector2.o sfw/core/vector2i.o sfw/core/vector3.o \ sfw/core/vector3i.o sfw/core/vector4.o sfw/core/vector4i.o \ sfw/core/pool_vector.o sfw/core/pool_allocator.o sfw/core/mutex.o sfw/core/stime.o \ sfw/render_core/application.o sfw/render_core/scene.o sfw/render_core/window.o \ diff --git a/sfw/core/error_macros.h b/sfw/core/error_macros.h index 11cb2d5..925cf37 100644 --- a/sfw/core/error_macros.h +++ b/sfw/core/error_macros.h @@ -234,10 +234,21 @@ _FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3, E } else \ ((void)0) -#define CRASH_MSG(msg) \ +#define CRASH_COND_MSG(cond, msg) \ + if (cond) { \ + RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \ + GENERATE_TRAP \ + } else \ + ((void)0) + +#define CRASH_MSG(msg) \ RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \ GENERATE_TRAP +#define CRASH_NOW(msg) \ + RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "CRASH!"); \ + GENERATE_TRAP + /** * This should be a 'free' assert for program flow and should not be needed in any releases, * only used in dev builds. diff --git a/sfw/core/hash_map.h b/sfw/core/hash_map.h index 674634e..f303af7 100644 --- a/sfw/core/hash_map.h +++ b/sfw/core/hash_map.h @@ -35,8 +35,9 @@ #include "hashfuncs.h" #include "paged_allocator.h" #include "pair.h" -#include "core/math/math_funcs.h" +#include "math_funcs.h" #include "memory.h" +#include "list.h" /** * A HashMap implementation that uses open addressing with Robin Hood hashing. diff --git a/sfw/core/hash_set.h b/sfw/core/hash_set.h index 8cc5f97..d72403a 100644 --- a/sfw/core/hash_set.h +++ b/sfw/core/hash_set.h @@ -34,7 +34,7 @@ #include "hash_map.h" #include "hashfuncs.h" -#include "core/math/math_funcs.h" +#include "math_funcs.h" #include "memory.h" /** diff --git a/sfw/core/hashfuncs.h b/sfw/core/hashfuncs.h index 00cef3a..e94bae8 100644 --- a/sfw/core/hashfuncs.h +++ b/sfw/core/hashfuncs.h @@ -32,22 +32,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rid.h" -#include "core/math/aabb.h" -#include "core/math/math_defs.h" -#include "core/math/math_funcs.h" -#include "core/math/rect2.h" -#include "core/math/rect2i.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/string/node_path.h" -#include "core/string/string_name.h" -#include "core/string/ustring.h" +#include "aabb.h" +#include "math_defs.h" +#include "math_funcs.h" +#include "rect2.h" +#include "rect2i.h" +#include "vector2.h" +#include "vector2i.h" +#include "vector3.h" +#include "vector3i.h" +#include "vector4.h" +#include "vector4i.h" +#include "string_name.h" +#include "ustring.h" #include "core/typedefs.h" /** @@ -321,10 +318,7 @@ struct HashMapHasherDefault { static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); } static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); } static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); } - static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } - static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } - //static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } 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_one_uint64(p_int); } diff --git a/sfw/core/spin_lock.h b/sfw/core/spin_lock.h new file mode 100644 index 0000000..b014d80 --- /dev/null +++ b/sfw/core/spin_lock.h @@ -0,0 +1,52 @@ +#ifndef SPIN_LOCK_H +#define SPIN_LOCK_H + +/*************************************************************************/ +/* spin_lock.h */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/typedefs.h" + +#include + +class SpinLock { + std::atomic_flag locked = ATOMIC_FLAG_INIT; + +public: + _ALWAYS_INLINE_ void lock() { + while (locked.test_and_set(std::memory_order_acquire)) { + ; + } + } + _ALWAYS_INLINE_ void unlock() { + locked.clear(std::memory_order_release); + } +}; +#endif // SPIN_LOCK_H diff --git a/sfw/core/string_name.cpp b/sfw/core/string_name.cpp new file mode 100644 index 0000000..13a9b3c --- /dev/null +++ b/sfw/core/string_name.cpp @@ -0,0 +1,544 @@ +/*************************************************************************/ +/* string_name.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "string_name.h" + +StaticCString StaticCString::create(const char *p_ptr) { + StaticCString scs; + scs.ptr = p_ptr; + return scs; +} + +StringName::_Data *StringName::_table[STRING_TABLE_LEN]; + +StringName _scs_create(const char *p_chr, bool p_static) { + return (p_chr[0] ? StringName(StaticCString::create(p_chr), p_static) : StringName()); +} + +bool StringName::configured = false; +Mutex StringName::lock; + +#ifdef DEBUG_ENABLED +bool StringName::debug_stringname = false; +#endif + +void StringName::setup() { + ERR_FAIL_COND(configured); + for (int i = 0; i < STRING_TABLE_LEN; i++) { + _table[i] = nullptr; + } + configured = true; +} + +void StringName::cleanup() { + lock.lock(); + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + Vector<_Data *> data; + for (int i = 0; i < STRING_TABLE_LEN; i++) { + _Data *d = _table[i]; + while (d) { + data.push_back(d); + d = d->next; + } + } + + print_line("\nStringName reference ranking (from most to least referenced):\n"); + + data.sort_custom(); + int unreferenced_stringnames = 0; + int rarely_referenced_stringnames = 0; + for (int i = 0; i < data.size(); i++) { + print_line(itos(i + 1) + ": " + data[i]->get_name() + " - " + itos(data[i]->debug_references)); + if (data[i]->debug_references == 0) { + unreferenced_stringnames += 1; + } else if (data[i]->debug_references < 5) { + rarely_referenced_stringnames += 1; + } + } + + print_line(vformat("\nOut of %d StringNames, %d StringNames were never referenced during this run (0 times) (%.2f%%).", data.size(), unreferenced_stringnames, unreferenced_stringnames / float(data.size()) * 100)); + print_line(vformat("Out of %d StringNames, %d StringNames were rarely referenced during this run (1-4 times) (%.2f%%).", data.size(), rarely_referenced_stringnames, rarely_referenced_stringnames / float(data.size()) * 100)); + } +#endif + + //int lost_strings = 0; + for (int i = 0; i < STRING_TABLE_LEN; i++) { + while (_table[i]) { + _Data *d = _table[i]; + + /* + if (d->static_count.get() != d->refcount.get()) { + lost_strings++; + if (OS::get_singleton()->is_stdout_verbose()) { + if (d->cname) { + print_line("Orphan StringName: " + String(d->cname)); + } else { + print_line("Orphan StringName: " + String(d->name)); + } + } + } + */ + + _table[i] = _table[i]->next; + memdelete(d); + } + } + + /* + if (lost_strings) { + print_verbose("StringName: " + itos(lost_strings) + " unclaimed string names at exit."); + } + */ + + configured = false; + + lock.unlock(); +} + +void StringName::unref() { + ERR_FAIL_COND(!configured); + + if (_data && _data->refcount.unref()) { + lock.lock(); + + if (_data->static_count.get() > 0) { + if (_data->cname) { + ERR_PRINT("BUG: Unreferenced static string to 0: " + String(_data->cname)); + } else { + ERR_PRINT("BUG: Unreferenced static string to 0: " + String(_data->name)); + } + } + + if (_data->prev) { + _data->prev->next = _data->next; + } else { + if (_table[_data->idx] != _data) { + ERR_PRINT("BUG!"); + } + + _table[_data->idx] = _data->next; + } + + if (_data->next) { + _data->next->prev = _data->prev; + } + + memdelete(_data); + lock.unlock(); + } + + _data = nullptr; +} + +bool StringName::operator==(const String &p_name) const { + if (!_data) { + return (p_name.length() == 0); + } + + return (_data->get_name() == p_name); +} + +bool StringName::operator==(const char *p_name) const { + if (!_data) { + return (p_name[0] == 0); + } + + return (_data->get_name() == p_name); +} + +bool StringName::operator!=(const String &p_name) const { + return !(operator==(p_name)); +} + +bool StringName::operator!=(const StringName &p_name) const { + // the real magic of all this mess happens here. + // this is why path comparisons are very fast + return _data != p_name._data; +} + +void StringName::operator=(const StringName &p_name) { + if (this == &p_name) { + return; + } + + unref(); + + if (p_name._data && p_name._data->refcount.ref()) { + _data = p_name._data; + } +} + +StringName::StringName(const StringName &p_name) { + _data = nullptr; + + ERR_FAIL_COND(!configured); + + if (p_name._data && p_name._data->refcount.ref()) { + _data = p_name._data; + } +} + +StringName::StringName(const char *p_name, bool p_static) { + _data = nullptr; + + ERR_FAIL_COND(!configured); + + if (!p_name || p_name[0] == 0) { + return; //empty, ignore + } + + lock.lock(); + + uint32_t hash = String::hash(p_name); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _data = _table[idx]; + + while (_data) { + // compare hash first + if (_data->hash == hash && _data->get_name() == p_name) { + break; + } + _data = _data->next; + } + + if (_data) { + if (_data->refcount.ref()) { + // exists + if (p_static) { + _data->static_count.increment(); + } + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + _data->debug_references++; + } +#endif + + lock.unlock(); + return; + } + } + + _data = memnew(_Data); + _data->name = p_name; + _data->refcount.init(); + _data->static_count.set(p_static ? 1 : 0); + _data->hash = hash; + _data->idx = idx; + _data->cname = NULL; + _data->next = _table[idx]; + _data->prev = NULL; + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + // Keep in memory, force static. + _data->refcount.ref(); + _data->static_count.increment(); + } +#endif + + if (_table[idx]) { + _table[idx]->prev = _data; + } + + _table[idx] = _data; + + lock.unlock(); +} + +StringName::StringName(const StaticCString &p_static_string, bool p_static) { + _data = NULL; + + ERR_FAIL_COND(!configured); + + ERR_FAIL_COND(!p_static_string.ptr || !p_static_string.ptr[0]); + + lock.lock(); + + uint32_t hash = String::hash(p_static_string.ptr); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _data = _table[idx]; + + while (_data) { + // compare hash first + if (_data->hash == hash && _data->get_name() == p_static_string.ptr) { + break; + } + _data = _data->next; + } + + if (_data) { + if (_data->refcount.ref()) { + // exists + if (p_static) { + _data->static_count.increment(); + } + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + _data->debug_references++; + } +#endif + + lock.unlock(); + return; + } + } + + _data = memnew(_Data); + + _data->refcount.init(); + _data->static_count.set(p_static ? 1 : 0); + _data->hash = hash; + _data->idx = idx; + _data->cname = p_static_string.ptr; + _data->next = _table[idx]; + _data->prev = NULL; + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + // Keep in memory, force static. + _data->refcount.ref(); + _data->static_count.increment(); + } +#endif + + if (_table[idx]) { + _table[idx]->prev = _data; + } + + _table[idx] = _data; + + lock.unlock(); +} + +StringName::StringName(const String &p_name, bool p_static) { + _data = nullptr; + + ERR_FAIL_COND(!configured); + + if (p_name.empty()) { + return; + } + + lock.lock(); + + uint32_t hash = p_name.hash(); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _data = _table[idx]; + + while (_data) { + if (_data->hash == hash && _data->get_name() == p_name) { + break; + } + + _data = _data->next; + } + + if (_data) { + if (_data->refcount.ref()) { + // exists + if (p_static) { + _data->static_count.increment(); + } + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + _data->debug_references++; + } +#endif + + lock.unlock(); + return; + } + } + + _data = memnew(_Data); + _data->name = p_name; + _data->refcount.init(); + _data->static_count.set(p_static ? 1 : 0); + _data->hash = hash; + _data->idx = idx; + _data->cname = NULL; + _data->next = _table[idx]; + _data->prev = NULL; + +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + // Keep in memory, force static. + _data->refcount.ref(); + _data->static_count.increment(); + } +#endif + + if (_table[idx]) { + _table[idx]->prev = _data; + } + + _table[idx] = _data; + + lock.unlock(); +} + +StringName StringName::search(const char *p_name) { + ERR_FAIL_COND_V(!configured, StringName()); + + ERR_FAIL_COND_V(!p_name, StringName()); + if (!p_name[0]) { + return StringName(); + } + + lock.lock(); + + uint32_t hash = String::hash(p_name); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _Data *_data = _table[idx]; + + while (_data) { + // compare hash first + if (_data->hash == hash && _data->get_name() == p_name) { + break; + } + _data = _data->next; + } + + if (_data && _data->refcount.ref()) { +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + _data->debug_references++; + } +#endif + + lock.unlock(); + + return StringName(_data); + } + + lock.unlock(); + return StringName(); //does not exist +} + +StringName StringName::search(const CharType *p_name) { + ERR_FAIL_COND_V(!configured, StringName()); + + ERR_FAIL_COND_V(!p_name, StringName()); + if (!p_name[0]) { + return StringName(); + } + + lock.lock(); + + uint32_t hash = String::hash(p_name); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _Data *_data = _table[idx]; + + while (_data) { + // compare hash first + if (_data->hash == hash && _data->get_name() == p_name) { + break; + } + + _data = _data->next; + } + + if (_data && _data->refcount.ref()) { + lock.unlock(); + return StringName(_data); + } + + lock.unlock(); + return StringName(); //does not exist +} +StringName StringName::search(const String &p_name) { + ERR_FAIL_COND_V(p_name == "", StringName()); + + lock.lock(); + + uint32_t hash = p_name.hash(); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _Data *_data = _table[idx]; + + while (_data) { + // compare hash first + if (_data->hash == hash && p_name == _data->get_name()) { + break; + } + + _data = _data->next; + } + + if (_data && _data->refcount.ref()) { +#ifdef DEBUG_ENABLED + if (unlikely(debug_stringname)) { + _data->debug_references++; + } +#endif + lock.unlock(); + return StringName(_data); + } + + lock.unlock(); + return StringName(); //does not exist +} + +StringName::StringName() { + _data = nullptr; +} + +/* +bool operator==(const String &p_name, const StringName &p_string_name) { + return p_name == p_string_name.operator String(); +} +bool operator!=(const String &p_name, const StringName &p_string_name) { + return p_name != p_string_name.operator String(); +} + +bool operator==(const char *p_name, const StringName &p_string_name) { + return p_name == p_string_name.operator String(); +} +bool operator!=(const char *p_name, const StringName &p_string_name) { + return p_name != p_string_name.operator String(); +} +*/ diff --git a/sfw/core/string_name.h b/sfw/core/string_name.h new file mode 100644 index 0000000..74d08fc --- /dev/null +++ b/sfw/core/string_name.h @@ -0,0 +1,231 @@ +#ifndef STRING_NAME_H +#define STRING_NAME_H + +/*************************************************************************/ +/* string_name.h */ +/*************************************************************************/ +/* This file is part of: */ +/* PANDEMONIUM ENGINE */ +/* https://github.com/Relintai/pandemonium_engine */ +/*************************************************************************/ +/* Copyright (c) 2022-present Péter Magyar. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "mutex.h" +#include "safe_refcount.h" +#include "ustring.h" + +struct StaticCString { + const char *ptr; + static StaticCString create(const char *p_ptr); +}; + +class StringName { + enum { + STRING_TABLE_BITS = 14, + STRING_TABLE_LEN = 1 << STRING_TABLE_BITS, + STRING_TABLE_MASK = STRING_TABLE_LEN - 1 + }; + + struct _Data { + SafeRefCount refcount; + SafeNumeric static_count; + const char *cname; + String name; + +#ifdef DEBUG_ENABLED + uint32_t debug_references; +#endif + + String get_name() const { + return cname ? String(cname) : name; + } + + int idx; + uint32_t hash; + _Data *prev; + _Data *next; + + _Data() { +#ifdef DEBUG_ENABLED + debug_references = 0; +#endif + cname = nullptr; + prev = nullptr; + next = nullptr; + idx = 0; + hash = 0; + } + }; + + static _Data *_table[STRING_TABLE_LEN]; + + _Data *_data; + + union _HashUnion { + _Data *ptr; + uint32_t hash; + + _HashUnion() { + ptr = nullptr; + } + }; + + void unref(); + friend void register_core_types(); + friend void unregister_core_types(); + + static Mutex lock; + static void setup(); + static void cleanup(); + static bool configured; +#ifdef DEBUG_ENABLED + struct DebugSortReferences { + bool operator()(const _Data *p_left, const _Data *p_right) const { + return p_left->debug_references > p_right->debug_references; + } + }; + + static bool debug_stringname; +#endif + + StringName(_Data *p_data) { + _data = p_data; + } + +public: + operator const void *() const { + return (_data && (_data->cname || !_data->name.empty())) ? (void *)1 : nullptr; + } + + bool operator==(const String &p_name) const; + bool operator==(const char *p_name) const; + bool operator!=(const String &p_name) const; + + _FORCE_INLINE_ bool is_node_unique_name() const { + if (!_data) { + return false; + } + + if (_data->cname != nullptr) { + return _data->cname[0] == '%'; + } else { + return _data->name[0] == '%'; + } + } + + _FORCE_INLINE_ bool operator<(const StringName &p_name) const { + return _data < p_name._data; + } + _FORCE_INLINE_ bool operator==(const StringName &p_name) const { + // the real magic of all this mess happens here. + // this is why path comparisons are very fast + return _data == p_name._data; + } + _FORCE_INLINE_ uint32_t hash() const { + if (_data) { + return _data->hash; + } else { + return 0; + } + } + _FORCE_INLINE_ const void *data_unique_pointer() const { + return (void *)_data; + } + bool operator!=(const StringName &p_name) const; + + _FORCE_INLINE_ operator String() const { + if (_data) { + if (_data->cname) { + return String(_data->cname); + } else { + return _data->name; + } + } + + return String(); + } + + static StringName search(const char *p_name); + static StringName search(const CharType *p_name); + static StringName search(const String &p_name); + + struct AlphCompare { + _FORCE_INLINE_ bool operator()(const StringName &l, const StringName &r) const { + const char *l_cname = l._data ? l._data->cname : ""; + const char *r_cname = r._data ? r._data->cname : ""; + + if (l_cname) { + if (r_cname) { + return is_str_less(l_cname, r_cname); + } else { + return is_str_less(l_cname, r._data->name.ptr()); + } + } else { + if (r_cname) { + return is_str_less(l._data->name.ptr(), r_cname); + } else { + return is_str_less(l._data->name.ptr(), r._data->name.ptr()); + } + } + } + }; + + void operator=(const StringName &p_name); + StringName(const char *p_name, bool p_static = false); + StringName(const StringName &p_name); + StringName(const String &p_name, bool p_static = false); + StringName(const StaticCString &p_static_string, bool p_static = false); + StringName(); + _FORCE_INLINE_ ~StringName() { + if (likely(configured) && _data) { //only free if configured + unref(); + } + } +}; + +/* +bool operator==(const String &p_name, const StringName &p_string_name); +bool operator!=(const String &p_name, const StringName &p_string_name); +bool operator==(const char *p_name, const StringName &p_string_name); +bool operator!=(const char *p_name, const StringName &p_string_name); +*/ + +StringName _scs_create(const char *p_chr, bool p_static = false); + +/* + * The SNAME macro is used to speed up StringName creation, as it allows caching it after the first usage in a very efficient way. + * It should NOT be used everywhere, but instead in places where high performance is required and the creation of a StringName + * can be costly. Places where it should be used are: + * - Control::get_theme_*( and Window::get_theme_*( functions. + * - emit_signal(,..) function + * - call_deferred(,..) function + * - Comparisons to a StringName in overridden _set and _get methods. + * + * Use in places that can be called hundreds of times per frame (or more) is recommended, but this situation is very rare. If in doubt, do not use. + */ + +//#define SNAME(m_arg) ([]() -> const StringName & { static StringName sname = _scs_create(m_arg, true); return sname; })() + +#endif // STRING_NAME_H diff --git a/sfw/render_core/image.cpp b/sfw/render_core/image.cpp index 7f38daa..9de2303 100644 --- a/sfw/render_core/image.cpp +++ b/sfw/render_core/image.cpp @@ -36,7 +36,7 @@ #include "memory.h" #include #include -#include +#include "hash_map.h" const char *Image::format_names[Image::FORMAT_MAX] = { "Lum8", // luminance @@ -1748,7 +1748,7 @@ void Image::create(const char **p_xpm) { Status status = READING_HEADER; int line = 0; - std::map colormap; + HashMap colormap; int colormap_size = 0; uint32_t pixel_size = 0; uint8_t *w_ptr; diff --git a/sfw/render_core/material.cpp b/sfw/render_core/material.cpp index a3de816..6ee3bef 100644 --- a/sfw/render_core/material.cpp +++ b/sfw/render_core/material.cpp @@ -9,7 +9,7 @@ void Material::bind() { shader = ShaderCache::get_singleton()->get_shader(get_material_id()); if (!shader) { - shader = new Shader(); + shader = memnew(Shader()); shader->set_vertex_shader_source(get_vertex_shader_source()); shader->set_fragment_shader_source(get_fragment_shader_source()); diff --git a/sfw/render_core/mesh.cpp b/sfw/render_core/mesh.cpp index c17d530..c83fe5d 100644 --- a/sfw/render_core/mesh.cpp +++ b/sfw/render_core/mesh.cpp @@ -64,18 +64,18 @@ void Mesh::upload() { glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices_vbo_size + normals_vbo_size + colors_vbo_size + uvs_vbo_size, NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, vertices_vbo_size, &vertices[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, vertices_vbo_size, vertices.ptr()); if (normals_vbo_size > 0) { - glBufferSubData(GL_ARRAY_BUFFER, vertices_vbo_size, normals_vbo_size, &normals[0]); + glBufferSubData(GL_ARRAY_BUFFER, vertices_vbo_size, normals_vbo_size, normals.ptr()); } if (colors_vbo_size > 0) { - glBufferSubData(GL_ARRAY_BUFFER, vertices_vbo_size + normals_vbo_size, colors_vbo_size, &colors[0]); + glBufferSubData(GL_ARRAY_BUFFER, vertices_vbo_size + normals_vbo_size, colors_vbo_size, colors.ptr()); } if (uvs_vbo_size > 0) { - glBufferSubData(GL_ARRAY_BUFFER, vertices_vbo_size + normals_vbo_size + colors_vbo_size, uvs_vbo_size, &uvs[0]); + glBufferSubData(GL_ARRAY_BUFFER, vertices_vbo_size + normals_vbo_size + colors_vbo_size, uvs_vbo_size, uvs.ptr()); } if (indices_vbo_size > 0) { @@ -84,7 +84,7 @@ void Mesh::upload() { } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_vbo_size, &indices[0], GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_vbo_size, indices.ptr(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } diff --git a/sfw/render_core/mesh.h b/sfw/render_core/mesh.h index 6f6e75c..b94331f 100644 --- a/sfw/render_core/mesh.h +++ b/sfw/render_core/mesh.h @@ -1,7 +1,7 @@ #ifndef MESH_H #define MESH_H -#include +#include "vector.h" #include #include "3rd_glad.h" @@ -34,11 +34,11 @@ public: int vertex_dimesions; - std::vector vertices; - std::vector normals; - std::vector colors; - std::vector uvs; - std::vector indices; + Vector vertices; + Vector normals; + Vector colors; + Vector uvs; + Vector indices; protected: uint32_t vertices_vbo_size; diff --git a/sfw/render_core/shader.cpp b/sfw/render_core/shader.cpp index 7d30cc4..6f08268 100644 --- a/sfw/render_core/shader.cpp +++ b/sfw/render_core/shader.cpp @@ -1,145 +1,145 @@ #include "shader.h" -#include #include +#include bool Shader::bind() { - if (current_shader != this) { - glUseProgram(program); + if (current_shader != this) { + glUseProgram(program); - current_shader = this; + current_shader = this; - return true; - } + return true; + } - return false; + return false; } void Shader::unbind() { - if (current_shader == this) { - glUseProgram(0); + if (current_shader == this) { + glUseProgram(0); - current_shader = NULL; - } + current_shader = NULL; + } } void Shader::compile() { - if (!program) { - program = glCreateProgram(); - } + if (!program) { + program = glCreateProgram(); + } - if (!vertex_shader) { - vertex_shader = glCreateShader(GL_VERTEX_SHADER); - } + if (!vertex_shader) { + vertex_shader = glCreateShader(GL_VERTEX_SHADER); + } - if (!fragment_shader) { - fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - } + if (!fragment_shader) { + fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + } - const GLchar **vertex_shader_source = get_vertex_shader_source(); + const GLchar **vertex_shader_source = get_vertex_shader_source(); - glShaderSource(vertex_shader, 1, vertex_shader_source, NULL); - glCompileShader(vertex_shader); + glShaderSource(vertex_shader, 1, vertex_shader_source, NULL); + glCompileShader(vertex_shader); - GLint shader_compiled = GL_FALSE; - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &shader_compiled); - if (shader_compiled != GL_TRUE) { - print_shader_errors(vertex_shader, "compiling Vertex Shader"); - return; - } + GLint shader_compiled = GL_FALSE; + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &shader_compiled); + if (shader_compiled != GL_TRUE) { + print_shader_errors(vertex_shader, "compiling Vertex Shader"); + return; + } - glAttachShader(program, vertex_shader); + glAttachShader(program, vertex_shader); + const GLchar **fragment_shader_source = get_fragment_shader_source(); - const GLchar **fragment_shader_source = get_fragment_shader_source(); + glShaderSource(fragment_shader, 1, fragment_shader_source, NULL); + glCompileShader(fragment_shader); - glShaderSource(fragment_shader, 1, fragment_shader_source, NULL); - glCompileShader(fragment_shader); + shader_compiled = GL_FALSE; + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &shader_compiled); + if (shader_compiled != GL_TRUE) { + print_shader_errors(fragment_shader, "compiling Fragment Shader"); + return; + } - shader_compiled = GL_FALSE; - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &shader_compiled); - if (shader_compiled != GL_TRUE) { - print_shader_errors(fragment_shader, "compiling Fragment Shader"); - return; - } + glAttachShader(program, fragment_shader); - glAttachShader(program, fragment_shader); + glBindAttribLocation(program, ATTRIBUTE_POSITION, "a_position"); + glBindAttribLocation(program, ATTRIBUTE_NORMAL, "a_normal"); + glBindAttribLocation(program, ATTRIBUTE_COLOR, "a_color"); + glBindAttribLocation(program, ATTRIBUTE_UV, "a_uv"); - glBindAttribLocation(program, ATTRIBUTE_POSITION, "a_position"); - glBindAttribLocation(program, ATTRIBUTE_NORMAL, "a_normal"); - glBindAttribLocation(program, ATTRIBUTE_COLOR, "a_color"); - glBindAttribLocation(program, ATTRIBUTE_UV, "a_uv"); + glLinkProgram(program); - glLinkProgram(program); - - GLint program_compiled = GL_FALSE; - glGetProgramiv(program, GL_LINK_STATUS, &program_compiled); - if (program_compiled != GL_TRUE) { - print_program_errors(program); - return; - } + GLint program_compiled = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &program_compiled); + if (program_compiled != GL_TRUE) { + print_program_errors(program); + return; + } } void Shader::destroy() { - glDeleteShader(vertex_shader); - glDeleteShader(fragment_shader); - glDeleteProgram(program); + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + glDeleteProgram(program); } const GLchar **Shader::get_vertex_shader_source() { - return vertex_shader_source; + return vertex_shader_source; } void Shader::set_vertex_shader_source(const GLchar **source) { - vertex_shader_source = source; + vertex_shader_source = source; } const GLchar **Shader::get_fragment_shader_source() { - return fragment_shader_source; + return fragment_shader_source; } void Shader::set_fragment_shader_source(const GLchar **source) { - fragment_shader_source = source; + fragment_shader_source = source; } void Shader::print_shader_errors(const GLuint p_program, const char *name) { - int max_length = 5000; - std::vector error_log(max_length); + int max_length = 5000; + Vector error_log; + error_log.resize(max_length); - glGetShaderInfoLog(p_program, max_length, &max_length, &error_log[0]); + glGetShaderInfoLog(p_program, max_length, &max_length, error_log.ptrw()); - printf("Error %s!\n", name); - printf("%s!\n", &error_log[0]); + printf("Error %s!\n", name); + printf("%s!\n", error_log.ptr()); } void Shader::print_program_errors(const GLuint p_program) { - if (glIsProgram(program)) { - int info_length = 0; - int max_length = 5000; + if (glIsProgram(program)) { + int info_length = 0; + int max_length = 5000; - glGetProgramiv(p_program, GL_INFO_LOG_LENGTH, &info_length); + glGetProgramiv(p_program, GL_INFO_LOG_LENGTH, &info_length); - char *info_log = new char[max_length]; + char *info_log = new char[max_length]; - glGetProgramInfoLog(p_program, max_length, &info_length, info_log); + glGetProgramInfoLog(p_program, max_length, &info_length, info_log); - if (info_length > 0) { - printf("%s\n", info_log); - } + if (info_length > 0) { + printf("%s\n", info_log); + } - delete[] info_log; - } else { - printf("print_program_errors: Not a program!\n"); - } + delete[] info_log; + } else { + printf("print_program_errors: Not a program!\n"); + } } Shader::Shader() { - vertex_shader = 0; - fragment_shader = 0; - program = 0; + vertex_shader = 0; + fragment_shader = 0; + program = 0; - vertex_shader_source = NULL; - fragment_shader_source = NULL; + vertex_shader_source = NULL; + fragment_shader_source = NULL; } Shader::~Shader() { - destroy(); + destroy(); } Shader *Shader::current_shader = NULL; @@ -147,25 +147,24 @@ Shader *Shader::current_shader = NULL; //Meyers singleton //thread safe ShaderCache *ShaderCache::get_singleton() { - static ShaderCache instance; + static ShaderCache instance; - return &instance; + return &instance; } Shader *ShaderCache::get_shader(const int id) { - return shaders[id]; + return shaders[id]; } void ShaderCache::add_shader(const int id, Shader *shader) { - shaders[id] = shader; + shaders[id] = shader; } ShaderCache::ShaderCache() { } ShaderCache::~ShaderCache() { - for (const std::pair n : shaders) { - delete n.second; - } + for (HashMap::Element *E = shaders.front(); E; E = E->next) { + memdelete(E->get()); + } - shaders.clear(); + shaders.clear(); } - diff --git a/sfw/render_core/shader.h b/sfw/render_core/shader.h index 99c3a25..a032a27 100644 --- a/sfw/render_core/shader.h +++ b/sfw/render_core/shader.h @@ -2,7 +2,7 @@ #define SHADER_H #include "3rd_glad.h" -#include +#include "hash_map.h" class Shader { public: @@ -53,7 +53,7 @@ public: ~ShaderCache(); protected: - std::unordered_map shaders; + HashMap shaders; }; #endif // SHADER_H diff --git a/sfw/render_objects/mesh_instance_2d.cpp b/sfw/render_objects/mesh_instance_2d.cpp index b64d406..13b89dc 100644 --- a/sfw/render_objects/mesh_instance_2d.cpp +++ b/sfw/render_objects/mesh_instance_2d.cpp @@ -17,7 +17,7 @@ void MeshInstance2D::render() { mesh->render(); - for (uint32_t i = 0; i < children.size(); ++i) { + for (int i = 0; i < children.size(); ++i) { MeshInstance2D * c = children[i]; if (c) { diff --git a/sfw/render_objects/mesh_instance_2d.h b/sfw/render_objects/mesh_instance_2d.h index d73259b..edd5b1a 100644 --- a/sfw/render_objects/mesh_instance_2d.h +++ b/sfw/render_objects/mesh_instance_2d.h @@ -1,7 +1,7 @@ #ifndef MESH_INSTACE_2D_H #define MESH_INSTACE_2D_H -#include +#include "vector.h" #include "material.h" #include "mesh.h" @@ -20,7 +20,7 @@ public: Transform2D transform; - std::vector children; + Vector children; }; #endif // MESH_INSTACE_H diff --git a/sfw/render_objects/mesh_instance_3d.cpp b/sfw/render_objects/mesh_instance_3d.cpp index 4b02c03..7067994 100644 --- a/sfw/render_objects/mesh_instance_3d.cpp +++ b/sfw/render_objects/mesh_instance_3d.cpp @@ -17,7 +17,7 @@ void MeshInstance3D::render() { mesh->render(); - for (uint32_t i = 0; i < children.size(); ++i) { + for (int i = 0; i < children.size(); ++i) { MeshInstance3D * c = children[i]; if (c) { diff --git a/sfw/render_objects/mesh_instance_3d.h b/sfw/render_objects/mesh_instance_3d.h index 5307266..afc67ca 100644 --- a/sfw/render_objects/mesh_instance_3d.h +++ b/sfw/render_objects/mesh_instance_3d.h @@ -1,7 +1,7 @@ #ifndef MESH_INSTACE_3D_H #define MESH_INSTACE_3D_H -#include +#include "vector.h" #include "object_3d.h" @@ -20,7 +20,7 @@ public: Material *material; Mesh *mesh; - std::vector children; + Vector children; }; #endif // MESH_INSTACE_H