diff --git a/doxy/Doxyfile b/doxy/Doxyfile
index df913ab..26d134c 100644
--- a/doxy/Doxyfile
+++ b/doxy/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = fennec
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.0.2
+PROJECT_NUMBER =
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/gdb/fennec/__init__.py b/gdb/fennec/__init__.py
index 93a75de..24b31b9 100644
--- a/gdb/fennec/__init__.py
+++ b/gdb/fennec/__init__.py
@@ -24,6 +24,7 @@ import gdb
from . import containers
from . import strings
from . import memory
+from . import utility
def register_printers(obj):
gdb.printing.register_pretty_printer(obj, containers.printer)
diff --git a/gdb/fennec/containers.py b/gdb/fennec/containers.py
index c007edb..2fad66c 100644
--- a/gdb/fennec/containers.py
+++ b/gdb/fennec/containers.py
@@ -19,6 +19,7 @@
import gdb
import re
from collections import deque
+from . import utility
# OPTIONAL =============================================================================================================
class OptionalPrinter:
@@ -34,7 +35,7 @@ class OptionalPrinter:
else:
return "{ empty }"
-# OPTIONAL =============================================================================================================
+# PAIR =================================================================================================================
class PairPrinter:
"""Print a fennec::optional"""
@@ -48,8 +49,28 @@ class PairPrinter:
return ("first", self.val['first']), ("second", self.val['second'])
+# TUPLE ================================================================================================================
+
+class TuplePrinter:
+ """Print a fennec::tuple"""
+
+ def __init__(self, val):
+ self.fields = val.type.fields()[0].type.fields()
+ self.elems = val
+ self.count = len(self.fields)
+
+ def to_string(self):
+ return " { size = " + str(len(self.fields)) + " }"
+
+ def children(self):
+ return (('[{}]'.format(i), self.elems.cast(self.fields[i].type)['value']) for i in range(self.count))
+
+
+
# ARRAY ================================================================================================================
class ArrayPrinter:
+ """Print a fennec::array"""
+
def __init__(self, val):
self.val = val
@@ -66,6 +87,8 @@ class ArrayPrinter:
# DYNARRAY =============================================================================================================
class DynArrayPrinter:
+ """Print a fennec::dynarray"""
+
def __init__(self, val):
self.val = val
@@ -201,6 +224,7 @@ class RDTreePrinter:
# SET ==================================================================================================================
class SetPrinter:
+ """Print a fennec::set"""
class Iterator:
def __init__(self, table, capacity):
@@ -244,6 +268,7 @@ class SetPrinter:
# MAP ==================================================================================================================
class MapPrinter:
+ """Print a fennec::map"""
class Iterator:
def __init__(self, table, capacity):
@@ -272,12 +297,12 @@ class MapPrinter:
if not self.move:
self.move = True
- return ('key' + str(i), key)
+ return 'key' + str(i), key
else:
self.move = False
self.index = self.index + 1
self.node = self.node + 1
- return ('value' + str(i), val)
+ return 'value' + str(i), val
def __init__(self, val):
self.table = val['_set']['_alloc']['_data']
@@ -303,6 +328,7 @@ def register_printers():
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::containers")
pp.add_printer('optional', '^fennec::optional<.*>$', OptionalPrinter)
pp.add_printer('pair', '^fennec::pair<.*>$', PairPrinter)
+ pp.add_printer('tuple', '^fennec::tuple<.*>$', TuplePrinter)
pp.add_printer('array', '^fennec::array<.*>$', ArrayPrinter)
pp.add_printer('dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter)
pp.add_printer('list', '^fennec::list<.*>$', ListPrinter)
diff --git a/gdb/fennec/utility.py b/gdb/fennec/utility.py
new file mode 100644
index 0000000..1adce0b
--- /dev/null
+++ b/gdb/fennec/utility.py
@@ -0,0 +1,20 @@
+# ======================================================================================================================
+# 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 .
+# ======================================================================================================================
+
+def printMembers(obj):
+ print(str(dir(obj)))
\ No newline at end of file
diff --git a/include/fennec/containers/detail/_tuple.h b/include/fennec/containers/detail/_tuple.h
index de3cd0a..70a4207 100644
--- a/include/fennec/containers/detail/_tuple.h
+++ b/include/fennec/containers/detail/_tuple.h
@@ -24,34 +24,28 @@
namespace fennec::detail
{
-// leaves
-template
-struct _tuple_leaf {
- T value;
- template
- _tuple_leaf(ArgsT&&...args) : value(args...) {
- }
+template
+struct _tuple_leaf
+{
+ template
+ _tuple_leaf(ArgT&& arg) : value(fennec::forward(arg)) {}
- constexpr operator T&() {
- return value;
- }
+ ~_tuple_leaf() = default;
- constexpr operator const T&() const {
- return value;
- }
+ T value;
};
-// proxy
-template
+template
struct _tuple;
-template
-struct _tuple, TypesT...> : _tuple_leaf... {
+template
+struct _tuple, TypesT...> : _tuple_leaf...
+{
+ template
+ _tuple(ArgsT&&... args) : _tuple_leaf(fennec::forward(args))... {}
- template
- _tuple(ArgsT&&...args) : _tuple_leaf(args)... {
- }
+ ~_tuple() = default;
};
}
diff --git a/include/fennec/containers/tuple.h b/include/fennec/containers/tuple.h
index 8fbe501..8f43394 100644
--- a/include/fennec/containers/tuple.h
+++ b/include/fennec/containers/tuple.h
@@ -36,32 +36,44 @@ template struct tuple;
template
constexpr typename tuple::template elem_t& get(tuple& x) {
using elem_t = typename tuple::template elem_t;
- auto& it = static_cast>(x);
- return it;
+ auto& it = *static_cast*>(&x);
+ return it.value;
}
template
-constexpr const typename tuple::template elem_t& get(tuple& x) {
+constexpr const typename tuple::template elem_t& get(const tuple& x) {
using elem_t = typename tuple::template elem_t;
- auto& it = static_cast>(x);
- return it;
+ const auto& it = *static_cast*>(&x);
+ return it.value;
}
-template
-struct tuple : detail::_tuple, TypesT...> {
-
-public:
- using base_t = detail::_tuple, TypesT...>;
+template
+struct tuple : public detail::_tuple, TypesT...>
+{
+ using base_t = detail::_tuple, TypesT...>;
template
- using elem_t = nth_element;
+ using elem_t = typename nth_element::type;
template
- constexpr tuple(ArgsT&&...args) : base_t(args...) {
+ tuple(ArgsT&&...args)
+ : base_t(fennec::forward(args)...) {
+ }
+
+ tuple(const tuple& cpy)
+ : base_t(cpy) {
+ }
+
+ tuple(tuple&& cpy)
+ : base_t(cpy) {
}
};
+// This is needed for
+template
+tuple(TypesT...) -> tuple;
+
}
#endif // FENNEC_CONTAINERS_TUPLE_H
diff --git a/include/fennec/lang/detail/_type_sequences.h b/include/fennec/lang/detail/_type_sequences.h
index eba03cf..614cc03 100644
--- a/include/fennec/lang/detail/_type_sequences.h
+++ b/include/fennec/lang/detail/_type_sequences.h
@@ -32,8 +32,8 @@ namespace fennec::detail
template
struct _nth_element : conditional<
- n == i, type_identity,
- _nth_element
+ n == i, HeadT,
+ typename _nth_element::type
> {};
}
diff --git a/include/fennec/langproc/strings/string.h b/include/fennec/langproc/strings/string.h
index 73eb71c..3bf4bfa 100644
--- a/include/fennec/langproc/strings/string.h
+++ b/include/fennec/langproc/strings/string.h
@@ -86,10 +86,10 @@ public:
///
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
/// This constructor makes the assumption that `n` is the intended number of characters.
- constexpr _string(const char* str, size_t n)
- : _str(n + 1) {
+ constexpr _string(char* str, size_t n)
+ : _str(str[n - 1] == '\0' ? n : n + 1) {
fennec::memcpy(_str.data(), str, n);
- _str[n] = '\0';
+ if (str[n - 1] != '\0') _str[n] = '\0';
}
///
@@ -97,7 +97,30 @@ public:
/// \param str the buffer to wrap
/// \tparam n the number of characters in the buffer plus the null terminator
template
- constexpr _string(char(&str)[n])
+ explicit constexpr _string(char(&str)[n])
+ : _str(str, n) {
+ assert(_str[n - 1] == '\0', "Invalid NTBS.");
+ }
+
+ ///
+ /// \brief Buffer Copy Constructor
+ /// \param str the buffer to copy
+ /// \param n number of characters in the buffer
+ ///
+ /// \details adds additional character for null termination. Ignores whether str is null-terminated.
+ /// This constructor makes the assumption that `n` is the intended number of characters.
+ constexpr _string(const char* str, size_t n)
+ : _str(str[n - 1] == '\0' ? n : n + 1) {
+ fennec::memcpy(_str.data(), str, n);
+ if (str[n - 1] != '\0') _str[n] = '\0';
+ }
+
+ ///
+ /// \brief Buffer Constructor, wraps the provided C-Style string
+ /// \param str the buffer to wrap
+ /// \tparam n the number of characters in the buffer plus the null terminator
+ template
+ explicit constexpr _string(const char(&str)[n])
: _str(str, n) {
assert(_str[n - 1] == '\0', "Invalid NTBS.");
}
@@ -385,7 +408,7 @@ public:
/// \returns
constexpr _string operator+(char c) const {
// Copy contents with one additional byte.
- _string res(_str.data(), _str.size());
+ _string res(_str.data(), _str.size() + 1);
res[size()] = c; // Set the last character to c
return res;
}
diff --git a/planning/CONTAINERS.md b/planning/CONTAINERS.md
index b78f532..d4d2a1a 100644
--- a/planning/CONTAINERS.md
+++ b/planning/CONTAINERS.md
@@ -29,7 +29,7 @@ Library and Template Library.
| Symbol | Implemented | Passed |
|:-------------------------------------|:-----------:|:------:|
| pair | ✔ | ✔ |
-| tuple | ⭕ | ❌ |
+| tuple | ⭕ | ⭕ |
| optional | ✔ | ✔ |
| variant | ❌ | ❌ |
| any | ❌ | ❌ |
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index aff97e5..c935096 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -34,6 +34,7 @@ add_executable(fennec-test main.cpp
tests/containers/test_map.h
tests/containers/test_rdtree.h
tests/containers/test_list.h
+ tests/containers/test_tuple.h
)
target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}"
diff --git a/test/tests/containers/test_tuple.h b/test/tests/containers/test_tuple.h
new file mode 100644
index 0000000..996c1c4
--- /dev/null
+++ b/test/tests/containers/test_tuple.h
@@ -0,0 +1,43 @@
+// =====================================================================================================================
+// 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 .
+// =====================================================================================================================
+
+#ifndef FENNEC_TEST_CONTAINERS_TUPLE_H
+#define FENNEC_TEST_CONTAINERS_TUPLE_H
+#include
+#include
+
+namespace fennec
+{
+
+namespace test
+{
+
+inline void fennec_test_containers_tuple() {
+ string str{ "Hello World!" };
+ tuple test { 0, 0.5f, str };
+
+ fennec_test_run(get<0>(test), 0);
+ fennec_test_run(get<1>(test), 0.5f);
+ fennec_test_run(get<2>(test), str);
+}
+
+}
+
+}
+
+#endif // FENNEC_TEST_CONTAINERS_TUPLE_H
\ No newline at end of file
diff --git a/test/tests/test_containers.h b/test/tests/test_containers.h
index 0aaad91..2ea99cb 100644
--- a/test/tests/test_containers.h
+++ b/test/tests/test_containers.h
@@ -26,6 +26,7 @@
#include "containers/test_optional.h"
#include "containers/test_rdtree.h"
#include "containers/test_set.h"
+#include "containers/test_tuple.h"
namespace fennec::test
{
@@ -37,6 +38,11 @@ namespace fennec::test
fennec_test_containers_optional();
fennec_test_spacer(3);
+ fennec_test_subheader("tuple tests");
+ fennec_test_spacer(2);
+ fennec_test_containers_tuple();
+ fennec_test_spacer(3);
+
fennec_test_subheader("array tests");
fennec_test_spacer(2);
fennec_test_containers_array();