From 17d82181240b8945a0ea9f11a62da8dcb607fed0 Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Mon, 7 Jul 2025 01:09:54 -0400 Subject: [PATCH] - Adjusted how asserts work and types of asserts --- include/fennec/containers/array.h | 29 ++---- include/fennec/fproc/io/file.h | 1 + include/fennec/fproc/strings/cstring.h | 120 +++++++++++++++++-------- include/fennec/fproc/strings/string.h | 55 +++++++++--- include/fennec/lang/assert.h | 10 ++- include/fennec/math/matrix.h | 8 +- 6 files changed, 152 insertions(+), 71 deletions(-) diff --git a/include/fennec/containers/array.h b/include/fennec/containers/array.h index e08dbae..74b4dfe 100644 --- a/include/fennec/containers/array.h +++ b/include/fennec/containers/array.h @@ -55,28 +55,12 @@ struct array /// \name Element Access /// @{ - /// - /// \copydetails array::at(size_t) const - 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** - /// \details Returns a reference to the element at \c i - /// \param i index of the element to return - /// \return reference to the requested element - /// - /// \par Time-Complexity - /// Constant - /// - /// \par Space-Complexity - /// Constant - constexpr const ValueT& at(size_t i) const { static_assert(i < ElemV); assert(i < ElemV, "Array Out of Bounds"); return elements[i]; } - - - /// /// \copydetails array::operator[](size_t) const - constexpr ValueT& operator[](size_t i) { return elements[i]; } + constexpr ValueT& operator[](size_t i) { + assertd(i < ElemV, "Array Out of Bounds"); + return elements[i]; + } /// /// \brief access specified element @@ -89,7 +73,10 @@ struct array /// /// \par Space-Complexity /// Constant - constexpr const ValueT& operator[](size_t i) const { return elements[i]; } + constexpr const ValueT& operator[](size_t i) const { + assertd(i < ElemV, "Array Out of Bounds"); + return elements[i]; + } /// @} diff --git a/include/fennec/fproc/io/file.h b/include/fennec/fproc/io/file.h index 2d28d9e..8897e60 100644 --- a/include/fennec/fproc/io/file.h +++ b/include/fennec/fproc/io/file.h @@ -22,6 +22,7 @@ #include struct FILE; +struct stat; namespace fennec { diff --git a/include/fennec/fproc/strings/cstring.h b/include/fennec/fproc/strings/cstring.h index 1a03b2e..4a2f613 100644 --- a/include/fennec/fproc/strings/cstring.h +++ b/include/fennec/fproc/strings/cstring.h @@ -60,7 +60,7 @@ public: /// /// \brief Default Constructor, initializes with nullptr constexpr cstring() - : _str(nullptr), _len(0), _const(true) + : _str(nullptr), _size(0), _const(true) { } /// @@ -68,7 +68,9 @@ public: /// \param str the buffer to wrap /// \param n the number of characters in the buffer plus the null terminator constexpr cstring(char* str, size_t n) - : _str(str), _len(n - 1), _const(false) + : _str(str) + , _size(n - 1) + , _const(false) { assert(_str[n - 1] == '\0', "Invalid NTBS."); } /// @@ -77,7 +79,9 @@ public: /// \tparam n the number of characters in the buffer plus the null terminator template constexpr cstring(char(&str)[n]) - : _str(str), _len(n - 1), _const(false) + : _str(str) + , _size(n - 1) + , _const(false) { assert(_str[n - 1] == '\0', "Invalid NTBS."); } /// @@ -85,7 +89,9 @@ public: /// \param str the buffer to wrap /// \param n the number of characters in the buffer plus the null terminator constexpr cstring(const char* str, size_t n) - : _cstr(str), _len(n - 1), _const(true) + : _cstr(str) + , _size(n - 1) + , _const(true) { assert(_cstr[n - 1] == '\0', "Invalid NTBS."); } /// @@ -94,15 +100,23 @@ public: /// \tparam n the number of characters in the buffer plus the null terminator template constexpr cstring(const char(&str)[n]) - : _cstr(str), _len(n - 1), _const(true) + : _cstr(str) + , _size(n - 1) + , _const(true) { assert(_cstr[n - 1] == '\0', "Invalid NTBS."); } /// /// \brief Move Constructor /// \param str object to move - constexpr cstring(cstring&& str) - : _cstr(str._cstr), _len(str._len) - { } + constexpr cstring(cstring&& str) noexcept + : _cstr(str._cstr) + , _size(str._size) + , _const(str._const) + { + str._cstr = nullptr; + str._size = 0; + str._const = true; + } constexpr cstring(const cstring&) = delete; constexpr ~cstring() = default; @@ -110,21 +124,31 @@ public: template constexpr cstring& operator=(char(&str)[n]) { assert(_str[n - 1] == '\0', "Invalid NTBS."); - _str = str; _len = n - 1; _const = false; + _str = str; _size = n - 1; _const = false; return *this; } template constexpr cstring& operator=(const char(&str)[n]) { assert(str[n - 1] == '\0', "Invalid NTBS."); - _cstr = str; _len = n - 1; _const = true; + _cstr = str; _size = n - 1; _const = true; + return *this; + } + + constexpr cstring& operator=(cstring&& str) noexcept + { + _cstr = str._cstr; str._cstr = nullptr; + _size = str._size; str._size = 0; + _const = str._const; str._const = true; return *this; } // Properties ========================================================================================================== - constexpr size_t size() const { return _len; } + /// + /// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'` + constexpr size_t size() const { return _size; } // Access ============================================================================================================== @@ -134,8 +158,8 @@ public: /// \param i the index to access /// \returns a reference to the character constexpr char& operator[](size_t i) { - assert(i < size(), "Array Out of Bounds"); - assert(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); + assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); + assertd(i < size(), "Array Out of Bounds"); return _str[i]; } @@ -144,7 +168,7 @@ public: /// \param i the index to access /// \returns a copy of the character constexpr char operator[](size_t i) const { - assert(i < size(), "Array Out of Bounds"); + assertd(i < size(), "Array Out of Bounds"); return _cstr[i]; } @@ -170,51 +194,77 @@ public: /// \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 cstring& str) const - { return ::strcoll(_cstr, str); } + constexpr int compare(const cstring& str, size_t i = 0) const + { + if (i >= _size) return -1; + return ::strcoll(_cstr + i, str); + } constexpr bool operator==(const cstring& str) const { return compare(str) == 0; } /// - /// \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 + /// \brief Finds the index of the first occurrence of `c` in the string + /// \param c the character to find + /// \param i the index to start at + /// \returns The index of `c` if it occurs in the string, otherwise returns `size()` + constexpr size_t find(char c, size_t i = 0) const { - const char* loc = ::strchr(_cstr, x); - return loc ? loc - _cstr : size(); + if (i >= _size) return _size; // bounds check + const char* loc = ::strchr(_cstr + i, c); // get location using strchr + return loc ? loc - _cstr : _size; // return size if not found } /// /// \brief Finds the index of the first occurrence of `str` in the string. /// \param str the string to find + /// \param i the index to start at /// \returns The index of `str` if it occurs in the string, otherwise returns `size()` - constexpr size_t find(const cstring& str) const + constexpr size_t find(const cstring& str, size_t i = 0) const { - const char* loc = ::strstr(_cstr, str); - return loc ? loc - _cstr : size(); + if (i + str._size > _size) return _size; // bounds check + const char* loc = ::strstr(_cstr + i, str); // get location using strstr + return loc ? loc - _cstr : _size; // return size if not found } /// - /// \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 + /// \brief Finds the index of the last occurrence of `c` in the string. + /// \param c the string to find + /// \param i the index to start at + /// \returns The index of `c` if it occurs in the string, otherwise returns `size()` + constexpr size_t rfind(char c, size_t i = 0) const { - const char* loc = ::strrchr(_cstr, x); - return loc ? loc - _cstr : size(); + if (_size == 0) return _size; + i = min(i, _size - 1); // clamp i to bounds + do { + if (_cstr[i] == c) return i; // loop backwards looking for c + } while (i--); + return _size; // base case } - // TODO: constexpr size_t rfind(const string& str) const; + /// + /// \brief Finds the index of the last occurrence of `str` in the string. + /// \param str the string to find + /// \param i the index to start at + /// \returns The index of `str` if it occurs in the string, otherwise returns `size()` + constexpr size_t rfind(const cstring& str, size_t i = 0) const + { + const char first = str[0]; + i = min(i, _size - str._size); + do { + if(_cstr[i] == first) + if (compare(str, i) == 0) return i; // loop backwards looking for str + } while (i--); + return _size; // base case + } private: - union { + union { // hack to allow both const qualified and non-const strings char* _str; const char* _cstr; }; - size_t _len; - bool _const; + size_t _size; + bool _const; }; } diff --git a/include/fennec/fproc/strings/string.h b/include/fennec/fproc/strings/string.h index e2e8147..7939681 100644 --- a/include/fennec/fproc/strings/string.h +++ b/include/fennec/fproc/strings/string.h @@ -107,7 +107,7 @@ public: /// \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"); + assertd(i >= 0 && i < size(), "Array Out of Bounds"); return _str[i]; } @@ -115,8 +115,8 @@ public: /// \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"); + constexpr char operator[](int i) const { + assertd(i >= 0 && i < size(), "Array Out of Bounds"); return _str[i]; } @@ -176,16 +176,51 @@ public: } /// - /// \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 + /// \brief Finds the index of the last occurrence of `c` in the string. + /// \param c the string to find + /// \param i the index to start at + /// \returns The index of `c` if it occurs in the string, otherwise returns `size()` + constexpr size_t rfind(char c, size_t i = 0) const { - const char* loc = ::strrchr(_str, x); - return loc ? loc - _str : size(); + if (size() == 0) return size(); + i = min(i, size() - 1); // clamp i to bounds + do { + if (_str[i] == c) return i; // loop backwards looking for c + } while (i--); + return size(); // base case } - // TODO: constexpr size_t rfind(const string& str) const; + /// + /// \brief Finds the index of the last occurrence of `str` in the string. + /// \param str the string to find + /// \param i the index to start at + /// \returns The index of `str` if it occurs in the string, otherwise returns `size()` + constexpr size_t rfind(const cstring& str, size_t i = 0) const + { + const char first = str[0]; + i = min(i, size() - str.size()); + do { + if(_str[i] == first) + if (compare(str, i) == 0) return i; // loop backwards looking for str + } while (i--); + return size(); // base case + } + + /// + /// \brief Finds the index of the last occurrence of `str` in the string. + /// \param str the string to find + /// \param i the index to start at + /// \returns The index of `str` if it occurs in the string, otherwise returns `size()` + constexpr size_t rfind(const string& str, size_t i = 0) const + { + const char first = str[0]; + i = min(i, size() - str.size()); + do { + if(_str[i] == first) + if (compare(str, i) == 0) return i; // loop backwards looking for str + } while (i--); + return size(); // base case + } // Manipulation ======================================================================================================== diff --git a/include/fennec/lang/assert.h b/include/fennec/lang/assert.h index 59bf1ab..fda3f56 100644 --- a/include/fennec/lang/assert.h +++ b/include/fennec/lang/assert.h @@ -27,7 +27,15 @@ 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, const char* desc); +// flagged unlikely to optimize branch prediction #define assert(expression, description) \ - if(not(expression)) { __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description); } + if(not(expression)) [[unlikely]] \ + { __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description); } + +#ifdef NDEBUG +#define assertd(expression, description) (0) +#else +#define assertd(expression, description) assert(expression, description) +#endif #endif // FENNEC_LANG_ASSERT_H diff --git a/include/fennec/math/matrix.h b/include/fennec/math/matrix.h index 7611825..cd41c75 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, "Array Out of Bounds"); return data[i]; } + { return data[i]; } /// /// \brief returns the column at index \f$i\f$ @@ -333,12 +333,12 @@ 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, "Array Out of Bounds"); return data[i]; } + { 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, "Array Out of Bounds"); return data[i][j]; } + { return data[i][j]; } /// /// \brief returns the cell in row \p j column \p i @@ -346,7 +346,7 @@ struct matrix /// \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, "Array Out of Bounds"); return data[i][j]; } + { return data[i][j]; } /// @}