From 0b76b06a1b71b0423e6ca6c7751311f6e5040dc4 Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Sun, 30 Nov 2025 20:58:56 -0500 Subject: [PATCH] - RTTI properties for types for iterators, indexing, and mapping --- CMakeLists.txt | 1 + include/fennec/containers/bitfield.h | 108 +++++++++++++++++++ include/fennec/langcpp/detail/_type_traits.h | 21 ++++ include/fennec/langcpp/type_traits.h | 28 +++++ include/fennec/rtti/type.h | 37 ++++++- include/fennec/rtti/type_data.h | 26 ++++- test/tests/test_rtti.h | 24 ++++- 7 files changed, 236 insertions(+), 9 deletions(-) create mode 100644 include/fennec/containers/bitfield.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b03c0f9..cd46d65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,7 @@ add_library(fennec STATIC include/fennec/langcpp/ranges.h include/fennec/langcpp/declval.h include/fennec/langcpp/detail/_declval.h + include/fennec/containers/bitfield.h ) add_dependencies(fennec metaprogramming fennec-dependencies) diff --git a/include/fennec/containers/bitfield.h b/include/fennec/containers/bitfield.h new file mode 100644 index 0000000..9c4ebc5 --- /dev/null +++ b/include/fennec/containers/bitfield.h @@ -0,0 +1,108 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \file bitfield.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + +#ifndef FENNEC_CONTAINERS_BITFIELD_H +#define FENNEC_CONTAINERS_BITFIELD_H + +#include +#include + +namespace fennec +{ + +/// +/// \brief Bitfield Container with basic Bit Ops +/// \tparam N The number of bits in the bitfield +template +struct bitfield { + static constexpr size_t size = N; + +public: + constexpr bitfield() + : _bytes() { + } + + constexpr bitfield(const bool (&arr)[N]) { + for (size_t i = 0; i < arr; ++i) { + this->store(i, arr[i]); + } + } + + template + constexpr bitfield(ArgsT&&...args) { + size_t i = 0; + (this->store(i++, fennec::forward(args)), ...); + } + + constexpr ~bitfield() = default; + + bool test(size_t i) const { + assertd(i < size, "Index out of Bounds!"); + size_t b = i / 8; + size_t o = i % 8; + return _bytes[b] & (1 << o); + } + + void set(size_t i) { + assertd(i < size, "Index out of Bounds!"); + size_t b = i / 8; + size_t o = i % 8; + _bytes[b] |= (1 << o); + } + + void clear(size_t i) { + assertd(i < size, "Index out of Bounds!"); + size_t b = i / 8; + size_t o = i % 8; + _bytes[b] &= ~(1 << o); + } + + void toggle(size_t i) { + assertd(i < size, "Index out of Bounds!"); + size_t b = i / 8; + size_t o = i % 8; + _bytes[b] ^= (1 << o); + } + + void store(size_t i, bool v) { + assertd(i < size, "Index out of Bounds!"); + size_t b = i / 8; + size_t o = i % 8; + (_bytes[b] &= ~((1 << o))) |= ((v << o)); + } + +private: + array _bytes; +}; + + +} + +#endif // FENNEC_CONTAINERS_BITFIELD_H \ No newline at end of file diff --git a/include/fennec/langcpp/detail/_type_traits.h b/include/fennec/langcpp/detail/_type_traits.h index c51fdb3..621d88c 100644 --- a/include/fennec/langcpp/detail/_type_traits.h +++ b/include/fennec/langcpp/detail/_type_traits.h @@ -102,6 +102,27 @@ namespace fennec::detail template auto _is_iterable(...) -> false_type; + + + template + auto _is_indexable(int) -> decltype( + declval()[0], + true_type{} + ); + + template + auto _is_indexable(...) -> false_type; + + + + template + auto _is_mappable(int) -> decltype( + declval()[declval()], + true_type{} + ); + + template + auto _is_mappable(...) -> false_type; } #endif // FENNEC_LANG_DETAIL_TYPE_TRAITS_H diff --git a/include/fennec/langcpp/type_traits.h b/include/fennec/langcpp/type_traits.h index 42e3f3f..dc9970c 100644 --- a/include/fennec/langcpp/type_traits.h +++ b/include/fennec/langcpp/type_traits.h @@ -697,6 +697,34 @@ template struct is_iterable : decltype(detail::_is_iterable(0)) { /// \tparam T type to check template constexpr bool_t is_iterable_v = is_iterable{}; +// fennec::is_complete ============================================================================================== + +/// +/// \brief check if type `T` is indexable +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_indexable : decltype(detail::_is_indexable(0)) {}; + +/// +/// \brief shorthand for `is_indexable::value` +/// \tparam T type to check +template constexpr bool_t is_indexable_v = is_indexable{}; + +// fennec::is_complete ============================================================================================== + +/// +/// \brief check if type `T` is mappable +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_mappable : decltype(detail::_is_mappable(0)) {}; + +/// +/// \brief shorthand for `is_mappable::value` +/// \tparam T type to check +template constexpr bool_t is_mappable_v = is_mappable{}; + // fennec::is_convertible ============================================================================================== /// diff --git a/include/fennec/rtti/type.h b/include/fennec/rtti/type.h index 13ea31e..132493c 100644 --- a/include/fennec/rtti/type.h +++ b/include/fennec/rtti/type.h @@ -42,29 +42,56 @@ struct type { /// /// \returns A const-qualified reference to a string containing the name of the type const string& name() const { - return _data->name; + static const string nullname = string("[none]"); + return _data ? _data->name : nullname; } /// /// \returns An integer value containing the unique universal identifier for the type uint64_t id() const { - return _data->uuid; + return _data ? _data->uuid : 0; } /// /// \returns A dynarray of all the super (base) types of the type dynarray supertypes() const { - return _data->supers; + return _data ? _data->supers : dynarray{}; } /// /// \returns A dynarray of all the sub (child) types of the type dynarray subtypes() const { - return _data->subs; + return _data ? _data->subs : dynarray{}; } + /// + /// \returns `true` if this is a complete type, false otherwise + bool is_complete() const { + return _data ? _data->properties.test(type_prop_complete) : false; + } + + /// + /// \returns `true` if this type fulfills the [C++11 range-initializer](https://en.cppreference.com/w/cpp/language/range-for.html), false otherwise bool is_iterable() const { - return _data->is_iterable; + return _data ? _data->properties.test(type_prop_iterable) : false; + } + + /// + /// \returns `true` if this type implements `operator[]` with a single parameter of integral type, false otherwise + bool is_indexable() const { + return _data ? _data->properties.test(type_prop_indexable) : false; + } + + /// + /// \returns `true` if this type implements `operator[]` with a single parameter of type `type::key_t` + bool is_mappable() const { + return _data ? _data->properties.test(type_prop_mappable) : false; + } + + /// + /// \returns The type used as a key for mappable types. + type key_type() const { + return _data ? _data->key_type : nullptr; } /// diff --git a/include/fennec/rtti/type_data.h b/include/fennec/rtti/type_data.h index 9a1acf7..ae1a748 100644 --- a/include/fennec/rtti/type_data.h +++ b/include/fennec/rtti/type_data.h @@ -31,6 +31,7 @@ #ifndef FENNEC_RTTI_TYPE_DATA_H #define FENNEC_RTTI_TYPE_DATA_H +#include #include #include #include @@ -42,7 +43,15 @@ namespace fennec { +enum type_prop_ { + type_prop_complete = 0, + type_prop_iterable, + type_prop_indexable, + type_prop_mappable, +}; + struct type_data { + uint64_t uuid; string name; @@ -50,12 +59,16 @@ struct type_data { dynarray supers; dynarray subs; - bool is_iterable; + // TODO: Change to bitfield + bitfield<8> properties; + + type_data* key_type; }; struct type_storage { private: template using _super_class_list = typename ClassT::super_class_list; + template using _key_t = typename ClassT::key_t; static dynarray>& _typelist() { static dynarray> typelist; @@ -75,7 +88,9 @@ private: .supers = type_storage::get_data(supers_t{}), .subs = {}, - .is_iterable = is_iterable_v + .properties = { is_complete_v, is_iterable_v, is_indexable_v, is_mappable_v }, + + .key_type = type_storage::get_data>(), }); for (type_data* t : res->supers) { @@ -87,7 +102,7 @@ private: public: template - static type_data* get_data() { + static type_data* get_data() requires(not is_void_v) { auto& typelist = _typelist(); uint64_t uuid = typeuuid(); @@ -102,6 +117,11 @@ public: return typelist[uuid].get(); } + template + static type_data* get_data() { + return nullptr; + } + template static dynarray get_data(typelist) { return { diff --git a/test/tests/test_rtti.h b/test/tests/test_rtti.h index 32a2d73..30ee499 100644 --- a/test/tests/test_rtti.h +++ b/test/tests/test_rtti.h @@ -56,11 +56,33 @@ inline void fennec_test_rtti() { fennec_test_run(string(detail::type_name()), string("int")); fennec_test_run(type::get(), type::get()); + fennec_test_spacer(1); + fennec_test_run(type::get().name(), string(detail::type_name())); fennec_test_run(type::get().supertypes()[0].name(), string(detail::type_name())); fennec_test_run(type::get().subtypes()[0].name(), string(detail::type_name())); - fennec_test_run(type::get>().is_iterable(), true); + fennec_test_spacer(1); + + fennec_test_run(type::get().is_complete(), true); + fennec_test_run(type::get().is_iterable(), false); + fennec_test_run(type::get().is_indexable(), false); + fennec_test_run(type::get().is_mappable(), false); + + fennec_test_spacer(1); + + fennec_test_run(type::get>().is_complete(), true); + fennec_test_run(type::get>().is_iterable(), true); + fennec_test_run(type::get>().is_indexable(), true); + fennec_test_run(type::get>().is_mappable(), false); + + fennec_test_spacer(1); + + fennec_test_run((type::get>().is_complete()), true); + fennec_test_run((type::get>().is_iterable()), true); + fennec_test_run((type::get>().is_indexable()), true); + fennec_test_run((type::get>().is_mappable()), true); + fennec_test_run((type::get>().key_type()), type::get()); }