From a33bf5206f089407caf5ab7135d48818096f2917 Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Sat, 5 Jul 2025 14:22:59 -0400 Subject: [PATCH] - Stacktrace generation with failed asserts --- .gitmodules | 3 + CMakeLists.txt | 34 +- PLANNING.md | 7 +- README.md | 2 + doxy/Doxyfile | 30 +- external/cpptrace | 1 + include/fennec/containers/array.h | 4 +- include/fennec/fproc/strings/detail/__ctype.h | 38 +++ include/fennec/fproc/strings/string.h | 297 ++++++++++++++++++ include/fennec/lang/assert.h | 5 +- include/fennec/lang/detail/__stdlib.h | 4 +- include/fennec/lang/types.h | 11 - include/fennec/math/matrix.h | 12 +- include/fennec/math/vector.h | 2 +- include/fennec/memory/allocator.h | 64 +++- .../memory/detail/{__memory.h => __string.h} | 54 ++-- include/fennec/memory/memory.h | 80 +---- include/fennec/memory/new.h | 2 - source/debug/assert_impl.cpp | 13 +- source/lang/assert.cpp | 8 +- source/memory/new.cpp | 44 +-- test/test.h | 5 +- 22 files changed, 529 insertions(+), 191 deletions(-) create mode 160000 external/cpptrace create mode 100644 include/fennec/fproc/strings/detail/__ctype.h create mode 100644 include/fennec/fproc/strings/string.h rename include/fennec/memory/detail/{__memory.h => __string.h} (53%) diff --git a/.gitmodules b/.gitmodules index 94b09d4..cd4e797 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "external/sdl"] path = external/sdl url = https://github.com/libsdl-org/SDL.git +[submodule "external/cpptrace"] + path = external/cpptrace + url = https://github.com/jeremy-rifkin/cpptrace.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 02f47c3..85123f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,9 @@ project(fennec) set(SDL_STATIC 1) add_subdirectory(external/sdl) +# CppTrace is a dependency of the project, added as a git submodule +add_subdirectory(external/cpptrace) + set(CMAKE_CXX_STANDARD 26) set(CMAKE_C_STANDARD 26) @@ -15,6 +18,8 @@ find_package(Doxygen) # any necessary include directories include_directories(include) +include_directories(external/cpptrace/include) +include_directories(external/sdl/include) # Metaprogramming is a dependency for generating various type info before compilation of the engine. add_subdirectory(metaprogramming) @@ -58,7 +63,9 @@ add_library(fennec STATIC include/fennec/lang/integer.h include/fennec/lang/detail/__bits.h + include/fennec/lang/detail/__int.h include/fennec/lang/detail/__numeric_transforms.h + include/fennec/lang/detail/__stdlib.h include/fennec/lang/detail/__type_traits.h include/fennec/lang/detail/__type_sequences.h @@ -75,6 +82,9 @@ add_library(fennec STATIC include/fennec/memory/detail/__ptr_traits.h +# DEBUG ================================================================================================================ + source/debug/assert_impl.cpp + # MATH ================================================================================================================= include/fennec/math/math.h @@ -98,22 +108,26 @@ add_library(fennec STATIC include/fennec/math/relational.h include/fennec/math/detail/__fwd.h + include/fennec/math/detail/__math.h + include/fennec/math/detail/__matrix.h include/fennec/math/detail/__types.h include/fennec/math/detail/__vector_traits.h - source/debug/assert_impl.cpp - include/fennec/math/detail/__math.h - include/fennec/lang/detail/__int.h - include/fennec/lang/detail/__stdlib.h - include/fennec/math/detail/__matrix.h include/fennec/math/ext/constants.h + +# FPROC ================================================================================================================ + + # Strings + include/fennec/fproc/strings/string.h + + include/fennec/fproc/strings/detail/__ctype.h ) # add metaprogramming templates as a dependency and also force documentation to be generated when fennec is compiled if(DOXYGEN_FOUND) - add_dependencies(fennec fennecdocs metaprogramming SDL3-static) + add_dependencies(fennec fennecdocs metaprogramming SDL3-static cpptrace::cpptrace) else() - add_dependencies(fennec metaprogramming SDL3-static) + add_dependencies(fennec metaprogramming SDL3-static cpptrace::cpptrace) endif() # Compiler Warning Flags @@ -123,12 +137,14 @@ else() add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror") # All gcc/etc. Warnings throw as errors endif() -#target_compile_options(fennec PUBLIC "-mavx" "-mavx2" "-mavx512f") # SIMD Instructions, currently unused +target_compile_options(fennec PUBLIC "-mavx" "-mavx2" "-mavx512f") # SIMD Instructions, automatic vectorization will occur -target_link_options(fennec PRIVATE "-nostdlib") # Do not compile base fennec library with c++ stdlib +target_link_options(fennec PRIVATE "-nostdlib -nodefaultlibs -fno-exceptions") # Do not compile base fennec library with c++ stdlib # fennec does not use the C++ stdlib because it is bloated, difficult to read, and implementation defined. # This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated +target_link_libraries(fennec PRIVATE SDL3-static cpptrace::cpptrace) + # add the test suite as a sub-project add_subdirectory(test) diff --git a/PLANNING.md b/PLANNING.md index f56764b..352713f 100644 --- a/PLANNING.md +++ b/PLANNING.md @@ -121,8 +121,13 @@ Here are essential data-structures not specified in the C++ stdlib: ## Format Processing (`fproc`) +This library contains information for any data that is formatted. This includes basic string formats, file formats, +and eventually programming languages + fennec should be able to use Doxygen and LaTeX externally. Consider including binaries with releases. +### Notes + * String Analysis (`fproc/strings`) * Search * Manipulation @@ -160,7 +165,7 @@ fennec should be able to use Doxygen and LaTeX externally. Consider including bi - FBX - Wavefront OBJ -**MAYBE** +**TODO LATER** * Compilation (`fproc/code`) * Lexical Analysis * Syntax Analysis diff --git a/README.md b/README.md index 28a5b3f..2c3ff01 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ may be used through the provided editor application, or as a standalone library to link against your application. + +
diff --git a/doxy/Doxyfile b/doxy/Doxyfile index 7be454f..b886496 100644 --- a/doxy/Doxyfile +++ b/doxy/Doxyfile @@ -68,7 +68,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = C:/Users/msloc/Documents/Work/Personal/fennec/docs +OUTPUT_DIRECTORY = /home/medusa/Documents/Work/Personal/fennec/docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format @@ -815,7 +815,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/DoxyLayout.xml +LAYOUT_FILE = /home/medusa/Documents/Work/Personal/fennec/doxy/DoxyLayout.xml # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -943,9 +943,9 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = "C:/Users/msloc/Documents/Work/Personal/fennec/include/" \ - "C:/Users/msloc/Documents/Work/Personal/fennec/source/" \ - "C:/Users/msloc/Documents/Work/Personal/fennec/README.md" +INPUT = "/home/medusa/Documents/Work/Personal/fennec/include/" \ + "/home/medusa/Documents/Work/Personal/fennec/source/" \ + "/home/medusa/Documents/Work/Personal/fennec/README.md" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -1079,7 +1079,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = "C:/Users/msloc/Documents/Work/Personal/fennec" +EXAMPLE_PATH = "/home/medusa/Documents/Work/Personal/fennec" # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -1160,7 +1160,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = "C:/Users/msloc/Documents/Work/Personal/fennec/README.md" +USE_MDFILE_AS_MAINPAGE = "/home/medusa/Documents/Work/Personal/fennec/README.md" # The Fortran standard specifies that for fixed formatted Fortran code all # characters from position 72 are to be considered as comment. A common @@ -1359,7 +1359,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/header.html +HTML_HEADER = /home/medusa/Documents/Work/Personal/fennec/doxy/header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1369,7 +1369,7 @@ HTML_HEADER = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/head # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/footer.html +HTML_FOOTER = /home/medusa/Documents/Work/Personal/fennec/doxy/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1381,7 +1381,7 @@ HTML_FOOTER = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/foot # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/style.css +HTML_STYLESHEET = /home/medusa/Documents/Work/Personal/fennec/doxy/style.css # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets @@ -1399,10 +1399,10 @@ HTML_STYLESHEET = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/styl # documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/doxygen-awesome.css \ - C:/Users/msloc/Documents/Work/Personal/fennec/doxy/doxygen-awesome-sidebar-only.css \ - C:/Users/msloc/Documents/Work/Personal/fennec/doxy/doxygen-awesome-sidebar-only-darkmode-toggle.css \ - C:/Users/msloc/Documents/Work/Personal/fennec/doxy/custom.css +HTML_EXTRA_STYLESHEET = /home/medusa/Documents/Work/Personal/fennec/doxy/doxygen-awesome.css \ + /home/medusa/Documents/Work/Personal/fennec/doxy/doxygen-awesome-sidebar-only.css \ + /home/medusa/Documents/Work/Personal/fennec/doxy/doxygen-awesome-sidebar-only-darkmode-toggle.css \ + /home/medusa/Documents/Work/Personal/fennec/doxy/custom.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1412,7 +1412,7 @@ HTML_EXTRA_STYLESHEET = C:/Users/msloc/Documents/Work/Personal/fennec/doxy/doxy # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = "C:/Users/msloc/Documents/Work/Personal/fennec/doxy/doxygen-awesome-darkmode-toggle.js" +HTML_EXTRA_FILES = "/home/medusa/Documents/Work/Personal/fennec/doxy/doxygen-awesome-darkmode-toggle.js" # The HTML_COLORSTYLE tag can be used to specify if the generated HTML output # should be rendered with a dark or light theme. diff --git a/external/cpptrace b/external/cpptrace new file mode 160000 index 0000000..9133b90 --- /dev/null +++ b/external/cpptrace @@ -0,0 +1 @@ +Subproject commit 9133b90a9995e438476206bb116c849dfd0fe712 diff --git a/include/fennec/containers/array.h b/include/fennec/containers/array.h index b088e10..e08dbae 100644 --- a/include/fennec/containers/array.h +++ b/include/fennec/containers/array.h @@ -57,7 +57,7 @@ struct array /// /// \copydetails array::at(size_t) const - constexpr ValueT& at(size_t i) { static_assert(i < ElemV); assert(i < ElemV); return elements[i]; } + constexpr ValueT& at(size_t i) { static_assert(i < ElemV); assert(i < ElemV, "Array Out of Bounds"); return elements[i]; } /// /// \brief access specified element, **with bounds checking** @@ -70,7 +70,7 @@ struct array /// /// \par Space-Complexity /// Constant - constexpr const ValueT& at(size_t i) const { static_assert(i < ElemV); assert(i < ElemV); return elements[i]; } + constexpr const ValueT& at(size_t i) const { static_assert(i < ElemV); assert(i < ElemV, "Array Out of Bounds"); return elements[i]; } diff --git a/include/fennec/fproc/strings/detail/__ctype.h b/include/fennec/fproc/strings/detail/__ctype.h new file mode 100644 index 0000000..dadcbc8 --- /dev/null +++ b/include/fennec/fproc/strings/detail/__ctype.h @@ -0,0 +1,38 @@ +// ===================================================================================================================== +// 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_FPROC_STRINGS_DETAIL_CTYPE_H +#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H + +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4117) + +#define __PTRDIFF_TYPE__ ptrdiff_t +#endif + +#pragma push_macro("__cplusplus") +#undef __cplusplus +#include +#pragma pop_macro("__cplusplus") + +#if _MSC_VER +#pragma warning(pop) +#endif + +#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H diff --git a/include/fennec/fproc/strings/string.h b/include/fennec/fproc/strings/string.h new file mode 100644 index 0000000..a85923a --- /dev/null +++ b/include/fennec/fproc/strings/string.h @@ -0,0 +1,297 @@ +// ===================================================================================================================== +// 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_FPROC_STRINGS_STRING_H +#define FENNEC_FPROC_STRINGS_STRING_H + +#include + +#include +#include +#include + +namespace fennec +{ + +// TODO: Document + +using ::isalnum; +using ::isalpha; +using ::islower; +using ::isupper; +using ::isdigit; +using ::isxdigit; +using ::iscntrl; +using ::isgraph; +using ::isspace; +using ::isblank; +using ::isprint; +using ::ispunct; + +using ::tolower; +using ::toupper; + +/// +/// \brief Struct for wrapping c-style strings +/// +/// \details fennec will use this class over `const char*` for memory safety. +/// behaviour guarantees that the underlying string is null-terminated +template> +struct string +{ +public: + using alloc_t = allocation; + + /// + /// \brief Default Constructor, initializes empty string + constexpr string() + : _str() + { } + + /// + /// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters + /// \param n the number of characters + /// + /// \details adds additional character for null termination. + constexpr string(size_t n) + : string('\0', n) + { } + + /// + /// \brief Sized Constructor, initializes a null-terminated string of size `n` filled with the character `c` + /// \param c the character to fill with + /// \param n the number of characters + /// + /// \details adds additional character for null termination. + constexpr string(char c, size_t n) + : _str(n + 1) + { fennec::memset(_str, c, n); _str[n] = '\0'; } + + /// + /// \brief Buffer Copy Constructor + /// \param str the buffer to copy + /// \param len 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 `len` is the intended number of characters. + constexpr string(const char* str, size_t len) + : _str(str, len + 1) + { _str[len] = '\0'; } + + /// + /// \brief Array Copy Constructor + /// \tparam N the number of characters + /// \param str the array to copy + /// + /// \details if str is not null-terminated, adds additional character for null-termination. + template + constexpr string(const char str[N]) + { + if (str[N - 1] == '\0') string(str, N - 1); + else string(str, N); + } + + /// + /// \brief String Copy Constructor + /// \param str the string to copy + constexpr string(const string& str) + : string(str, str.size() - 1) + { } + + constexpr string(string&& str) noexcept + : _str(fennec::move(str._str)) + { } + + /// + /// \brief String Destructor, cleans up the underlying allocation + constexpr ~string() = default; // allocation cleans up itself + +// Properties ========================================================================================================== + + /// + /// \returns The size of the string excluding null terminator + constexpr size_t size() const { return _str.capacity() - 1; } + + +// Access ============================================================================================================== + + /// + /// \brief Array Access Operator + /// \param i the index to access + /// \returns a reference to the character + constexpr char& operator[](int i) { + assert(i >= 0 && i < size(), "Array Out of Bounds"); + return _str[i]; + } + + /// + /// \brief Const-Array Access Operator + /// \param i the index to access + /// \returns a copy of the character + constexpr char operator[](int i) const { + assert(i >= 0 && i < size(), "Array Out of Bounds"); + return _str[i]; + } + + /// + /// \brief Dereference Operator + /// \returns A const qualified pointer to the underlying allocation + constexpr const char* operator*() const { return _str; } + + /// + /// \brief Implicit Dereference Cast + constexpr operator const char*() const { return _str; } + + +// Examination ========================================================================================================= + + /// + /// \returns The length of the string to the first null-terminator + constexpr size_t length() const + { return find('\0'); } + + /// + /// \brief String Comparison + /// \param ostr the string to compare against + /// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the + /// current locale, otherwise a positive value. + constexpr int compare(const string& ostr) const + { return ::strcoll(_str, ostr); } + + /// + /// \brief Finds the index of the first occurrence of `x` in the string + /// \param x the character to find + /// \returns The index of `x` if it occurs in the string, otherwise returns `size()` + constexpr size_t find(char x) const + { + const char* loc = ::strchr(_str, x); + return loc ? loc - _str : size(); + } + + /// + /// \brief Finds the index of the first occurrence of `str` in the string. + /// \param str the string to find + /// \returns The index of `str` if it occurs in the string, otherwise returns `size()` + constexpr size_t find(const string& str) const + { + const char* loc = ::strstr(_str, str); + return loc ? loc - _str : size(); + } + + /// + /// \brief Finds the index of the last occurrence of `x` in the string. + /// \param x the string to find + /// \returns The index of `x` if it occurs in the string, otherwise returns `size()` + constexpr size_t rfind(char x) const + { + const char* loc = ::strrchr(_str, x); + return loc ? loc - _str : size(); + } + + // TODO: constexpr size_t rfind(const string& str) const; + +// Manipulation ======================================================================================================== + + /// + /// \brief Resize the string, filling additional bytes with `'\0'` + /// \param n the new size of the string + constexpr void resize(size_t n) + { + size_t i = size(); + _str.reallocate(n + 1); + if (n > i) fennec::memset(*_str + i, '\0', n - i); + } + + /// + /// \brief Copy Assignment Operator + /// \param str the string to copy + /// \returns a reference to `this` + constexpr string& operator=(const string& str) + { + if (str.size() > size()) string::resize(str.size()); + fennec::memcpy(_str, str, str.size()); + _str[str.size()] = '\0'; + return *this; + } + + /// + /// \brief Move Assignment Operator + /// \param str the string to move + /// \returns a reference to `this` + constexpr string& operator=(string&& str) noexcept + { + _str = fennec::move(str._str); + return *this; + } + + /// + /// \brief Retrieve a substring of a string + /// \param i the start index + /// \param n the number of characters + /// \return + constexpr string substring(size_t i, size_t n = size()) + { + assert(i < size(), "Array Out of Bounds"); + n = min(n, size() - i); + return string(&_str[i], n); + } + + /// + /// \brief Returns a string with `c` appended to it + /// \param c + /// \returns + constexpr string operator+(char c) + { + // Copy contents with one additional byte. + string res(_str, _str.size()); + res[size()] = c; // Set the last character to c + return res; + } + + constexpr string operator+(const string& str) + { + string res(size() + str.size()); // Make a new string with the size of this + str + fennec::memcpy(res, _str, size()); // Copy the contents of this + fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str + return res; + } + + constexpr string& operator+=(char c) + { + size_t x = size(); + resize(x + 1); + _str[x] = c; + return *this; + } + + constexpr string& operator+=(const string& str) + { + size_t x = size(); + string::resize(x + str.size()); + fennec::memcpy(&_str[x], str, str.size()); + return *this; + } + +private: + alloc_t _str; +}; + +} + + +#endif // FENNEC_FPROC_STRINGS_STRING_H diff --git a/include/fennec/lang/assert.h b/include/fennec/lang/assert.h index 78526ec..59bf1ab 100644 --- a/include/fennec/lang/assert.h +++ b/include/fennec/lang/assert.h @@ -25,8 +25,9 @@ using assert_handler = void (*)(const char *, const char *, int , const char *); -extern void __assert_impl(const char* expression, const char* file, int line, const char* function); +extern void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc); -#define assert(expression) if(not(expression)) { __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__); } +#define assert(expression, description) \ + if(not(expression)) { __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description); } #endif // FENNEC_LANG_ASSERT_H diff --git a/include/fennec/lang/detail/__stdlib.h b/include/fennec/lang/detail/__stdlib.h index c0af009..a3c9e9b 100644 --- a/include/fennec/lang/detail/__stdlib.h +++ b/include/fennec/lang/detail/__stdlib.h @@ -26,9 +26,9 @@ #pragma push_macro("__cplusplus") #undef __cplusplus -extern "C" { + extern "C" { #include -} + } #pragma pop_macro("__cplusplus") #if _MSC_VER diff --git a/include/fennec/lang/types.h b/include/fennec/lang/types.h index e9d341d..7662a84 100644 --- a/include/fennec/lang/types.h +++ b/include/fennec/lang/types.h @@ -153,17 +153,6 @@ /// \copybrief fennec::int64_t /// /// -/////
-///// \ref fennec::float32_t "float32_t" -///// -///// \copybrief fennec::float32_t -///// -/////
-///// \ref fennec::float64_t "float64_t" -///// -///// \copybrief fennec::float64_t -/// -/// /// Special Types ///
/// \ref fennec::nullptr_t "nullptr_t" diff --git a/include/fennec/math/matrix.h b/include/fennec/math/matrix.h index a6fb0f8..7611825 100644 --- a/include/fennec/math/matrix.h +++ b/include/fennec/math/matrix.h @@ -324,7 +324,7 @@ struct matrix /// /// \copydetails matrix::operator[](size_t) const constexpr column_t& operator[](size_t i) - { assert(i < columns); return data[i]; } + { assert(i < columns, "Array Out of Bounds"); return data[i]; } /// /// \brief returns the column at index \f$i\f$ @@ -333,20 +333,20 @@ struct matrix /// \param i the index /// \returns the column at index \f$i\f$ constexpr const column_t& operator[](size_t i) const - { assert(i < columns); return data[i]; } + { assert(i < columns, "Array Out of Bounds"); return data[i]; } /// /// \copydetails matrix::operator()(size_t, size_t) const - constexpr scalar_t& operator()(size_t i, size_t j) - { assert(i < columns && j < rows); return data[i][j]; } + constexpr scalar_t& operator[](size_t i, size_t j) + { assert(i < columns && j < rows, "Array Out of Bounds"); return data[i][j]; } /// /// \brief returns the cell in row \p j column \p i /// \param i the column /// \param j the row /// \returns the cell at the specified index. - constexpr scalar_t operator()(size_t i, size_t j) const - { assert(i < columns && j < rows); return data[i][j]; } + constexpr scalar_t operator[](size_t i, size_t j) const + { assert(i < columns && j < rows, "Array Out of Bounds"); return data[i][j]; } /// @} diff --git a/include/fennec/math/vector.h b/include/fennec/math/vector.h index 2036f45..20b5e21 100644 --- a/include/fennec/math/vector.h +++ b/include/fennec/math/vector.h @@ -710,7 +710,7 @@ struct vector : detail::vector_base_type /// \brief unary boolean not operator /// /// \details - /// \param v the vector + /// \param x the vector /// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=!x_i\f$ constexpr friend vector_t operator!(const vector_t& x) { return vector_t(!x[IndicesV] ...); } diff --git a/include/fennec/memory/allocator.h b/include/fennec/memory/allocator.h index b1b5d36..8b3e21e 100644 --- a/include/fennec/memory/allocator.h +++ b/include/fennec/memory/allocator.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -64,7 +65,7 @@ private: struct __diff> { using type = typename AllocT::diff_t; }; template - struct __size : std::make_unsigned {}; + struct __size : make_unsigned {}; template struct __size> { using type = typename AllocT::size_t; }; @@ -188,7 +189,17 @@ public: /// \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) {} + : _data(nullptr), _capacity(0) + { allocate(n); } + + /// + /// \brief Buffer Copy Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes. + /// Then, the contents of data are copied into the allocation. + /// \param data the buffer to copy + /// \param n the number of elements + constexpr allocation(const T* data, size_t n) + : allocation(n) + { fennec::memcpy(_data, data, n); } /// /// \brief Allocator Constructor @@ -205,7 +216,20 @@ public: /// /// \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) {} + : _alloc(alloc), _data(nullptr), _capacity(0) + { allocate(n); } + + /// + /// \brief Buffer Copy Allocator Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes. + /// Then, the contents of data are copied into the allocation. + /// \param data the buffer to copy + /// \param n the number of elements + /// \param alloc The allocation object to copy. + /// + /// \details This constructor should be used when the type `AllocT` needs internal data. + constexpr allocation(const T* data, size_t n, const alloc_t& alloc) + : allocation(n, alloc) + { fennec::memcpy(_data, data, n); } /// /// \brief Copy Constructor, creates an allocation of equal size and performs a byte-wise copy @@ -227,6 +251,35 @@ public: /// \brief Default Destructor, releases the memory block if still present constexpr ~allocation() noexcept { if (_data) _alloc.deallocate(_data); } + /// + /// \brief Copy Assignment Operator + /// \param alloc the allocation to copy + /// \returns a reference to `this` + constexpr allocation& operator=(const allocation& alloc) + { + allocation::allocate(alloc.capacity()); + fennec::memcpy(_data, alloc, size()); + return *this; + } + + /// + /// \brief Move Assignment Operator + /// \param alloc the allocation to copy + /// \returns a reference to `this` + constexpr allocation& operator=(allocation&& alloc) noexcept + { + // Copy contents + _alloc = alloc._alloc; + _data = alloc._data; + _capacity = alloc._capacity; + + // Cleanup alloc + alloc._data = nullptr; + alloc._capacity = 0; + + return *this; + } + /// /// \brief Allocate a block of memory for the allocation. /// If there is already an allocated block of memory, the previous allocation is released. @@ -236,7 +289,7 @@ public: if (_data) _alloc.deallocate(_data); - _data = alloc_t::allocate(_capacity = n); + _data = _alloc.allocate(_capacity = n); } /// @@ -245,6 +298,7 @@ public: { if (_data) _alloc.deallocate(_data); + _data = nullptr; _capacity = 0; } @@ -258,7 +312,7 @@ public: return _alloc.allocate(_capacity = n); value_t* old = _data; - _data = alloc_t::allocate(n); + _data = _alloc.allocate(n); fennec::memcpy(_data, old, min(_capacity, n) * sizeof(T)); _alloc.deallocate(old); _capacity = n; diff --git a/include/fennec/memory/detail/__memory.h b/include/fennec/memory/detail/__string.h similarity index 53% rename from include/fennec/memory/detail/__memory.h rename to include/fennec/memory/detail/__string.h index 906091f..5bf33d2 100644 --- a/include/fennec/memory/detail/__memory.h +++ b/include/fennec/memory/detail/__string.h @@ -21,46 +21,32 @@ #include -namespace fennec -{ -namespace detail -{ -constexpr size_t __memcpy_8(void* dst, const void* src) - { *static_cast(dst) = *static_cast(src); return 1; } +// deprecated, switched to ISO C implementation +// see https://git.mslockbo.org/mslockbo/fennec/src/commit/0eeb7ae3cff9d78e98dc5d9fc09bcb98b10986b9 for previous +// implementation -// helper for copying 2 bytes at once -constexpr size_t __memcpy_16(void* dst, const void* src) - { *static_cast(dst) = *static_cast(src); return 2; } +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4117) +#endif -// helper for copying 4 bytes at once -constexpr size_t __memcpy_32(void* dst, const void* src) - { *static_cast(dst) = *static_cast(src); return 4; } +#if __GNUC__ +#define __OPTIMIZE__ +#endif -// helper for copying 8 bytes at once -constexpr size_t __memcpy_64(void* dst, const void* src) - { *static_cast(dst) = *static_cast(src); return 8; } +#pragma push_macro("__cplusplus") +#undef __cplusplus +#include +#pragma pop_macro("__cplusplus") -constexpr size_t __memcpy(void* dst, const void* src, size_t n) -{ - switch (n) - { - case 0: - return 0; - case 1: - return __memcpy_8(dst, src); - case 2: case 3: - return __memcpy_16(dst, src); - case 4: case 5: case 6: case 7: - return __memcpy_32(dst, src); - default: - return __memcpy_64(dst, src); - } -} +#if __GNUC__ +#undef __OPTIMIZE__ +#endif -} - -} +#if _MSC_VER +#pragma warning(pop) +#endif #endif // FENNEC_MEMORY_DETAIL_MEMORY_H diff --git a/include/fennec/memory/memory.h b/include/fennec/memory/memory.h index be0f5b8..ae45709 100644 --- a/include/fennec/memory/memory.h +++ b/include/fennec/memory/memory.h @@ -21,7 +21,7 @@ #define FENNEC_MEMORY_H #include -#include +#include namespace fennec { @@ -34,27 +34,14 @@ namespace fennec template constexpr TypeT* addressof(TypeT& obj) { return FENNEC_BUILTIN_ADDRESSOF(obj); } -/// -/// \copydetails fennec::memchr(const void*, int, size_t) -constexpr void* memchr(void* arr, int ch, size_t n) -{ - uint8_t* a = static_cast(arr); - while (n-- && *a++ != ch) {} - return n ? a : nullptr; -} - /// /// \brief Finds the first occurence of ```static_cast(ch)``` in the first \f$n\f$ bytes /// \param arr Pointer to the object, interpreted as an array of bytes /// \param ch The byte to search for /// \param n The number of bytes to search /// \returns A pointer to the location of \f$ch\f$, otherwise \f$nullptr\f$ if \f$ch\f$ is not found. -constexpr const void* memchr(const void* arr, int ch, size_t n) -{ - const uint8_t* a = static_cast(arr); - while (n-- && *a++ != ch) {} - return n ? a : nullptr; -} +using ::memchr; +using ::wmemchr; /// /// \brief Compares the bytes of \f$lhs\f$ with \f$rhs\f$. @@ -63,13 +50,8 @@ constexpr const void* memchr(const void* arr, int ch, size_t n) /// \param n The number of bytes to parse /// \returns \f$0\f$ if the first \f$n\f$ bytes of \f$lhs\f$ and \f$rhs\f$ are equivalent. Otherwise, returns \f$1\f$ /// for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$ -constexpr int memcmp(const void* lhs, const void* rhs, size_t n) -{ - const uint8_t* lhs_ = static_cast(lhs); - const uint8_t* rhs_ = static_cast(rhs); - while (n-- && *lhs_++ == *rhs_++) {} - return n ? *lhs_ - *rhs_ : 0; -} +using ::memcmp; +using ::wmemcmp; /// /// \brief Safe version of memcmp @@ -91,19 +73,8 @@ constexpr int memcmp_s(const void* lhs, size_t n0, const void* rhs, size_t n1) /// \f$src\f$ will be repeated in \f$dst\f$ with a period of \f$k\f$. /// /// A full mathematical proof of this function is possible in Set Theory. -constexpr void* memcpy(void* dst, const void* src, size_t n) -{ - if (dst == src) return dst; - uint8_t* d = static_cast(dst); - const uint8_t* s = static_cast(src); - - while (n > 0) { - size_t step = detail::__memcpy(d, s, n); - d += step; s += step; n -= step; - } - - return dst; -} +using ::memcpy; +using ::wmemcpy; /// /// \brief Safe version of memcpy @@ -119,27 +90,8 @@ constexpr void* memcpy_s(void* dst, size_t n0, const void* src, size_t n1) /// \param src The source object, interpreted as an array of bytes /// \param n The number of bytes to copy /// \returns \f$dst\f$ -constexpr void* memmove(void* dst, const void* src, size_t n) -{ - if (dst == src) return dst; - uint8_t* d = static_cast(dst); - const uint8_t* s = static_cast(src); - - if (d < s) { - while (n > 0) { - size_t step = detail::__memcpy(d, s, n); - d += step; s += step; n -= step; - } - } - else { - d += n - 1; s += n - 1; - while (n > 0) { - size_t step = detail::__memcpy(d, s, n); - d -= step; s -= step; n -= step; - } - } - return dst; -} +using ::memmove; +using ::wmemmove; /// /// \brief Safe version of memmove @@ -155,18 +107,8 @@ constexpr void* memmove_s(void* dst, size_t n0, const void* src, size_t n1) /// \param ch The value, interpreted as an \f$uint8_t\f$ /// \param n The number of bytes to set /// \returns \f$dst\f$ -constexpr void* memset(void* dst, int ch, size_t n) -{ - uint8_t* d = static_cast(dst); - uint8_t val[8] = { static_cast(ch) }; - - while (n > 0) { - size_t step = detail::__memcpy(d, val, n); - d += step; n -= step; - } - - return dst; -} +using ::memset; +using ::wmemset; } diff --git a/include/fennec/memory/new.h b/include/fennec/memory/new.h index dd714c0..315811e 100644 --- a/include/fennec/memory/new.h +++ b/include/fennec/memory/new.h @@ -20,8 +20,6 @@ #ifndef FENNEC_MEMORY_NEW_H #define FENNEC_MEMORY_NEW_H -#include - #include #include diff --git a/source/debug/assert_impl.cpp b/source/debug/assert_impl.cpp index 3675252..7d5d647 100644 --- a/source/debug/assert_impl.cpp +++ b/source/debug/assert_impl.cpp @@ -16,7 +16,16 @@ // along with this program. If not, see . // ===================================================================================================================== -void __assert_callback(const char*, const char*, int, const char*) -{ +#include +void __assert_callback(const char* expression, const char* file, int line, const char* function, const char* description) +{ + // Skip + // __assert_callback + // __assert_impl + printf("Assert failed: \"%s\" \n" + "At %s:%d in %s \n" + "Description: %s \n", + expression, file, line, function, description); + cpptrace::generate_trace(2).print(); } \ No newline at end of file diff --git a/source/lang/assert.cpp b/source/lang/assert.cpp index aa02e7e..12ed477 100644 --- a/source/lang/assert.cpp +++ b/source/lang/assert.cpp @@ -20,13 +20,13 @@ using assert_handler = void (*)(const char *, const char *, int , const char *); -extern void __assert_callback(const char* expression, const char* file, int line, const char* function); +extern void __assert_callback(const char* expression, const char* file, int line, const char* function, const char* description); -void __assert_impl(const char* expression, const char* file, int line, const char* function) +void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* description) { - __assert_callback(expression, file, line, function); + __assert_callback(expression, file, line, function, description); #ifndef NDEBUG - abort(); + ::abort(); #endif } \ No newline at end of file diff --git a/source/memory/new.cpp b/source/memory/new.cpp index e685da1..495d722 100644 --- a/source/memory/new.cpp +++ b/source/memory/new.cpp @@ -29,10 +29,10 @@ #else // Allocation functions -inline void* operator new (fennec::size_t size) { return malloc(size); } -inline void* operator new[](fennec::size_t size) { return malloc(size); } -inline void* operator new (fennec::size_t size, const fennec::nothrow_t&) { return malloc(size); } -inline void* operator new[](fennec::size_t size, const fennec::nothrow_t&) { return malloc(size); } +inline void* operator new (fennec::size_t size) { return ::malloc(size); } +inline void* operator new[](fennec::size_t size) { return ::malloc(size); } +inline void* operator new (fennec::size_t size, const fennec::nothrow_t&) { return ::malloc(size); } +inline void* operator new[](fennec::size_t size, const fennec::nothrow_t&) { return ::malloc(size); } // Aligned allocation & deallocation functions #ifdef _WIN32 @@ -46,31 +46,31 @@ inline void* operator new[](fennec::size_t size, fennec::align_t align) inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast(align), size); } inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast(align), size); } #else -inline void operator delete (void* ptr) noexcept { free(ptr); } -inline void operator delete[](void* ptr) noexcept { free(ptr); } -inline void operator delete (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { free(ptr); } -inline void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { free(ptr); } +inline void operator delete (void* ptr) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr) noexcept { ::free(ptr); } +inline void operator delete (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } -inline void* operator new (fennec::size_t size, fennec::align_t align) { return aligned_alloc(static_cast(align), size); } -inline void* operator new[](fennec::size_t size, fennec::align_t align) { return aligned_alloc(static_cast(align), size); } -inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return aligned_alloc(static_cast(align), size); } -inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return aligned_alloc(static_cast(align), size); } +inline void* operator new (fennec::size_t size, fennec::align_t align) { return ::aligned_alloc(static_cast(align), size); } +inline void* operator new[](fennec::size_t size, fennec::align_t align) { return ::aligned_alloc(static_cast(align), size); } +inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast(align), size); } +inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast(align), size); } #endif // Aligned deallocation functions -inline void operator delete (void* ptr, fennec::align_t) noexcept { free(ptr); } -inline void operator delete[](void* ptr, fennec::align_t) noexcept { free(ptr); } +inline void operator delete (void* ptr, fennec::align_t) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::align_t) noexcept { ::free(ptr); } // Sized deallocation functions -inline void operator delete (void* ptr, fennec::size_t) noexcept { free(ptr); } -inline void operator delete[](void* ptr, fennec::size_t) noexcept { free(ptr); } -inline void operator delete (void* ptr, fennec::size_t, fennec::align_t) noexcept { free(ptr); } -inline void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { free(ptr); } +inline void operator delete (void* ptr, fennec::size_t) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::size_t) noexcept { ::free(ptr); } +inline void operator delete (void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); } // Non-throwing deallocation functions -inline void operator delete (void* ptr, const fennec::nothrow_t&) noexcept { free(ptr); } -inline void operator delete[](void* ptr, const fennec::nothrow_t&) noexcept { free(ptr); } -inline void operator delete (void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept { free(ptr); } -inline void operator delete[](void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept { free(ptr); } +inline void operator delete (void* ptr, const fennec::nothrow_t&) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, const fennec::nothrow_t&) noexcept { ::free(ptr); } +inline void operator delete (void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } #endif \ No newline at end of file diff --git a/test/test.h b/test/test.h index 6cca29a..8b8f750 100644 --- a/test/test.h +++ b/test/test.h @@ -51,9 +51,6 @@ inline std::ostream& operator<<(std::ostream& os, const matrix(std::ostream& os, index_sequence) { - // ((os << fennec::row(m, i) << " "), ...); - //}(os, make_index_sequence{}); os << "]"; return os; } @@ -97,7 +94,7 @@ inline void __fennec_test_run(const std::string& expression, const ResultT resul std::cout << std::endl; // Assert to halt and get some debug info - assert(passed); + assert(passed, "Test Failed"); } }