diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c9c116..d1ace8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ add_library(fennec STATIC include/fennec/lang/detail/__numeric_transforms.h include/fennec/lang/detail/__type_traits.h + include/fennec/lang/detail/__variadics.h # MEMORY =============================================================================================================== @@ -70,9 +71,6 @@ add_library(fennec STATIC include/fennec/math/detail/__fwd.h include/fennec/math/detail/__types.h include/fennec/math/detail/__vector_traits.h - - include/fennec/lang/detail/__variadics.h - ) add_subdirectory(metaprogramming) diff --git a/README.md b/README.md index 69ef250..344ed6a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,21 @@ -# fennec -*a free and open source game engine* +

+ +
+drawing +
+

fennec

+

a free and open source game engine

+
+
+ +

## Table of Contents -1. [Introduction](#introduction) -2. [Building from Source](#building-from-source) - 1. [Building from Terminal](#building-from-terminal) - 2. [Building on Windows](#building-on-windows) -3. [Running the Test Suite](#running-the-test-suite) + 1. [Introduction](#introduction) + 2. [Building from Source](#building-from-source) + 1. [Building from Terminal](#building-from-terminal) + 2. [Building on Windows](#building-on-windows) + 3. [Running the Test Suite](#running-the-test-suite)
@@ -17,14 +26,23 @@ fennec is designed to be a general purpose, educational game engine. Interfacing with the API in C++ follows the [GNU Coding Standards](https://www.gnu.org/prep/standards/html_node/index.html). +Some main areas where the engine strays from the GNU standard includes the following: + +- [Section 4.7, Standards for Graphical Interfaces](https://www.gnu.org/prep/standards/html_node/Graphical-Interfaces.html). + fennec provides an implementation for X11, however it does not use the GTK toolkit.
-Some main areas where the engine strays from the GNU standard includes the following: +The C++ stdlib is reimplemented in the fennec engine. +There are a few reasons for this: - - [Section 4.7, Standards for Graphical Interfaces](https://www.gnu.org/prep/standards/html_node/Graphical-Interfaces.html). - fennec provides an implementation for X11, however it does not use the GTK toolkit. - + 1. Standardize implementations across compilers + 2. Set proper naming conventions, i.e. `std::vector`->`fennec::dynarray` + 3. Optimize compilation times, binary size, and performance. + 4. Inject debugging information when necessary. + 5. Expose functionality in a readable manner for those interested in learning the + intricacies of the implementation. +
@@ -107,4 +125,9 @@ cmake -G "Visual Studio 17 2022" -A x64 ## Running the Test Suite -`test.sh` provides profiles for building the test suite and executes them. \ No newline at end of file +`test.sh` provides profiles for building the test suite and executes them. + +By default, it runs in debug mode and the first failed test will throw an assertion. +Any tests that involve running as an application will spawn a subprocess with a window, +and give a short description of the behaviour in the terminal. It will then have you confirm +whether the information displayed is correct. \ No newline at end of file diff --git a/build.sh b/build.sh index 3cc4752..a9652a8 100755 --- a/build.sh +++ b/build.sh @@ -21,7 +21,7 @@ Help() { - echo "Bash script for building fennec from source." + echo "Bash script for building fennec from source. By default, the build script executes in release mode." echo echo "GNU long options:" echo "--help (-h) = Print this help info." @@ -82,6 +82,11 @@ All() # Main Program ========================================================================================================= +if [[ $# -eq 0 ]] ; then + Release + exit 0 +fi + while [ "${1:-}" != '' ]; do case "$1" in '--debug' | '-d') diff --git a/include/fennec/containers/dynarray.h b/include/fennec/containers/dynarray.h index 5acb43d..531f199 100644 --- a/include/fennec/containers/dynarray.h +++ b/include/fennec/containers/dynarray.h @@ -43,7 +43,8 @@ public: using alloc_t = Alloc; dynarray() : _alloc(), _size(0) {} - dynarray() + dynarray(size_t size) : _alloc(size), _size(size) { } + dynarray(const alloc_t& alloc) : _alloc(alloc), _size(0) {} private: allocation _alloc; diff --git a/include/fennec/lang/intrinsics.h b/include/fennec/lang/intrinsics.h index 87ffa30..8cb5f9f 100644 --- a/include/fennec/lang/intrinsics.h +++ b/include/fennec/lang/intrinsics.h @@ -20,7 +20,7 @@ #ifndef FENNEC_LANG_INTRINSICS_H #define FENNEC_LANG_INTRINSICS_H -// Most major compilers support __has_builtin +// Most major compilers support __has_builtin, notably GCC, MINGW, CLANG, and MSVC #if defined(__has_builtin) @@ -91,6 +91,14 @@ # define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 0 #endif +// Difficult and Inconsistent without intrinsics +#if __has_builtin(__is_constructible) +# define FENNEC_BUILTIN_CAN_CONSTRUCT 1 +# define FENNEC_BUILTIN_CAN_CONSTRUCT(type, args...) __is_constructible(type, args) +#else +# define FENNEC_HAS_BUILTIN_CAN_CONSTRUCT 0 +#endif + // For compilers without or differently named builtins #else diff --git a/include/fennec/lang/type_traits.h b/include/fennec/lang/type_traits.h index 6bf6352..cb94f01 100644 --- a/include/fennec/lang/type_traits.h +++ b/include/fennec/lang/type_traits.h @@ -204,8 +204,18 @@ template struct can_convert /// \brief shorthand /// \param T0 First type /// \param T1 Second type -template using can_convert_v = typename can_convert::type; +template using can_convert_v + = typename can_convert::type; + +// fennec::is_constructible ============================================================================================ + + +template struct can_construct + : bool_constant {}; + +template constexpr bool_t can_construct_v + = can_construct{}; // diff --git a/include/fennec/memory/allocator.h b/include/fennec/memory/allocator.h index 0aab02f..8d47db3 100644 --- a/include/fennec/memory/allocator.h +++ b/include/fennec/memory/allocator.h @@ -106,6 +106,8 @@ public: /// \brief Rebinds the allocator type to produce an element type of type `TypeT` template using rebind = typename __rebind::type; + + // TODO: allocator_traits static functions }; @@ -180,19 +182,22 @@ public: /// /// \brief Default Constructor, initializes internal data to `null` and the capacity to `0` - constexpr allocation() noexcept : _data(nullptr), _capacity(0) {} + constexpr allocation() noexcept + : _data(nullptr), _capacity(0) {} /// /// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes /// \param n The number of elements of type `T` to allocate for - constexpr allocation(size_t n) noexcept : _data(_alloc.al), _capacity(n) {} + constexpr allocation(size_t n) noexcept + : _data(_alloc.al), _capacity(n) {} /// /// \brief Allocator Constructor /// \param alloc The allocation object to copy. /// /// \details This constructor should be used when the type `AllocT` needs internal data. - constexpr allocation(const alloc_t& alloc) noexcept : _alloc(alloc), _data(nullptr), _capacity(0) {} + constexpr allocation(const alloc_t& alloc) noexcept + : _alloc(alloc), _data(nullptr), _capacity(0) {} /// /// \brief Sized Allocator Constructor @@ -200,7 +205,24 @@ public: /// \param alloc The allocation object to copy. /// /// \details This constructor should be used when the type `AllocT` needs internal data. - constexpr allocation(size_t n, const alloc_t& alloc) noexcept : _alloc(alloc), _data(nullptr), _capacity(0) {} + constexpr allocation(size_t n, const alloc_t& alloc) noexcept + : _alloc(alloc), _data(nullptr), _capacity(0) {} + + /// + /// \brief Copy Constructor, creates an allocation of equal size and performs a byte-wise copy + /// \param alloc The allocation to copy + constexpr allocation(const allocation& alloc) noexcept + : _alloc(alloc._alloc), _data(_alloc.allocate(alloc._capacity)), _capacity(alloc._capacity) + { fennec::memcpy(_data, alloc._data, alloc._capacity * sizeof(T)); } + + /// + /// \brief Move Constructor, moves the data in `alloc` to the new object and cleans `alloc` so that it + /// can safely destruct + /// \param alloc The allocation to move + constexpr allocation(allocation&& alloc) noexcept + : _alloc(alloc._alloc), _data(alloc._data), _capacity(alloc._capacity) + { alloc._data = nullptr; alloc._capacity = 0; } + /// /// \brief Default Destructor, releases the memory block if still present diff --git a/include/fennec/memory/memory.h b/include/fennec/memory/memory.h index 46fe744..44f3f82 100644 --- a/include/fennec/memory/memory.h +++ b/include/fennec/memory/memory.h @@ -20,6 +20,7 @@ #ifndef FENNEC_MEMORY_H #define FENNEC_MEMORY_H +#include #include namespace fennec @@ -152,22 +153,6 @@ constexpr void* memset(void* dst, int ch, size_t n) return dst; } - -template -struct default_delete -{ - constexpr default_delete() noexcept = default; - - template default_delete(const default_delete&) noexcept; - template default_delete(const default_delete&) noexcept; -}; - -template -struct default_delete -{ - -}; - } #endif // FENNEC_MEMORY_H diff --git a/include/fennec/memory/pointers.h b/include/fennec/memory/pointers.h index 3d67b7d..50d66e7 100644 --- a/include/fennec/memory/pointers.h +++ b/include/fennec/memory/pointers.h @@ -19,19 +19,105 @@ #ifndef FENNEC_LANG_POINTERS_H #define FENNEC_LANG_POINTERS_H +#include -template +namespace fennec +{ + +template +struct default_delete +{ + /// + /// \brief Default constructor + constexpr default_delete() noexcept = default; + + /// + /// \brief Conversion Constructor + /// \tparam ConvT of other deleter + template requires requires { can_convert{}.value == true; } + constexpr default_delete(const default_delete&) noexcept {} + + /// + /// \brief Function Call Operator, calls `delete` on `ptr` + /// \param ptr Memory resource to delete + constexpr void operator()(TypeT* ptr) const noexcept + { + static_assert(not is_void_v, "cannot delete a pointer to an incomplete type"); + static_assert(not sizeof(TypeT) > 0, "cannot delete a pointer to an incomplete type"); + delete ptr; + } +}; + +template +struct default_delete +{ + /// + /// \brief Default constructor + constexpr default_delete() noexcept = default; + + /// + /// \brief Conversion Constructor + /// \tparam ConvT of other deleter + template requires requires { can_convert{}.value == true; } + constexpr default_delete(const default_delete&) noexcept {} + + /// + /// \brief Function Call Operator, calls `delete` on `ptr` + /// \param ptr Memory resource to delete + template requires requires { can_convert{}.value == true; } + constexpr void operator()(TypeT* ptr) const noexcept + { + static_assert(not is_void_v, "cannot delete a pointer to an incomplete type"); + static_assert(not sizeof(TypeT) > 0, "cannot delete a pointer to an incomplete type"); + delete[] ptr; + } +}; + +template> class unique_ptr { public: + /// \brief the element type using element_t = TypeT; + + /// \brief pointer to element type using pointer_t = element_t*; + /// \brief the deleter + using delete_t = DeleteT; + + /// + /// \brief Default Constructor, creates a unique_ptr that owns nothing. constexpr unique_ptr() : unique_ptr(nullptr) {} - constexpr unique_ptr(pointer_t ptr) : _handle(ptr) {} + + /// + /// \brief Nullptr Constructor, creates a unique_ptr that owns nothing. + constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr) {} + + /// + /// \brief Pointer Constructor, creates a unique_ptr that owns `ptr` with deleter `del` + /// \param ptr The resource to own + /// \param del The deleter + explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del) : _delete(del), _handle(ptr) {} + + /// + /// \brief Pointer Constructor, creates a unique_ptr that owns `ptr` with deleter `del` + /// \param ptr The resource to own + /// \param del The deleter + explicit constexpr unique_ptr(pointer_t ptr, delete_t&& del) : _delete(del), _handle(ptr) {} + + /// + /// \brief Move Constructor, transfers ownership from `other` + /// \param other The unique_ptr to take ownership from constexpr unique_ptr(unique_ptr&& other) : _handle(other._handle) { other._handle = nullptr; } - constexpr ~unique_ptr() { if(_handle) ::operator delete(_handle); } + // Delete copy constructor + constexpr unique_ptr(const unique_ptr&) = delete; + + /// + /// \brief Default Constructor, if it owns a resource, it deletes it using `delete_t` + constexpr ~unique_ptr() { if(_handle) _delete(_handle); } + constexpr unique_ptr& operator=(unique_ptr&& r) noexcept { _handle = r._handle; r._handle = nullptr; return *this; } @@ -40,7 +126,10 @@ public: private: + delete_t _delete; pointer_t _handle; }; +} + #endif // FENNEC_LANG_POINTERS_H diff --git a/logo/raster.png b/logo/raster.png new file mode 100644 index 0000000..8eeedab Binary files /dev/null and b/logo/raster.png differ diff --git a/logo/vector.svg b/logo/vector.svg new file mode 100644 index 0000000..b77523f --- /dev/null +++ b/logo/vector.svg @@ -0,0 +1,70 @@ + + + + diff --git a/test.sh b/test.sh index 2039bdc..423384e 100755 --- a/test.sh +++ b/test.sh @@ -21,7 +21,7 @@ Help() { - echo "Bash script for building fennec from source." + echo "Bash script for running the fennec test suite. By default, the build script executes in debug mode." echo echo "GNU long options:" echo "--help (-h) = Print this help info." @@ -87,7 +87,7 @@ All() # Main Program ========================================================================================================= if [[ $# -eq 0 ]] ; then - All + Debug exit 0 fi