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