Compare commits

...

2 Commits

Author SHA1 Message Date
a33bf5206f - Stacktrace generation with failed asserts 2025-07-05 14:22:59 -04:00
0afaae72ac - Micro Optimization 2025-07-02 18:23:53 -04:00
23 changed files with 532 additions and 193 deletions

3
.gitmodules vendored
View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -31,6 +31,8 @@
may be used through the provided editor application, or as a standalone library to
link against your application.
<br>
<a id="coding-standards"></a>

View File

@@ -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.

1
external/cpptrace vendored Submodule

Submodule external/cpptrace added at 9133b90a99

View File

@@ -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]; }

View File

@@ -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 <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#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 <ctype.h>
#pragma pop_macro("__cplusplus")
#if _MSC_VER
#pragma warning(pop)
#endif
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H

View File

@@ -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 <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_STRING_H
#define FENNEC_FPROC_STRINGS_STRING_H
#include <fennec/fproc/strings/detail/__ctype.h>
#include <fennec/lang/assert.h>
#include <fennec/memory/allocator.h>
#include <fennec/memory/memory.h>
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<typename AllocT = allocator<char>>
struct string
{
public:
using alloc_t = allocation<char, AllocT>;
///
/// \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<size_t N>
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

View File

@@ -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

View File

@@ -153,17 +153,6 @@
/// \copybrief fennec::int64_t
///
///
///// <tr><td width="50%" style="vertical-align: top"> <br>
///// <tt>\ref fennec::float32_t "float32_t"</tt>
///// <td width="50%" style="vertical-align: top">
///// \copybrief fennec::float32_t
/////
///// <tr><td width="50%" style="vertical-align: top"> <br>
///// <tt>\ref fennec::float64_t "float64_t"</tt>
///// <td width="50%" style="vertical-align: top">
///// \copybrief fennec::float64_t
///
///
/// <tr><th colspan=2 style="text-align: center;">Special Types
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// <tt>\ref fennec::nullptr_t "nullptr_t"</tt>

View File

@@ -461,12 +461,13 @@ constexpr genType roundEven(genType x)
//bool up = r - fennec::floor(r) > e;
//return i + static_cast<genType>(up);
static const genType e = std::numeric_limits<genType>::epsilon();
genType i = fennec::floor(x);
int I = static_cast<int>(x);
genType i = static_cast<genType>(I);
genType f = x - i;
if (abs(f - genType(0.5)) > e)
return fennec::round(x);
bool dir = (static_cast<int>(x) % 2);
bool dir = (I % 2);
return dir ? i + 1 : i;
}

View File

@@ -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]; }
/// @}

View File

@@ -710,7 +710,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \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] ...); }

View File

@@ -22,6 +22,7 @@
#include <fennec/memory/ptr_traits.h>
#include <fennec/lang/conditional_types.h>
#include <fennec/lang/numeric_transforms.h>
#include <fennec/lang/types.h>
#include <fennec/lang/type_traits.h>
#include <fennec/math/common.h>
@@ -64,7 +65,7 @@ private:
struct __diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };
template<typename AllocT, typename DiffT, typename = void>
struct __size : std::make_unsigned<DiffT> {};
struct __size : make_unsigned<DiffT> {};
template<typename AllocT, typename DiffT>
struct __size<AllocT, DiffT, void_t<typename AllocT::size_t>> { 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;

View File

@@ -21,46 +21,32 @@
#include <fennec/lang/types.h>
namespace fennec
{
namespace detail
{
constexpr size_t __memcpy_8(void* dst, const void* src)
{ *static_cast<uint8_t*>(dst) = *static_cast<const uint8_t*>(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<uint16_t*>(dst) = *static_cast<const uint16_t*>(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<uint32_t*>(dst) = *static_cast<const uint32_t*>(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<uint64_t*>(dst) = *static_cast<const uint64_t*>(src); return 8; }
#pragma push_macro("__cplusplus")
#undef __cplusplus
#include <string.h>
#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

View File

@@ -21,7 +21,7 @@
#define FENNEC_MEMORY_H
#include <fennec/lang/type_traits.h>
#include <fennec/memory/detail/__memory.h>
#include <fennec/memory/detail/__string.h>
namespace fennec
{
@@ -34,27 +34,14 @@ namespace fennec
template<typename TypeT>
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<uint8_t*>(arr);
while (n-- && *a++ != ch) {}
return n ? a : nullptr;
}
///
/// \brief Finds the first occurence of ```static_cast<uint8_t>(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<const uint8_t*>(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<const uint8_t*>(lhs);
const uint8_t* rhs_ = static_cast<const uint8_t*>(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<uint8_t*>(dst);
const uint8_t* s = static_cast<const uint8_t*>(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<uint8_t*>(dst);
const uint8_t* s = static_cast<const uint8_t*>(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<uint8_t*>(dst);
uint8_t val[8] = { static_cast<uint8_t>(ch) };
while (n > 0) {
size_t step = detail::__memcpy(d, val, n);
d += step; n -= step;
}
return dst;
}
using ::memset;
using ::wmemset;
}

View File

@@ -20,8 +20,6 @@
#ifndef FENNEC_MEMORY_NEW_H
#define FENNEC_MEMORY_NEW_H
#include <new>
#include <fennec/lang/types.h>
#include <fennec/lang/utility.h>

View File

@@ -16,7 +16,16 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
void __assert_callback(const char*, const char*, int, const char*)
{
#include <cpptrace/cpptrace.hpp>
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();
}

View File

@@ -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
}

View File

@@ -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<size_t>(align), size); }
inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast<size_t>(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<size_t>(align), size); }
inline void* operator new[](fennec::size_t size, fennec::align_t align) { return aligned_alloc(static_cast<size_t>(align), size); }
inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return aligned_alloc(static_cast<size_t>(align), size); }
inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return aligned_alloc(static_cast<size_t>(align), size); }
inline void* operator new (fennec::size_t size, fennec::align_t align) { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }
inline void* operator new[](fennec::size_t size, fennec::align_t align) { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }
inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }
inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast<fennec::size_t>(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

View File

@@ -51,9 +51,6 @@ inline std::ostream& operator<<(std::ostream& os, const matrix<ScalarT, RowsV, C
{
os << "[ ";
((os << m[ColIndicesV] << " "), ...);
//[m]<size_t...i>(std::ostream& os, index_sequence<i...>) {
// ((os << fennec::row(m, i) << " "), ...);
//}(os, make_index_sequence<RowsV>{});
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");
}
}