diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f170fa6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,66 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/.gitignore b/.gitignore index 3bb6715..29e0bd2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,13 @@ -# Xmake cache -.xmake/ -build/ - -# MacOS Cache -.DS_Store/ - -# CMake -CMakeLists.txt -cmake-build-*/ - -# Idea +# Xmake cache +.xmake/ +build/ + +# MacOS Cache +.DS_Store/ + +# CMake +CMakeLists.txt +cmake-build-*/ + +# Idea .idea/ \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..fe830ec --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "windows-gcc", + "compileCommands": ".vscode/compile_commands.json", + "intelliSenseMode": "windows-gcc-x64", + "compilerPath": "C:/Users/Administrator/scoop/apps/msys2/current/mingw64/bin/gcc.exe", + "includePath": [ + "${workspaceFolder}/source" + ], + "cppStandard": "gnu++20" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/compile_commands.json b/.vscode/compile_commands.json new file mode 100644 index 0000000..9fbc212 --- /dev/null +++ b/.vscode/compile_commands.json @@ -0,0 +1,26 @@ +[ +{ + "directory": "c:\\Users\\Administrator\\Projects\\hpr", + "arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include\\imgui", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include\\backends", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include\\misc\\cpp", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\implot\\v0.15\\6861f774eb2844d6a543372e119845e3\\include", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include\\imgui", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include\\backends", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include\\misc\\cpp", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\glfw\\3.3.8\\d31abc5641874d8fbdc13f33b5569420\\include", "-IC:\\Users\\Administrator\\scoop\\apps\\msys2\\2023-10-26\\mingw64\\include", "-IC:\\Users\\Administrator\\scoop\\apps\\msys2\\2023-10-26\\mingw64\\include\\opencascade", "-DHPR_SCALAR=float", "-DGLFW_INCLUDE_NONE", "-DNDEBUG", "-o", "build\\.objs\\hpr\\mingw\\x86_64\\release\\source\\hpr\\hpr.cpp.obj", "source\\hpr\\hpr.cpp"], + "file": "source\\hpr\\hpr.cpp" +}, +{ + "directory": "c:\\Users\\Administrator\\Projects\\hpr", + "arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\main.cpp.obj", "source\\hpr\\tests\\main.cpp"], + "file": "source\\hpr\\tests\\main.cpp" +}, +{ + "directory": "c:\\Users\\Administrator\\Projects\\hpr", + "arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\test_container.cpp.obj", "source\\hpr\\tests\\test_container.cpp"], + "file": "source\\hpr\\tests\\test_container.cpp" +}, +{ + "directory": "c:\\Users\\Administrator\\Projects\\hpr", + "arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\test_math.cpp.obj", "source\\hpr\\tests\\test_math.cpp"], + "file": "source\\hpr\\tests\\test_math.cpp" +}, +{ + "directory": "c:\\Users\\Administrator\\Projects\\hpr", + "arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\test_numeric.cpp.obj", "source\\hpr\\tests\\test_numeric.cpp"], + "file": "source\\hpr\\tests\\test_numeric.cpp" +}] diff --git a/source/hpr/container.hpp b/source/hpr/container.hpp index 52ae007..71d7456 100644 --- a/source/hpr/container.hpp +++ b/source/hpr/container.hpp @@ -1,7 +1,7 @@ -#pragma once - -#include -#include -#include -#include -#include +#pragma once + +#include +#include +#include +#include +#include diff --git a/source/hpr/container/dynamic_array.hpp b/source/hpr/container/dynamic_array.hpp index 8b3abe8..d8fb627 100644 --- a/source/hpr/container/dynamic_array.hpp +++ b/source/hpr/container/dynamic_array.hpp @@ -1,307 +1,307 @@ -#pragma once - -#include - -#include -#include - - -namespace hpr -{ - // forward declaration - - template - class DynamicArray; - - // type traits - - template - struct is_sequence> : public std::true_type - {}; - - // aliases - - template - using darray = DynamicArray; - - // class definition - - template - class DynamicArray : public Sequence - { - - using base = Sequence; - - public: - - using difference_type = std::ptrdiff_t; - using value_type = T; - using size_type = Size; - using pointer = T*; - using reference = T&; - using iterator = Iterator; - using const_pointer = T const*; - using const_reference = T const&; - using const_iterator = Iterator; - - public: - - friend constexpr - void swap(DynamicArray& main, DynamicArray& other) noexcept - { - using std::swap; - swap(static_cast(main), static_cast(other)); - } - - constexpr - DynamicArray() noexcept : - base {} - {} - - constexpr explicit - DynamicArray(const base& b) noexcept : - base {b} - {} - - constexpr explicit - DynamicArray(base&& b) noexcept : - base {std::forward(b)} - {} - - constexpr - DynamicArray(const DynamicArray& arr) noexcept : - base {static_cast(arr)} - {} - - //! Move constructor - constexpr - DynamicArray(DynamicArray&& arr) noexcept : - base {std::forward(static_cast(arr))} - {} - - template - constexpr - DynamicArray(Iter start, Iter end) : - base {start, end} - {} - - constexpr - DynamicArray(typename base::iterator start, typename base::iterator end) : - base {start, end} - {} - - constexpr - DynamicArray(typename base::const_iterator start, typename base::const_iterator end) : - base {start, end} - {} - - constexpr - DynamicArray(typename base::iterator start, typename base::iterator end, size_type capacity) : - base {start, end, capacity} - {} - - constexpr - DynamicArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) : - base {start, end, capacity} - {} - - constexpr - DynamicArray(std::initializer_list list) : - base {list.begin(), list.end()} - {} - - constexpr - DynamicArray(size_type size, value_type value) noexcept : - base {size, value} - {} - - constexpr - DynamicArray& operator=(base other) noexcept - { - swap(*this, other); - return *this; - } - - constexpr - DynamicArray& operator=(DynamicArray other) noexcept - { - swap(*this, other); - return *this; - } - - constexpr - DynamicArray& operator=(DynamicArray&& arr) noexcept - { - swap(*this, arr); - return *this; - } - - virtual - ~DynamicArray() = default; - - // Member functions - - [[nodiscard]] virtual constexpr - size_type capacity() const noexcept - { - return base::p_capacity; - } - - [[nodiscard]] virtual constexpr - bool is_empty() const - { - return base::begin() == base::end(); - } - - virtual constexpr - iterator storage_end() - { - return iterator(base::p_start + base::p_capacity); - } - - virtual constexpr - const_iterator storage_end() const - { - return const_iterator(base::p_start + base::p_capacity); - } - - virtual constexpr - void resize(size_type newCapacity) - { - if (newCapacity == base::p_capacity) - return; - - if (std::numeric_limits::max() - base::size() < newCapacity) - throw hpr::LengthError("Invalid capacity value passed"); - - if (newCapacity > base::p_capacity) - { - DynamicArray tmp {base::begin(), base::end(), newCapacity}; - swap(*this, tmp); - } - else - { - if (newCapacity >= base::p_size) - { - DynamicArray tmp {base::begin(), base::end()}; - swap(*this, tmp); - } - else - { - DynamicArray tmp {base::begin(), base::begin() + newCapacity}; - swap(*this, tmp); - } - } - } - - virtual constexpr - void push(const value_type& val) - { - if (base::end() == storage_end()) - resize(base::p_capacity * 2); - *base::end() = val; - ++base::p_size; - } - - virtual constexpr - void push(value_type&& val) - { - if (base::end() == storage_end()) - resize(base::p_capacity * 2); - *base::end() = std::move(val); - ++base::p_size; - } - - virtual constexpr - void push(const DynamicArray& arr) - { - for (const value_type& el : arr) - push(el); - } - - virtual constexpr - value_type pop() - { - if (is_empty()) - throw hpr::LengthError("Cannot pop element from empty array"); - value_type val = base::back(); - std::destroy_at(base::p_start + base::p_size); - --base::p_size; - return val; - } - - virtual constexpr - void insert(size_type position, const value_type& val) - { - if (base::end() == storage_end()) - resize(base::p_capacity * 2); - for (size_type n = base::p_size; n > position; --n) - *(base::p_start + n) = std::move(*(base::p_start + n - 1)); - *(base::p_start + position) = val; - ++base::p_size; - } - - virtual constexpr - void insert(size_type position, value_type&& val) - { - if (base::end() == storage_end()) - resize(base::p_capacity * 2); - for (size_type n = base::p_size; n > position; --n) - *(base::p_start + n) = std::move(*(base::p_start + n - 1)); - *(base::p_start + position) = std::move(val); - ++base::p_size; - } - - virtual constexpr - void remove(size_type position) - { - for (size_type n = position; n < base::p_size - 1; ++n) - *(base::p_start + n) = std::move(*(base::p_start + n + 1)); - std::destroy_at(base::p_start + base::p_size); - --base::p_size; - } - - virtual constexpr - void remove(iterator position) - { - if (position + 1 != base::end()) - std::copy(position + 1, base::end(), position); - std::destroy_at(base::p_start + base::p_size); - --base::p_size; - } - - virtual constexpr - void remove(const std::function& condition) - { - size_type newSize = base::p_size; - for (size_type offset = 0; offset < newSize; ++offset) - { - if (condition(*(base::p_start + offset))) - { - for (size_type n = offset; n < newSize; ++n) - *(base::p_start + n) = std::move(*(base::p_start + n + 1)); - - --newSize; - --offset; - } - } - base::p_size = newSize; - } - - virtual constexpr - void clear() - { - delete[] base::p_start; - base::p_size = 0; - base::p_capacity = 1; - base::p_start = new value_type[base::p_capacity]; - } - - DynamicArray slice(iterator start, iterator end) - { - return DynamicArray {start, end}; - } - - }; - +#pragma once + +#include + +#include +#include + + +namespace hpr +{ + // forward declaration + + template + class DynamicArray; + + // type traits + + template + struct is_sequence> : public std::true_type + {}; + + // aliases + + template + using darray = DynamicArray; + + // class definition + + template + class DynamicArray : public Sequence + { + + using base = Sequence; + + public: + + using difference_type = std::ptrdiff_t; + using value_type = T; + using size_type = Size; + using pointer = T*; + using reference = T&; + using iterator = Iterator; + using const_pointer = T const*; + using const_reference = T const&; + using const_iterator = Iterator; + + public: + + friend constexpr + void swap(DynamicArray& main, DynamicArray& other) noexcept + { + using std::swap; + swap(static_cast(main), static_cast(other)); + } + + constexpr + DynamicArray() noexcept : + base {} + {} + + constexpr explicit + DynamicArray(const base& b) noexcept : + base {b} + {} + + constexpr explicit + DynamicArray(base&& b) noexcept : + base {std::forward(b)} + {} + + constexpr + DynamicArray(const DynamicArray& arr) noexcept : + base {static_cast(arr)} + {} + + //! Move constructor + constexpr + DynamicArray(DynamicArray&& arr) noexcept : + base {std::forward(static_cast(arr))} + {} + + template + constexpr + DynamicArray(Iter start, Iter end) : + base {start, end} + {} + + constexpr + DynamicArray(typename base::iterator start, typename base::iterator end) : + base {start, end} + {} + + constexpr + DynamicArray(typename base::const_iterator start, typename base::const_iterator end) : + base {start, end} + {} + + constexpr + DynamicArray(typename base::iterator start, typename base::iterator end, size_type capacity) : + base {start, end, capacity} + {} + + constexpr + DynamicArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) : + base {start, end, capacity} + {} + + constexpr + DynamicArray(std::initializer_list list) : + base {list.begin(), list.end()} + {} + + constexpr + DynamicArray(size_type size, value_type value) noexcept : + base {size, value} + {} + + constexpr + DynamicArray& operator=(base other) noexcept + { + swap(*this, other); + return *this; + } + + constexpr + DynamicArray& operator=(DynamicArray other) noexcept + { + swap(*this, other); + return *this; + } + + constexpr + DynamicArray& operator=(DynamicArray&& arr) noexcept + { + swap(*this, arr); + return *this; + } + + virtual + ~DynamicArray() = default; + + // Member functions + + [[nodiscard]] virtual constexpr + size_type capacity() const noexcept + { + return base::p_capacity; + } + + [[nodiscard]] virtual constexpr + bool is_empty() const + { + return base::begin() == base::end(); + } + + virtual constexpr + iterator storage_end() + { + return iterator(base::p_start + base::p_capacity); + } + + virtual constexpr + const_iterator storage_end() const + { + return const_iterator(base::p_start + base::p_capacity); + } + + virtual constexpr + void resize(size_type newCapacity) + { + if (newCapacity == base::p_capacity) + return; + + if (std::numeric_limits::max() - base::size() < newCapacity) + throw hpr::LengthError("Invalid capacity value passed"); + + if (newCapacity > base::p_capacity) + { + DynamicArray tmp {base::begin(), base::end(), newCapacity}; + swap(*this, tmp); + } + else + { + if (newCapacity >= base::p_size) + { + DynamicArray tmp {base::begin(), base::end()}; + swap(*this, tmp); + } + else + { + DynamicArray tmp {base::begin(), base::begin() + newCapacity}; + swap(*this, tmp); + } + } + } + + virtual constexpr + void push(const value_type& val) + { + if (base::end() == storage_end()) + resize(base::p_capacity * 2); + *base::end() = val; + ++base::p_size; + } + + virtual constexpr + void push(value_type&& val) + { + if (base::end() == storage_end()) + resize(base::p_capacity * 2); + *base::end() = std::move(val); + ++base::p_size; + } + + virtual constexpr + void push(const DynamicArray& arr) + { + for (const value_type& el : arr) + push(el); + } + + virtual constexpr + value_type pop() + { + if (is_empty()) + throw hpr::LengthError("Cannot pop element from empty array"); + value_type val = base::back(); + std::destroy_at(base::p_start + base::p_size); + --base::p_size; + return val; + } + + virtual constexpr + void insert(size_type position, const value_type& val) + { + if (base::end() == storage_end()) + resize(base::p_capacity * 2); + for (size_type n = base::p_size; n > position; --n) + *(base::p_start + n) = std::move(*(base::p_start + n - 1)); + *(base::p_start + position) = val; + ++base::p_size; + } + + virtual constexpr + void insert(size_type position, value_type&& val) + { + if (base::end() == storage_end()) + resize(base::p_capacity * 2); + for (size_type n = base::p_size; n > position; --n) + *(base::p_start + n) = std::move(*(base::p_start + n - 1)); + *(base::p_start + position) = std::move(val); + ++base::p_size; + } + + virtual constexpr + void remove(size_type position) + { + for (size_type n = position; n < base::p_size - 1; ++n) + *(base::p_start + n) = std::move(*(base::p_start + n + 1)); + std::destroy_at(base::p_start + base::p_size); + --base::p_size; + } + + virtual constexpr + void remove(iterator position) + { + if (position + 1 != base::end()) + std::copy(position + 1, base::end(), position); + std::destroy_at(base::p_start + base::p_size); + --base::p_size; + } + + virtual constexpr + void remove(const std::function& condition) + { + size_type newSize = base::p_size; + for (size_type offset = 0; offset < newSize; ++offset) + { + if (condition(*(base::p_start + offset))) + { + for (size_type n = offset; n < newSize; ++n) + *(base::p_start + n) = std::move(*(base::p_start + n + 1)); + + --newSize; + --offset; + } + } + base::p_size = newSize; + } + + virtual constexpr + void clear() + { + delete[] base::p_start; + base::p_size = 0; + base::p_capacity = 1; + base::p_start = new value_type[base::p_capacity]; + } + + DynamicArray slice(iterator start, iterator end) + { + return DynamicArray {start, end}; + } + + }; + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/container/iterator.hpp b/source/hpr/container/iterator.hpp index 32db78a..8cb4d3f 100644 --- a/source/hpr/container/iterator.hpp +++ b/source/hpr/container/iterator.hpp @@ -1,98 +1,98 @@ -#pragma once - -#include - - -namespace hpr -{ - - template - class Iterator - { - - public: - - using iterator_category = Category; - using difference_type = std::ptrdiff_t; - using value_type = Type; - using pointer = Type*; - using reference = Type&; - using iterator = Iterator; - using const_pointer = Type const*; - using const_reference = Type const&; - using const_iterator = Iterator const; - - protected: - - pointer p_ptr; - - public: - - Iterator() : - p_ptr {nullptr} - {} - - Iterator(pointer ptr) : - p_ptr {ptr} - {} - - reference operator*() - { - return *p_ptr; - } - - const_reference operator*() const - { - return *p_ptr; - } - - pointer operator->() - { - return p_ptr; - } - - const_pointer operator->() const - { - return p_ptr; - } - - iterator& operator++() - { - p_ptr++; - return *this; - } - - const_iterator& operator++() const - { - p_ptr++; - return *this; - } - - iterator operator++(int) - { - iterator temp {*this}; - ++(*this); - return temp; - } - - iterator operator+(int value) - { - iterator temp {*this}; - temp.p_ptr += value; - return temp; - } - - friend - bool operator==(const iterator& lhs, const iterator& rhs) - { - return lhs.p_ptr == rhs.p_ptr; - } - - friend - bool operator!=(const iterator& lhs, const iterator& rhs) - { - return lhs.p_ptr != rhs.p_ptr; - } - }; - -} // end namespace hpr +#pragma once + +#include + + +namespace hpr +{ + + template + class Iterator + { + + public: + + using iterator_category = Category; + using difference_type = std::ptrdiff_t; + using value_type = Type; + using pointer = Type*; + using reference = Type&; + using iterator = Iterator; + using const_pointer = Type const*; + using const_reference = Type const&; + using const_iterator = Iterator const; + + protected: + + pointer p_ptr; + + public: + + Iterator() : + p_ptr {nullptr} + {} + + Iterator(pointer ptr) : + p_ptr {ptr} + {} + + reference operator*() + { + return *p_ptr; + } + + const_reference operator*() const + { + return *p_ptr; + } + + pointer operator->() + { + return p_ptr; + } + + const_pointer operator->() const + { + return p_ptr; + } + + iterator& operator++() + { + p_ptr++; + return *this; + } + + const_iterator& operator++() const + { + p_ptr++; + return *this; + } + + iterator operator++(int) + { + iterator temp {*this}; + ++(*this); + return temp; + } + + iterator operator+(int value) + { + iterator temp {*this}; + temp.p_ptr += value; + return temp; + } + + friend + bool operator==(const iterator& lhs, const iterator& rhs) + { + return lhs.p_ptr == rhs.p_ptr; + } + + friend + bool operator!=(const iterator& lhs, const iterator& rhs) + { + return lhs.p_ptr != rhs.p_ptr; + } + }; + +} // end namespace hpr diff --git a/source/hpr/container/sequence.hpp b/source/hpr/container/sequence.hpp index fffac31..555f4cc 100644 --- a/source/hpr/container/sequence.hpp +++ b/source/hpr/container/sequence.hpp @@ -1,319 +1,319 @@ -#pragma once - -#include -#include -#include - - -namespace hpr -{ - // forward declaration - - template - class Sequence; - - // type traits - - template - struct is_sequence : public std::false_type - {}; - - template - struct is_sequence> : public std::true_type - {}; - - // concepts - - template - concept IsSequence = is_sequence::value; - - // class definition - - template - class Sequence - { - - public: - - using difference_type = std::ptrdiff_t; - using value_type = T; - using size_type = Size; - using pointer = T*; - using reference = T&; - using iterator = Iterator; - using const_pointer = T const*; - using const_reference = T const&; - using const_iterator = Iterator; - - protected: - - size_type p_size; - size_type p_capacity; - pointer p_start; - - protected: - - constexpr - Sequence(size_type size, size_type capacity, pointer start) : - p_size {size}, - p_capacity {capacity}, - p_start {start} - {} - - constexpr explicit - Sequence(size_type size, size_type capacity) : - p_size {size}, - p_capacity {capacity}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - {} - - public: - - friend constexpr - void swap(Sequence& main, Sequence& other) noexcept - { - using std::swap; - swap(main.p_size, other.p_size); - swap(main.p_capacity, other.p_capacity); - swap(main.p_start, other.p_start); - } - - constexpr - Sequence() noexcept : - p_size {0}, - p_capacity {1}, - p_start {new value_type[p_capacity]} - {} - - constexpr - Sequence(const Sequence& seq) noexcept : - p_size {seq.p_size}, - p_capacity {seq.p_capacity}, - p_start {p_capacity ? new value_type[seq.p_capacity] : nullptr} - { - std::copy(seq.p_start, seq.p_start + seq.p_size, p_start); - } - - //! Move constructor - constexpr - Sequence(Sequence&& seq) noexcept : - Sequence {} - { - swap(*this, seq); - } - - template - constexpr - Sequence(Iter start, Iter end) : - p_size {static_cast(std::distance(start, end))}, - p_capacity {p_size}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - { - std::copy(start, end, p_start); - } - - constexpr - Sequence(iterator start, iterator end) : - p_size {static_cast(std::distance(start, end))}, - p_capacity {p_size}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - { - std::copy(start, end, p_start); - } - - constexpr - Sequence(const_iterator start, const_iterator end) : - p_size {static_cast(std::distance(start, end))}, - p_capacity {p_size}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - { - std::copy(start, end, p_start); - } - - constexpr - Sequence(iterator start, iterator end, size_type capacity) : - p_size {static_cast(std::distance(start, end))}, - p_capacity {capacity}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - { - std::copy(start, end, p_start); - } - - constexpr - Sequence(const_iterator start, const_iterator end, size_type capacity) : - p_size {static_cast(std::distance(start, end))}, - p_capacity {capacity}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - { - std::copy(start, end, p_start); - } - - /*constexpr - Sequence(std::initializer_list list) : - Sequence {list.begin(), list.end()} - {}*/ - - constexpr - Sequence(size_type size, value_type value) noexcept: - p_size {size}, - p_capacity {size}, - p_start {p_capacity ? new value_type[p_capacity] : nullptr} - { - for (auto n = 0; n < size; ++n) - *(p_start + n) = value; - } - - constexpr - Sequence& operator=(Sequence other) noexcept - { - swap(*this, other); - return *this; - } - - constexpr - Sequence& operator=(Sequence&& seq) noexcept - { - swap(*this, seq); - return *this; - } - - virtual - ~Sequence() - { - delete[] p_start; - } - - - // Member functions - - virtual constexpr - iterator begin() - { - return iterator(p_start); - } - - [[nodiscard]] virtual constexpr - const_iterator begin() const - { - return const_iterator(p_start); - } - - virtual constexpr - iterator end() - { - return iterator(p_start + p_size); - } - - virtual constexpr - const_iterator end() const - { - return const_iterator(p_start + p_size); - } - - virtual constexpr - iterator storage_end() - { - return iterator(p_start + p_capacity); - } - - virtual constexpr - const_iterator storage_end() const - { - return const_iterator(p_start + p_capacity); - } - - [[nodiscard]] virtual constexpr - size_type size() const noexcept - { - return p_size; - } - - virtual constexpr - reference operator[](size_type n) - { - if (n >= size()) - throw hpr::OutOfRange(); - return *(p_start + n); - } - - virtual constexpr - const_reference operator[](size_type n) const - { - if (n >= size()) - throw hpr::OutOfRange(); - return *(p_start + n); - } - - virtual constexpr - reference at(size_type n) - { - return operator[](n); - } - - virtual constexpr - const_reference at(size_type n) const - { - return operator[](n); - } - - virtual constexpr - reference front() - { - return *begin(); - } - - virtual constexpr - const_reference front() const - { - return *begin(); - } - - virtual constexpr - reference back() - { - return *(p_start + p_size - 1); - } - - virtual constexpr - const_reference back() const - { - return *(p_start + p_size - 1); - } - - virtual constexpr - pointer data() - { - return p_start; - } - - [[nodiscard]] virtual constexpr - const_pointer data() const - { - return p_start; - } - - // Friend functions - - friend - bool operator==(const Sequence& lhs, const Sequence& rhs) - { - for (auto n = 0; n < lhs.size(); ++n) - if (lhs[n] != rhs[n]) - return false; - return true; - } - - friend - Sequence operator+(const Sequence& lhs, const Sequence& rhs) - { - Sequence seq {rhs.size() + lhs.size(), {}}; - for (auto n = 0; n < rhs.size(); ++n) - { - seq[n] = rhs[n]; - seq[n + rhs.size()] = lhs[n]; - } - return seq; - } - }; - +#pragma once + +#include +#include +#include + + +namespace hpr +{ + // forward declaration + + template + class Sequence; + + // type traits + + template + struct is_sequence : public std::false_type + {}; + + template + struct is_sequence> : public std::true_type + {}; + + // concepts + + template + concept IsSequence = is_sequence::value; + + // class definition + + template + class Sequence + { + + public: + + using difference_type = std::ptrdiff_t; + using value_type = T; + using size_type = Size; + using pointer = T*; + using reference = T&; + using iterator = Iterator; + using const_pointer = T const*; + using const_reference = T const&; + using const_iterator = Iterator; + + protected: + + size_type p_size; + size_type p_capacity; + pointer p_start; + + protected: + + constexpr + Sequence(size_type size, size_type capacity, pointer start) : + p_size {size}, + p_capacity {capacity}, + p_start {start} + {} + + constexpr explicit + Sequence(size_type size, size_type capacity) : + p_size {size}, + p_capacity {capacity}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + {} + + public: + + friend constexpr + void swap(Sequence& main, Sequence& other) noexcept + { + using std::swap; + swap(main.p_size, other.p_size); + swap(main.p_capacity, other.p_capacity); + swap(main.p_start, other.p_start); + } + + constexpr + Sequence() noexcept : + p_size {0}, + p_capacity {1}, + p_start {new value_type[p_capacity]} + {} + + constexpr + Sequence(const Sequence& seq) noexcept : + p_size {seq.p_size}, + p_capacity {seq.p_capacity}, + p_start {p_capacity ? new value_type[seq.p_capacity] : nullptr} + { + std::copy(seq.p_start, seq.p_start + seq.p_size, p_start); + } + + //! Move constructor + constexpr + Sequence(Sequence&& seq) noexcept : + Sequence {} + { + swap(*this, seq); + } + + template + constexpr + Sequence(Iter start, Iter end) : + p_size {static_cast(std::distance(start, end))}, + p_capacity {p_size}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + { + std::copy(start, end, p_start); + } + + constexpr + Sequence(iterator start, iterator end) : + p_size {static_cast(std::distance(start, end))}, + p_capacity {p_size}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + { + std::copy(start, end, p_start); + } + + constexpr + Sequence(const_iterator start, const_iterator end) : + p_size {static_cast(std::distance(start, end))}, + p_capacity {p_size}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + { + std::copy(start, end, p_start); + } + + constexpr + Sequence(iterator start, iterator end, size_type capacity) : + p_size {static_cast(std::distance(start, end))}, + p_capacity {capacity}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + { + std::copy(start, end, p_start); + } + + constexpr + Sequence(const_iterator start, const_iterator end, size_type capacity) : + p_size {static_cast(std::distance(start, end))}, + p_capacity {capacity}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + { + std::copy(start, end, p_start); + } + + /*constexpr + Sequence(std::initializer_list list) : + Sequence {list.begin(), list.end()} + {}*/ + + constexpr + Sequence(size_type size, value_type value) noexcept: + p_size {size}, + p_capacity {size}, + p_start {p_capacity ? new value_type[p_capacity] : nullptr} + { + for (auto n = 0; n < size; ++n) + *(p_start + n) = value; + } + + constexpr + Sequence& operator=(Sequence other) noexcept + { + swap(*this, other); + return *this; + } + + constexpr + Sequence& operator=(Sequence&& seq) noexcept + { + swap(*this, seq); + return *this; + } + + virtual + ~Sequence() + { + delete[] p_start; + } + + + // Member functions + + virtual constexpr + iterator begin() + { + return iterator(p_start); + } + + [[nodiscard]] virtual constexpr + const_iterator begin() const + { + return const_iterator(p_start); + } + + virtual constexpr + iterator end() + { + return iterator(p_start + p_size); + } + + virtual constexpr + const_iterator end() const + { + return const_iterator(p_start + p_size); + } + + virtual constexpr + iterator storage_end() + { + return iterator(p_start + p_capacity); + } + + virtual constexpr + const_iterator storage_end() const + { + return const_iterator(p_start + p_capacity); + } + + [[nodiscard]] virtual constexpr + size_type size() const noexcept + { + return p_size; + } + + virtual constexpr + reference operator[](size_type n) + { + if (n >= size()) + throw hpr::OutOfRange(); + return *(p_start + n); + } + + virtual constexpr + const_reference operator[](size_type n) const + { + if (n >= size()) + throw hpr::OutOfRange(); + return *(p_start + n); + } + + virtual constexpr + reference at(size_type n) + { + return operator[](n); + } + + virtual constexpr + const_reference at(size_type n) const + { + return operator[](n); + } + + virtual constexpr + reference front() + { + return *begin(); + } + + virtual constexpr + const_reference front() const + { + return *begin(); + } + + virtual constexpr + reference back() + { + return *(p_start + p_size - 1); + } + + virtual constexpr + const_reference back() const + { + return *(p_start + p_size - 1); + } + + virtual constexpr + pointer data() + { + return p_start; + } + + [[nodiscard]] virtual constexpr + const_pointer data() const + { + return p_start; + } + + // Friend functions + + friend + bool operator==(const Sequence& lhs, const Sequence& rhs) + { + for (auto n = 0; n < lhs.size(); ++n) + if (lhs[n] != rhs[n]) + return false; + return true; + } + + friend + Sequence operator+(const Sequence& lhs, const Sequence& rhs) + { + Sequence seq {rhs.size() + lhs.size(), {}}; + for (auto n = 0; n < rhs.size(); ++n) + { + seq[n] = rhs[n]; + seq[n + rhs.size()] = lhs[n]; + } + return seq; + } + }; + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/container/static_array.hpp b/source/hpr/container/static_array.hpp index cd58a02..074cba0 100644 --- a/source/hpr/container/static_array.hpp +++ b/source/hpr/container/static_array.hpp @@ -1,146 +1,146 @@ -#pragma once - -#include - - -namespace hpr -{ - // forward declaration - - template - requires (S > 0) - class StaticArray; - - // type traits - - template - struct is_sequence> : public std::true_type - {}; - - // aliases - - template - using sarray = StaticArray; - - // class definition - - template - requires (S > 0) - class StaticArray : public Sequence - { - - using base = Sequence; - - public: - - using difference_type = std::ptrdiff_t; - using value_type = T; - using size_type = Size; - using pointer = T*; - using reference = T&; - using iterator = Iterator; - using const_pointer = T const*; - using const_reference = T const&; - using const_iterator = Iterator; - - public: - - friend constexpr - void swap(StaticArray& main, StaticArray& other) noexcept - { - using std::swap; - swap(static_cast(main), static_cast(other)); - } - - //! Default constructor - constexpr - StaticArray() noexcept : - base {S, S, new value_type[S] {}} - {} - - constexpr explicit - StaticArray(const base& b) noexcept : - base {b} - {} - - //! Copy constructor - constexpr - StaticArray(const StaticArray& arr) noexcept : - base {static_cast(arr)} - {} - - //! Move constructor - constexpr - StaticArray(StaticArray&& arr) noexcept : - base {std::forward(static_cast(arr))} - {} - - constexpr - StaticArray(typename base::iterator start, typename base::iterator end) : - base {start, end} - {} - - constexpr - StaticArray(typename base::const_iterator start, typename base::const_iterator end) : - base {start, end} - {} - - constexpr - StaticArray(typename base::iterator start, typename base::iterator end, size_type capacity) : - base {start, end, capacity} - {} - - constexpr - StaticArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) : - base {start, end, capacity} - {} - - constexpr - StaticArray(std::initializer_list list) : - base {list.begin(), list.end()} - {} - - template ... Args> - constexpr explicit - StaticArray(const value_type& v, const Args& ...args) - requires (1 + sizeof...(args) == S) : - StaticArray {std::initializer_list({v, static_cast(args)...})} - {} - - template ... Args> - constexpr explicit - StaticArray(value_type&& v, Args&& ...args) - requires (1 + sizeof...(args) == S) : - StaticArray {std::initializer_list({std::forward(v), std::forward(static_cast(args))...})} - {} - - template ... Args> - constexpr - StaticArray(const StaticArray& subArr, const value_type& v, const Args& ...args) noexcept - requires (SS + 1 + sizeof...(args) == S) : - base {S, S, new value_type[S] {}} - { - std::copy(subArr.begin(), subArr.end(), base::begin()); - std::initializer_list list {v, static_cast(args)...}; - std::copy(list.begin(), list.end(), base::begin() + subArr.size()); - } - - constexpr - StaticArray& operator=(StaticArray other) - { - swap(*this, other); - return *this; - } - - constexpr - StaticArray& operator=(StaticArray&& other) noexcept - { - swap(*this, other); - return *this; - } - - virtual - ~StaticArray() = default; - }; - -} // end namespace hpr +#pragma once + +#include + + +namespace hpr +{ + // forward declaration + + template + requires (S > 0) + class StaticArray; + + // type traits + + template + struct is_sequence> : public std::true_type + {}; + + // aliases + + template + using sarray = StaticArray; + + // class definition + + template + requires (S > 0) + class StaticArray : public Sequence + { + + using base = Sequence; + + public: + + using difference_type = std::ptrdiff_t; + using value_type = T; + using size_type = Size; + using pointer = T*; + using reference = T&; + using iterator = Iterator; + using const_pointer = T const*; + using const_reference = T const&; + using const_iterator = Iterator; + + public: + + friend constexpr + void swap(StaticArray& main, StaticArray& other) noexcept + { + using std::swap; + swap(static_cast(main), static_cast(other)); + } + + //! Default constructor + constexpr + StaticArray() noexcept : + base {S, S, new value_type[S] {}} + {} + + constexpr explicit + StaticArray(const base& b) noexcept : + base {b} + {} + + //! Copy constructor + constexpr + StaticArray(const StaticArray& arr) noexcept : + base {static_cast(arr)} + {} + + //! Move constructor + constexpr + StaticArray(StaticArray&& arr) noexcept : + base {std::forward(static_cast(arr))} + {} + + constexpr + StaticArray(typename base::iterator start, typename base::iterator end) : + base {start, end} + {} + + constexpr + StaticArray(typename base::const_iterator start, typename base::const_iterator end) : + base {start, end} + {} + + constexpr + StaticArray(typename base::iterator start, typename base::iterator end, size_type capacity) : + base {start, end, capacity} + {} + + constexpr + StaticArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) : + base {start, end, capacity} + {} + + constexpr + StaticArray(std::initializer_list list) : + base {list.begin(), list.end()} + {} + + template ... Args> + constexpr explicit + StaticArray(const value_type& v, const Args& ...args) + requires (1 + sizeof...(args) == S) : + StaticArray {std::initializer_list({v, static_cast(args)...})} + {} + + template ... Args> + constexpr explicit + StaticArray(value_type&& v, Args&& ...args) + requires (1 + sizeof...(args) == S) : + StaticArray {std::initializer_list({std::forward(v), std::forward(static_cast(args))...})} + {} + + template ... Args> + constexpr + StaticArray(const StaticArray& subArr, const value_type& v, const Args& ...args) noexcept + requires (SS + 1 + sizeof...(args) == S) : + base {S, S, new value_type[S] {}} + { + std::copy(subArr.begin(), subArr.end(), base::begin()); + std::initializer_list list {v, static_cast(args)...}; + std::copy(list.begin(), list.end(), base::begin() + subArr.size()); + } + + constexpr + StaticArray& operator=(StaticArray other) + { + swap(*this, other); + return *this; + } + + constexpr + StaticArray& operator=(StaticArray&& other) noexcept + { + swap(*this, other); + return *this; + } + + virtual + ~StaticArray() = default; + }; + +} // end namespace hpr diff --git a/source/hpr/container/tree_node.hpp b/source/hpr/container/tree_node.hpp index af3d1b0..deeaa90 100644 --- a/source/hpr/container/tree_node.hpp +++ b/source/hpr/container/tree_node.hpp @@ -1,181 +1,181 @@ -#pragma once - -#include - -#include - - -namespace hpr -{ - - template - class TreeNode - { - - public: - - using value_type = Type; - using pointer = Type*; - using reference = Type&; - using const_pointer = Type const*; - using const_reference = Type const&; - - protected: - - pointer p_data; - - darray p_descendants; - TreeNode* p_ancestor; - - public: - - friend constexpr - void swap(TreeNode& main, TreeNode& other) noexcept - { - using std::swap; - swap(main.p_data, other.p_data); - swap(main.p_descendants, other.p_descendants); - swap(main.p_ancestor, other.p_ancestor); - } - - inline - TreeNode() : - p_data {new value_type {}}, - p_descendants {}, - p_ancestor {} - {} - - inline - TreeNode(const TreeNode& node) : - p_data {new value_type {*node.p_data}}, - p_descendants {}, - p_ancestor {} - {} - - inline - TreeNode(TreeNode&& node) noexcept : - p_data {}, - p_descendants {}, - p_ancestor {} - { - swap(*this, node); - /*std::swap(p_data, node.p_data); - std::swap(p_descendants, node.p_descendants); - std::swap(p_ancestor, node.p_ancestor);*/ - } - - inline - TreeNode& operator=(TreeNode other) - { - swap(*this, other); - return *this; - } - - inline explicit - TreeNode(const value_type& data) : - p_data {new value_type {data}}, - p_descendants {}, - p_ancestor {} - {} - - inline - TreeNode(const value_type& data, const darray& descendants, TreeNode* ancestor) : - p_data {new value_type {data}}, - p_descendants {descendants}, - p_ancestor {ancestor} - { - for (auto descendant : p_descendants) - descendant->ancestor(this); - } - - inline - TreeNode(const value_type& data, const darray& descendants) : - p_data {new value_type {data}}, - p_descendants {descendants}, - p_ancestor {} - { - for (auto descendant : p_descendants) - descendant->ancestor(this); - } - - virtual - ~TreeNode() - { - delete p_data; - //delete p_ancestor; - } - - // Member functions - - inline - pointer data() - { - return p_data; - } - - inline - void ancestor(TreeNode* node) - { - p_ancestor = node; - } - - inline - TreeNode* ancestor() - { - return p_ancestor; - } - - inline - void descendants(const darray& descendants) - { - p_descendants = descendants; - } - - inline - darray& descendants() - { - return p_descendants; - } - - darray traverse_descendants() - { - std::function(TreeNode*)> collect = [&](TreeNode* node) - { - darray ds; - - if (!node->descendants().is_empty()) - { - for (TreeNode* dnode: node->descendants()) - { - ds.push(dnode); - if (!dnode->descendants().is_empty()) - ds.push(collect(dnode)); - } - } - - return ds; - }; - - return collect(this); - } - - darray traverse_ancestors() - { - std::function(TreeNode*)> collect = [&](TreeNode* node) - { - darray ds; - - if (node->p_ancestor) - { - ds.push(node); - ds.push(collect(node->p_ancestor)); - } - - return ds; - }; - - return collect(this); - } - }; - +#pragma once + +#include + +#include + + +namespace hpr +{ + + template + class TreeNode + { + + public: + + using value_type = Type; + using pointer = Type*; + using reference = Type&; + using const_pointer = Type const*; + using const_reference = Type const&; + + protected: + + pointer p_data; + + darray p_descendants; + TreeNode* p_ancestor; + + public: + + friend constexpr + void swap(TreeNode& main, TreeNode& other) noexcept + { + using std::swap; + swap(main.p_data, other.p_data); + swap(main.p_descendants, other.p_descendants); + swap(main.p_ancestor, other.p_ancestor); + } + + inline + TreeNode() : + p_data {new value_type {}}, + p_descendants {}, + p_ancestor {} + {} + + inline + TreeNode(const TreeNode& node) : + p_data {new value_type {*node.p_data}}, + p_descendants {}, + p_ancestor {} + {} + + inline + TreeNode(TreeNode&& node) noexcept : + p_data {}, + p_descendants {}, + p_ancestor {} + { + swap(*this, node); + /*std::swap(p_data, node.p_data); + std::swap(p_descendants, node.p_descendants); + std::swap(p_ancestor, node.p_ancestor);*/ + } + + inline + TreeNode& operator=(TreeNode other) + { + swap(*this, other); + return *this; + } + + inline explicit + TreeNode(const value_type& data) : + p_data {new value_type {data}}, + p_descendants {}, + p_ancestor {} + {} + + inline + TreeNode(const value_type& data, const darray& descendants, TreeNode* ancestor) : + p_data {new value_type {data}}, + p_descendants {descendants}, + p_ancestor {ancestor} + { + for (auto descendant : p_descendants) + descendant->ancestor(this); + } + + inline + TreeNode(const value_type& data, const darray& descendants) : + p_data {new value_type {data}}, + p_descendants {descendants}, + p_ancestor {} + { + for (auto descendant : p_descendants) + descendant->ancestor(this); + } + + virtual + ~TreeNode() + { + delete p_data; + //delete p_ancestor; + } + + // Member functions + + inline + pointer data() + { + return p_data; + } + + inline + void ancestor(TreeNode* node) + { + p_ancestor = node; + } + + inline + TreeNode* ancestor() + { + return p_ancestor; + } + + inline + void descendants(const darray& descendants) + { + p_descendants = descendants; + } + + inline + darray& descendants() + { + return p_descendants; + } + + darray traverse_descendants() + { + std::function(TreeNode*)> collect = [&](TreeNode* node) + { + darray ds; + + if (!node->descendants().is_empty()) + { + for (TreeNode* dnode: node->descendants()) + { + ds.push(dnode); + if (!dnode->descendants().is_empty()) + ds.push(collect(dnode)); + } + } + + return ds; + }; + + return collect(this); + } + + darray traverse_ancestors() + { + std::function(TreeNode*)> collect = [&](TreeNode* node) + { + darray ds; + + if (node->p_ancestor) + { + ds.push(node); + ds.push(collect(node->p_ancestor)); + } + + return ds; + }; + + return collect(this); + } + }; + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/exception.hpp b/source/hpr/exception.hpp index 41ad7e7..749ba6b 100644 --- a/source/hpr/exception.hpp +++ b/source/hpr/exception.hpp @@ -1,63 +1,63 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - - -namespace hpr -{ - class Exception : public std::exception - { - - protected: - - std::string p_message; - - public: - - inline explicit - Exception(std::source_location location = std::source_location::current()) : - p_message {} - { - std::stringstream _message; - _message << "\t" << p_message - << "\n where:\t\t" << location.file_name() << ":" << location.line() << ":" << location.column() - << "\n function:\t" << location.function_name(); - p_message = _message.str(); - } - - inline explicit - Exception(const std::string& message, std::source_location location = std::source_location::current()) : - p_message {message} - { - std::stringstream _message; - _message << "\t" << p_message - << "\n where:\t" << location.file_name() << ":" << location.line() << ":" << location.column() - << "\n function:\t" << location.function_name(); - p_message = _message.str(); - } - - [[nodiscard]] - const char* what() const noexcept override { - std::vector vv; - return p_message.data(); - } - }; - - struct OutOfRange : public Exception - { - inline explicit OutOfRange(std::source_location location = std::source_location::current()) : Exception {"Out of range", location} {} - inline explicit OutOfRange(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {} - }; - - struct LengthError : public Exception - { - inline explicit LengthError(std::source_location location = std::source_location::current()) : Exception {"Length error", location} {} - inline explicit LengthError(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {} - }; - +#pragma once + +#include +#include +#include +#include +#include +#include + + +namespace hpr +{ + class Exception : public std::exception + { + + protected: + + std::string p_message; + + public: + + inline explicit + Exception(std::source_location location = std::source_location::current()) : + p_message {} + { + std::stringstream _message; + _message << "\t" << p_message + << "\n where:\t\t" << location.file_name() << ":" << location.line() << ":" << location.column() + << "\n function:\t" << location.function_name(); + p_message = _message.str(); + } + + inline explicit + Exception(const std::string& message, std::source_location location = std::source_location::current()) : + p_message {message} + { + std::stringstream _message; + _message << "\t" << p_message + << "\n where:\t" << location.file_name() << ":" << location.line() << ":" << location.column() + << "\n function:\t" << location.function_name(); + p_message = _message.str(); + } + + [[nodiscard]] + const char* what() const noexcept override { + std::vector vv; + return p_message.data(); + } + }; + + struct OutOfRange : public Exception + { + inline explicit OutOfRange(std::source_location location = std::source_location::current()) : Exception {"Out of range", location} {} + inline explicit OutOfRange(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {} + }; + + struct LengthError : public Exception + { + inline explicit LengthError(std::source_location location = std::source_location::current()) : Exception {"Length error", location} {} + inline explicit LengthError(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {} + }; + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/hpr.cpp b/source/hpr/hpr.cpp index 1e1dd56..ef9a577 100644 --- a/source/hpr/hpr.cpp +++ b/source/hpr/hpr.cpp @@ -1,5 +1,6 @@ - -#include -#include -#include -#include + +#include +#include +#include +#include +#include diff --git a/source/hpr/math.hpp b/source/hpr/math.hpp index 13f8985..f802d95 100644 --- a/source/hpr/math.hpp +++ b/source/hpr/math.hpp @@ -1,5 +1,5 @@ -#pragma once - -#include -#include -#include +#pragma once + +#include +#include +#include diff --git a/source/hpr/math/matrix.hpp b/source/hpr/math/matrix.hpp index 5ccd103..5533944 100644 --- a/source/hpr/math/matrix.hpp +++ b/source/hpr/math/matrix.hpp @@ -1,509 +1,509 @@ -#pragma once - -#include -#include -#include - - -namespace hpr -{ - // forward declarations - - template requires (Rows >= 0 && Cols >= 0) - class Matrix; - - template - using SubMatrix = typename std::conditional<(Rows >= 2 && Cols >= 2), Matrix, Matrix>::type; - - // type traits - - template - struct is_matrix : public std::false_type {}; - - template - struct is_matrix> : public std::true_type {}; - - // concepts - - template - concept IsMatrix = is_matrix::value; - - // aliases - - template - using mat = Matrix; - - using mat2 = Matrix; - using mat3 = Matrix; - using mat4 = Matrix; - - - template requires (Rows >= 0 && Cols >= 0) - class Matrix : public StaticArray - { - - using base = StaticArray; - - public: - - using value_type = Type; - using size_type = Size; - using pointer = Type*; - using reference = Type&; - using iterator = Iterator; - using const_reference = Type const&; - using const_iterator = Iterator; - - protected: - - size_type p_rows; - size_type p_cols; - - public: - - friend constexpr - void swap(Matrix& main, Matrix& other) - { - using std::swap; - swap(static_cast(main), static_cast(other)); - swap(main.p_rows, other.p_rows); - swap(main.p_cols, other.p_cols); - } - - inline - Matrix() : - base {}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix(const Matrix& ms) : - base {static_cast(ms)}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix(Matrix&& ms) noexcept: - base {std::forward(static_cast(ms))}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix& operator=(const Matrix& ms) - { - //base::operator=(ms); - swap(*this, ms); - return *this; - } - - inline explicit - Matrix(const base& vs) : - base {vs}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline explicit - Matrix(base&& vs) noexcept: - base {std::forward(vs)}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix(typename base::iterator start, typename base::iterator end) : - base {start, end}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix(typename base::const_iterator start, typename base::const_iterator end) : - base {start, end}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix(std::initializer_list list) : - base {list}, - p_rows {Rows}, - p_cols {Cols} - {} - - template - inline - Matrix(value_type&& v, Args&& ...args) requires (1 + sizeof...(args) == Rows * Cols): - base {v, static_cast(std::forward(args))...}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - Matrix(const value_type& v) : - base {}, - p_rows {Rows}, - p_cols {Cols} - { - for (Size n = 0; n < Rows * Cols; ++n) - (*this)[n] = v; - } - - inline - Matrix& operator=(const value_type& v) - { - for (Size n = 0; n < Rows * Cols; ++n) - (*this)[n] = v; - return *this; - } - - inline explicit - Matrix(const Quaternion& q) requires (Rows == 3 && Cols == 3 || Rows == 4 && Cols == 4) : - base {}, - p_rows {Rows}, - p_cols {Cols} - { - const scalar s = pow(norm(q), -2); - - (*this)(0, 0) = 1 - 2 * s * (q[2] * q[2] + q[3] * q[3]); - (*this)(1, 0) = 2 * s * (q[1] * q[2] - q[3] * q[0]); - (*this)(2, 0) = 2 * s * (q[1] * q[3] - q[2] * q[0]); - - (*this)(0, 1) = 2 * s * (q[1] * q[2] + q[3] * q[0]); - (*this)(1, 1) = 1 - 2 * s * (q[1] * q[1] + q[3] * q[3]); - (*this)(2, 1) = 2 * s * (q[2] * q[3] + q[1] * q[0]); - - (*this)(0, 2) = 2 * s * (q[1] * q[3] + q[2] * q[0]); - (*this)(1, 2) = 2 * s * (q[2] * q[3] + q[1] * q[0]); - (*this)(2, 2) = 1 - 2 * s * (q[1] * q[1] + q[2] * q[2]); - - if constexpr (Rows == 4) - (*this)(3, 3) = 1; - } - - - // access - - inline - reference operator()(size_type row, size_type col) - { - if (row >= p_rows || std::numeric_limits::max() - p_rows < row) - throw std::out_of_range("Row index is out of range"); - if (col >= p_cols || std::numeric_limits::max() - p_cols < col) - throw std::out_of_range("Column index is out of range"); - return (*this)[col + p_rows * row]; - } - - inline - const_reference operator()(size_type row, size_type col) const - { - if (row >= p_rows || std::numeric_limits::max() - p_rows < row) - throw std::out_of_range("Row index is out of range"); - if (col >= p_cols || std::numeric_limits::max() - p_cols < col) - throw std::out_of_range("Column index is out of range"); - return (*this)[col + p_rows * row]; - } - - Vector row(size_type row) const - { - Vector vs; - for (auto n = 0; n < Cols; ++n) - vs[n] = (*this)(row, n); - return vs; - } - - void row(size_type row, const Vector& vs) - { - for (auto n = 0; n < Cols; ++n) - (*this)(row, n) = vs[n]; - } - - Vector col(size_type col) const - { - Vector vs; - for (auto n = 0; n < Rows; ++n) - vs[n] = (*this)(n, col); - return vs; - } - - void col(size_type col, const Vector& vs) - { - for (auto n = 0; n < Rows; ++n) - (*this)(n, col) = vs[n]; - } - - [[nodiscard]] constexpr size_type rows() const { return p_rows; } - [[nodiscard]] constexpr size_type cols() const { return p_cols; } - - // member functions - - [[nodiscard]] - constexpr - bool is_square() const - { - return p_rows == p_cols; - } - - inline - Matrix& fill(value_type value) - { - for (auto n = 0; n < this->size(); ++n) - (*this)[n] = value; - return *this; - } - - // Global functions - - static inline - Matrix identity() - { - Matrix ms; - for (auto n = 0; n < Rows; ++n) - //for (auto k = 0; k < Cols; ++k) - ms(n, n) = 1; - return ms; - } - }; - - // global operators - - template inline Matrix operator+(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = lhs[n]; return ms; } - template inline Matrix operator-(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = -lhs[n]; return ms; } - - template inline Matrix& operator+=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs[n]; return lhs; } - template inline Matrix& operator-=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs[n]; return lhs; } - template inline Matrix& operator*=(Matrix& lhs, const Matrix& rhs) { Matrix temp {lhs}; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) lhs(n, k) = sum(temp.col(k) * rhs.row(n)); return lhs; } - - template inline Matrix operator+(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs[n]; return ms; } - template inline Matrix operator-(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs[n]; return ms; } - template inline Matrix operator*(const Matrix& lhs, const Matrix& rhs) { Matrix ms; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) ms(n, k) = sum(lhs.col(k) * rhs.row(n)); return ms; } - - template inline bool operator==(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] != rhs[n]) return false; return true; } - template inline bool operator!=(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] == rhs[n]) return false; return true; } - - - template inline Matrix& operator+=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs; return lhs; } - template inline Matrix& operator-=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs; return lhs; } - template inline Matrix& operator*=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] *= rhs; return lhs; } - template inline Matrix& operator/=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] /= rhs; return lhs; } - - template inline Matrix operator+(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs; return ms; } - template inline Matrix operator-(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs; return ms; } - template inline Matrix operator*(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] *= rhs; return ms; } - template inline Matrix operator/(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] /= rhs; return ms; } - - - template inline Vector operator*(const Matrix& ms, const Vector& vs) { Vector res; for (Size n = 0; n < R; ++n) res[n] = sum(ms.row(n) * vs); return res; } - template inline Vector operator*(const Vector& vs, const Matrix& ms) { Vector res; for (Size n = 0; n < C; ++n) res[n] = sum(ms.col(n) * vs); return res; } - - template inline bool operator==(const Matrix& lhs, const Vector& rhs) { return false; } - template inline bool operator!=(const Matrix& lhs, const Vector& rhs) { return true; } - - // matrix operations - - //! Transpose matrix - template - inline - Matrix transpose(const Matrix& ms) - { - Matrix res; - for (Size n = 0; n < R; ++n) - for (Size k = 0; k < C; ++k) - res(k, n) = ms(n, k); - return res; - } - - //! Trace of a matrix - template - inline - T trace(const Matrix& ms) requires (R == C) - { - T res; - for (auto n = 0; n < R; ++n) - res += ms(n, n); - return res; - } - - //! Minor of a matrix - template - inline - SubMatrix minor(const Matrix& ms, Size row, Size col) - { - if (ms.size() < 4) - throw std::runtime_error("Matrix should be greater 2x2"); - - SubMatrix minor; - auto minor_iter = minor.begin(); - for (auto n = 0; n < R; ++n) - for (auto k = 0; k < C; ++k) - if (k != col && n != row) - *(minor_iter++) = ms[k + ms.rows() * n]; - return minor; - } - - //! Determinant of a matrix - template - inline - scalar det(const Matrix& ms) requires (R == C) - { - if (ms.size() == 1) - return ms[0]; - - else if (ms.size() == 4) - return ms(0, 0) * ms(1, 1) - ms(0, 1) * ms(1, 0); - - else { - scalar res = 0; - for (auto n = 0; n < ms.cols(); ++n) - res += pow(-1, n) * ms(0, n) * det(minor(ms, 0, n)); - return res; - } - } - - //! Adjoint matrix - template - inline - Matrix adj(const Matrix& ms) - { - Matrix res; - for (auto n = 0; n < R; ++n) - for (auto k = 0; k < C; ++k) - res(n, k) = pow(-1, n + k) * det(minor(ms, n, k)); - return transpose(res); - } - - //! Inverse matrix - template - inline - Matrix inv(const Matrix& ms) - { - return adj(ms) / det(ms); - } - - // Transforms - - template - inline - Matrix translate(const Matrix& ms, const Vector& vs) - { - Matrix res {ms}; - res.col(3, ms.row(0) * vs[0] + ms.row(1) * vs[1] + ms.row(2) * vs[2] + ms.row(3)); - - return res; - } - - template - inline - Matrix rotate(const Matrix& ms, const Vector& vs, T angle) - { - const T cosv = cos(angle); - const T sinv = sin(angle); - Vector axis {normalize(vs)}; - Vector temp {(static_cast(1) - cosv) * axis}; - - Matrix rot; - rot(0, 0) = cosv + temp[0] * axis[0]; - rot(0, 1) = temp[0] * axis[1] + sinv * axis[2]; - rot(0, 2) = temp[0] * axis[2] - sinv * axis[1]; - rot(1, 0) = temp[1] * axis[0] - sinv * axis[2]; - rot(1, 1) = cosv + temp[1] * axis[1]; - rot(1, 2) = temp[1] * axis[2] + sinv * axis[0]; - rot(2, 0) = temp[2] * axis[0] + sinv * axis[1]; - rot(2, 1) = temp[2] * axis[1] - sinv * axis[0]; - rot(2, 2) = cosv + temp[2] * axis[2]; - - Matrix res {ms}; - res.row(0, ms.row(0) * rot(0, 0) + ms.row(1) * rot(0, 1) + ms.row(2) * rot(0, 2)); - res.row(1, ms.row(0) * rot(1, 0) + ms.row(1) * rot(1, 1) + ms.row(2) * rot(1, 2)); - res.row(2, ms.row(0) * rot(2, 0) + ms.row(1) * rot(2, 1) + ms.row(2) * rot(2, 2)); - res.row(3, ms.row(3)); - - return res; - } - - template - inline - Matrix rotate(const Matrix& ms, const Quaternion& q) - { - return ms * Matrix(q); - } - - template - inline - Matrix scale(const Matrix& ms, const Vector& vs) - { - Matrix res; - res.row(0, ms.row(0) * vs[0]); - res.row(1, ms.row(1) * vs[1]); - res.row(2, ms.row(2) * vs[2]); - res.row(3, ms.row(3)); - - return res; - } - - template - inline - Matrix lookAt(const Vector& eye, const Vector& center, const Vector& up) - { - const Vector forward {normalize(center - eye)}; - const Vector right {normalize(cross(forward, up))}; - const Vector nup {cross(right, forward)}; - const Vector translation {dot(right, eye), dot(nup, eye), -dot(forward, eye)}; - - Matrix res = Matrix::identity(); - res.row(0, Vector(right, 0)); - res.row(1, Vector(nup, 0)); - res.row(2, Vector(-forward, 0)); - res.col(3, Vector(-translation, static_cast(1))); - - return res; - } - - // Clip space - - template - inline - Matrix ortho(T left, T right, T bottom, T top) - { - Matrix ms = Matrix::identity(); - ms(0, 0) = static_cast(2) / (right - left); - ms(1, 1) = static_cast(2) / (top - bottom); - ms(2, 2) = -static_cast(1); - ms(3, 0) = -(right + left) / (right - left); - ms(3, 1) = -(top + bottom) / (top - bottom); - return ms; - } - - template - inline - Matrix ortho(T left, T right, T bottom, T top, T zNear, T zFar) - { - Matrix ms = Matrix::identity(); - ms(0, 0) = static_cast(2) / (right - left); - ms(1, 1) = static_cast(2) / (top - bottom); - ms(2, 2) = -static_cast(2) / (zFar - zNear); - ms(0, 3) = -(right + left) / (right - left); - ms(1, 3) = -(top + bottom) / (top - bottom); - ms(2, 3) = -(zFar + zNear) / (zFar - zNear); - return ms; - } - - template - inline - Matrix perspective(T fovy, T aspect, T zNear, T zFar) - { - assert(abs(aspect - std::numeric_limits::epsilon()) > 0); - Matrix ms; - const T halfFovyTan = tan(fovy / 2); - ms(0, 0) = static_cast(1) / (aspect * halfFovyTan); - ms(1, 1) = static_cast(1) / halfFovyTan; - ms(2, 2) = -(zFar + zNear) / (zFar - zNear); - ms(3, 2) = -static_cast(1); - ms(2, 3) = -(static_cast(2) * zFar * zNear) / (zFar - zNear); - return ms; - } - +#pragma once + +#include +#include +#include + + +namespace hpr +{ + // forward declarations + + template requires (Rows >= 0 && Cols >= 0) + class Matrix; + + template + using SubMatrix = typename std::conditional<(Rows >= 2 && Cols >= 2), Matrix, Matrix>::type; + + // type traits + + template + struct is_matrix : public std::false_type {}; + + template + struct is_matrix> : public std::true_type {}; + + // concepts + + template + concept IsMatrix = is_matrix::value; + + // aliases + + template + using mat = Matrix; + + using mat2 = Matrix; + using mat3 = Matrix; + using mat4 = Matrix; + + + template requires (Rows >= 0 && Cols >= 0) + class Matrix : public StaticArray + { + + using base = StaticArray; + + public: + + using value_type = Type; + using size_type = Size; + using pointer = Type*; + using reference = Type&; + using iterator = Iterator; + using const_reference = Type const&; + using const_iterator = Iterator; + + protected: + + size_type p_rows; + size_type p_cols; + + public: + + friend constexpr + void swap(Matrix& main, Matrix& other) + { + using std::swap; + swap(static_cast(main), static_cast(other)); + swap(main.p_rows, other.p_rows); + swap(main.p_cols, other.p_cols); + } + + inline + Matrix() : + base {}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix(const Matrix& ms) : + base {static_cast(ms)}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix(Matrix&& ms) noexcept: + base {std::forward(static_cast(ms))}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix& operator=(const Matrix& ms) + { + //base::operator=(ms); + swap(*this, ms); + return *this; + } + + inline explicit + Matrix(const base& vs) : + base {vs}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline explicit + Matrix(base&& vs) noexcept: + base {std::forward(vs)}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix(typename base::iterator start, typename base::iterator end) : + base {start, end}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix(typename base::const_iterator start, typename base::const_iterator end) : + base {start, end}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix(std::initializer_list list) : + base {list}, + p_rows {Rows}, + p_cols {Cols} + {} + + template + inline + Matrix(value_type&& v, Args&& ...args) requires (1 + sizeof...(args) == Rows * Cols): + base {v, static_cast(std::forward(args))...}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + Matrix(const value_type& v) : + base {}, + p_rows {Rows}, + p_cols {Cols} + { + for (Size n = 0; n < Rows * Cols; ++n) + (*this)[n] = v; + } + + inline + Matrix& operator=(const value_type& v) + { + for (Size n = 0; n < Rows * Cols; ++n) + (*this)[n] = v; + return *this; + } + + inline explicit + Matrix(const Quaternion& q) requires (Rows == 3 && Cols == 3 || Rows == 4 && Cols == 4) : + base {}, + p_rows {Rows}, + p_cols {Cols} + { + const scalar s = pow(norm(q), -2); + + (*this)(0, 0) = 1 - 2 * s * (q[2] * q[2] + q[3] * q[3]); + (*this)(1, 0) = 2 * s * (q[1] * q[2] - q[3] * q[0]); + (*this)(2, 0) = 2 * s * (q[1] * q[3] - q[2] * q[0]); + + (*this)(0, 1) = 2 * s * (q[1] * q[2] + q[3] * q[0]); + (*this)(1, 1) = 1 - 2 * s * (q[1] * q[1] + q[3] * q[3]); + (*this)(2, 1) = 2 * s * (q[2] * q[3] + q[1] * q[0]); + + (*this)(0, 2) = 2 * s * (q[1] * q[3] + q[2] * q[0]); + (*this)(1, 2) = 2 * s * (q[2] * q[3] + q[1] * q[0]); + (*this)(2, 2) = 1 - 2 * s * (q[1] * q[1] + q[2] * q[2]); + + if constexpr (Rows == 4) + (*this)(3, 3) = 1; + } + + + // access + + inline + reference operator()(size_type row, size_type col) + { + if (row >= p_rows || std::numeric_limits::max() - p_rows < row) + throw std::out_of_range("Row index is out of range"); + if (col >= p_cols || std::numeric_limits::max() - p_cols < col) + throw std::out_of_range("Column index is out of range"); + return (*this)[col + p_rows * row]; + } + + inline + const_reference operator()(size_type row, size_type col) const + { + if (row >= p_rows || std::numeric_limits::max() - p_rows < row) + throw std::out_of_range("Row index is out of range"); + if (col >= p_cols || std::numeric_limits::max() - p_cols < col) + throw std::out_of_range("Column index is out of range"); + return (*this)[col + p_rows * row]; + } + + Vector row(size_type row) const + { + Vector vs; + for (auto n = 0; n < Cols; ++n) + vs[n] = (*this)(row, n); + return vs; + } + + void row(size_type row, const Vector& vs) + { + for (auto n = 0; n < Cols; ++n) + (*this)(row, n) = vs[n]; + } + + Vector col(size_type col) const + { + Vector vs; + for (auto n = 0; n < Rows; ++n) + vs[n] = (*this)(n, col); + return vs; + } + + void col(size_type col, const Vector& vs) + { + for (auto n = 0; n < Rows; ++n) + (*this)(n, col) = vs[n]; + } + + [[nodiscard]] constexpr size_type rows() const { return p_rows; } + [[nodiscard]] constexpr size_type cols() const { return p_cols; } + + // member functions + + [[nodiscard]] + constexpr + bool is_square() const + { + return p_rows == p_cols; + } + + inline + Matrix& fill(value_type value) + { + for (auto n = 0; n < this->size(); ++n) + (*this)[n] = value; + return *this; + } + + // Global functions + + static inline + Matrix identity() + { + Matrix ms; + for (auto n = 0; n < Rows; ++n) + //for (auto k = 0; k < Cols; ++k) + ms(n, n) = 1; + return ms; + } + }; + + // global operators + + template inline Matrix operator+(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = lhs[n]; return ms; } + template inline Matrix operator-(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = -lhs[n]; return ms; } + + template inline Matrix& operator+=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs[n]; return lhs; } + template inline Matrix& operator-=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs[n]; return lhs; } + template inline Matrix& operator*=(Matrix& lhs, const Matrix& rhs) { Matrix temp {lhs}; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) lhs(n, k) = sum(temp.col(k) * rhs.row(n)); return lhs; } + + template inline Matrix operator+(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs[n]; return ms; } + template inline Matrix operator-(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs[n]; return ms; } + template inline Matrix operator*(const Matrix& lhs, const Matrix& rhs) { Matrix ms; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) ms(n, k) = sum(lhs.col(k) * rhs.row(n)); return ms; } + + template inline bool operator==(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] != rhs[n]) return false; return true; } + template inline bool operator!=(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] == rhs[n]) return false; return true; } + + + template inline Matrix& operator+=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs; return lhs; } + template inline Matrix& operator-=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs; return lhs; } + template inline Matrix& operator*=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] *= rhs; return lhs; } + template inline Matrix& operator/=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] /= rhs; return lhs; } + + template inline Matrix operator+(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs; return ms; } + template inline Matrix operator-(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs; return ms; } + template inline Matrix operator*(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] *= rhs; return ms; } + template inline Matrix operator/(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] /= rhs; return ms; } + + + template inline Vector operator*(const Matrix& ms, const Vector& vs) { Vector res; for (Size n = 0; n < R; ++n) res[n] = sum(ms.row(n) * vs); return res; } + template inline Vector operator*(const Vector& vs, const Matrix& ms) { Vector res; for (Size n = 0; n < C; ++n) res[n] = sum(ms.col(n) * vs); return res; } + + template inline bool operator==(const Matrix& lhs, const Vector& rhs) { return false; } + template inline bool operator!=(const Matrix& lhs, const Vector& rhs) { return true; } + + // matrix operations + + //! Transpose matrix + template + inline + Matrix transpose(const Matrix& ms) + { + Matrix res; + for (Size n = 0; n < R; ++n) + for (Size k = 0; k < C; ++k) + res(k, n) = ms(n, k); + return res; + } + + //! Trace of a matrix + template + inline + T trace(const Matrix& ms) requires (R == C) + { + T res; + for (auto n = 0; n < R; ++n) + res += ms(n, n); + return res; + } + + //! Minor of a matrix + template + inline + SubMatrix minor(const Matrix& ms, Size row, Size col) + { + if (ms.size() < 4) + throw std::runtime_error("Matrix should be greater 2x2"); + + SubMatrix minor; + auto minor_iter = minor.begin(); + for (auto n = 0; n < R; ++n) + for (auto k = 0; k < C; ++k) + if (k != col && n != row) + *(minor_iter++) = ms[k + ms.rows() * n]; + return minor; + } + + //! Determinant of a matrix + template + inline + scalar det(const Matrix& ms) requires (R == C) + { + if (ms.size() == 1) + return ms[0]; + + else if (ms.size() == 4) + return ms(0, 0) * ms(1, 1) - ms(0, 1) * ms(1, 0); + + else { + scalar res = 0; + for (auto n = 0; n < ms.cols(); ++n) + res += pow(-1, n) * ms(0, n) * det(minor(ms, 0, n)); + return res; + } + } + + //! Adjoint matrix + template + inline + Matrix adj(const Matrix& ms) + { + Matrix res; + for (auto n = 0; n < R; ++n) + for (auto k = 0; k < C; ++k) + res(n, k) = pow(-1, n + k) * det(minor(ms, n, k)); + return transpose(res); + } + + //! Inverse matrix + template + inline + Matrix inv(const Matrix& ms) + { + return adj(ms) / det(ms); + } + + // Transforms + + template + inline + Matrix translate(const Matrix& ms, const Vector& vs) + { + Matrix res {ms}; + res.col(3, ms.row(0) * vs[0] + ms.row(1) * vs[1] + ms.row(2) * vs[2] + ms.row(3)); + + return res; + } + + template + inline + Matrix rotate(const Matrix& ms, const Vector& vs, T angle) + { + const T cosv = cos(angle); + const T sinv = sin(angle); + Vector axis {normalize(vs)}; + Vector temp {(static_cast(1) - cosv) * axis}; + + Matrix rot; + rot(0, 0) = cosv + temp[0] * axis[0]; + rot(0, 1) = temp[0] * axis[1] + sinv * axis[2]; + rot(0, 2) = temp[0] * axis[2] - sinv * axis[1]; + rot(1, 0) = temp[1] * axis[0] - sinv * axis[2]; + rot(1, 1) = cosv + temp[1] * axis[1]; + rot(1, 2) = temp[1] * axis[2] + sinv * axis[0]; + rot(2, 0) = temp[2] * axis[0] + sinv * axis[1]; + rot(2, 1) = temp[2] * axis[1] - sinv * axis[0]; + rot(2, 2) = cosv + temp[2] * axis[2]; + + Matrix res {ms}; + res.row(0, ms.row(0) * rot(0, 0) + ms.row(1) * rot(0, 1) + ms.row(2) * rot(0, 2)); + res.row(1, ms.row(0) * rot(1, 0) + ms.row(1) * rot(1, 1) + ms.row(2) * rot(1, 2)); + res.row(2, ms.row(0) * rot(2, 0) + ms.row(1) * rot(2, 1) + ms.row(2) * rot(2, 2)); + res.row(3, ms.row(3)); + + return res; + } + + template + inline + Matrix rotate(const Matrix& ms, const Quaternion& q) + { + return ms * Matrix(q); + } + + template + inline + Matrix scale(const Matrix& ms, const Vector& vs) + { + Matrix res; + res.row(0, ms.row(0) * vs[0]); + res.row(1, ms.row(1) * vs[1]); + res.row(2, ms.row(2) * vs[2]); + res.row(3, ms.row(3)); + + return res; + } + + template + inline + Matrix lookAt(const Vector& eye, const Vector& center, const Vector& up) + { + const Vector forward {normalize(center - eye)}; + const Vector right {normalize(cross(forward, up))}; + const Vector nup {cross(right, forward)}; + const Vector translation {dot(right, eye), dot(nup, eye), -dot(forward, eye)}; + + Matrix res = Matrix::identity(); + res.row(0, Vector(right, 0)); + res.row(1, Vector(nup, 0)); + res.row(2, Vector(-forward, 0)); + res.col(3, Vector(-translation, static_cast(1))); + + return res; + } + + // Clip space + + template + inline + Matrix ortho(T left, T right, T bottom, T top) + { + Matrix ms = Matrix::identity(); + ms(0, 0) = static_cast(2) / (right - left); + ms(1, 1) = static_cast(2) / (top - bottom); + ms(2, 2) = -static_cast(1); + ms(3, 0) = -(right + left) / (right - left); + ms(3, 1) = -(top + bottom) / (top - bottom); + return ms; + } + + template + inline + Matrix ortho(T left, T right, T bottom, T top, T zNear, T zFar) + { + Matrix ms = Matrix::identity(); + ms(0, 0) = static_cast(2) / (right - left); + ms(1, 1) = static_cast(2) / (top - bottom); + ms(2, 2) = -static_cast(2) / (zFar - zNear); + ms(0, 3) = -(right + left) / (right - left); + ms(1, 3) = -(top + bottom) / (top - bottom); + ms(2, 3) = -(zFar + zNear) / (zFar - zNear); + return ms; + } + + template + inline + Matrix perspective(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > 0); + Matrix ms; + const T halfFovyTan = tan(fovy / 2); + ms(0, 0) = static_cast(1) / (aspect * halfFovyTan); + ms(1, 1) = static_cast(1) / halfFovyTan; + ms(2, 2) = -(zFar + zNear) / (zFar - zNear); + ms(3, 2) = -static_cast(1); + ms(2, 3) = -(static_cast(2) * zFar * zNear) / (zFar - zNear); + return ms; + } + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/math/quaternion.hpp b/source/hpr/math/quaternion.hpp index e987bc2..99f95e5 100644 --- a/source/hpr/math/quaternion.hpp +++ b/source/hpr/math/quaternion.hpp @@ -1,290 +1,290 @@ -#pragma once - -#include -#include - - -namespace hpr -{ - // forward declarations - - class Quaternion; - - inline - Quaternion inverse(const Quaternion& q); - - inline - Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs); - - // aliases - - using quat = Quaternion; - - // class declaration - class Quaternion - { - - public: - - enum RotationSequence - { - ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX - }; - - protected: - - scalar p_real; - vec3 p_imag; - - public: - - inline - Quaternion() : - p_real{}, - p_imag{} - {} - - inline - Quaternion(const scalar real, const vec3& imag) : - p_real {real}, - p_imag {imag} - {} - - inline explicit - Quaternion(const scalar real) : - p_real {real}, - p_imag {} - {} - - inline explicit - Quaternion(const vec3& imag) : - p_real {}, - p_imag {imag} - {} - - inline - Quaternion(const vec3& vs, const scalar& theta) : - p_real {cos(0.5 * theta)}, - p_imag {sin(0.5 * theta) * vs / mag(vs)} - {} - - static inline - Quaternion unit(const vec3& vs) - { - return Quaternion(sqrt(1 - norm(vs)), vs); - } - - inline - Quaternion(const RotationSequence rs, const vec3& angles) - { - switch (rs) - { - case XYZ: - *this = Quaternion(vec3(0, 1, 0), angles[0]) * - Quaternion(vec3(0, 1, 0), angles[1]) * - Quaternion(vec3(0, 0, 1), angles[2]); - break; - - default: - throw std::runtime_error("Unknown rotation sequence"); - } - } - - inline - scalar real() const - { - return p_real; - } - - inline - scalar& real() - { - return p_real; - } - - inline - vec3 imag() const - { - return p_imag; - } - - inline - vec3& imag() - { - return p_imag; - } - - inline - scalar& operator[](Size n) - { - if (n > 3) - throw hpr::OutOfRange(); - if (n == 0) - return p_real; - else - return p_imag[n - 1]; - } - - inline - scalar operator[](Size n) const - { - if (n > 3) - throw hpr::OutOfRange(); - if (n == 0) - return p_real; - else - return p_imag[n - 1]; - } - - inline - void operator+=(const Quaternion& q) - { - p_real += q.p_real; - p_imag += q.p_imag; - } - - inline - void operator-=(const Quaternion& q) - { - p_real -= q.p_real; - p_imag -= q.p_imag; - } - - inline - void operator*=(const Quaternion& q) - { - scalar temp = p_real; - p_real = p_real * q.p_real - dot(p_imag, q.p_imag); - p_imag = temp * q.p_imag + q.p_real * p_imag + cross(p_imag, q.p_imag); - } - - inline - void operator/=(const Quaternion& q) - { - operator*=(inverse(q)); - } - - inline - void operator*=(const scalar s) - { - p_real *= s; - p_imag *= s; - } - - inline - void operator/=(const scalar s) - { - p_real /= s; - p_imag /= s; - } - }; - - inline - bool equal(const Quaternion& lhs, const Quaternion& rhs) - { - return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); - } - - inline - bool operator==(const Quaternion& lhs, const Quaternion& rhs) - { - return equal(lhs, rhs); - } - - inline - bool operator!=(const Quaternion& lhs, const Quaternion& rhs) - { - return !equal(lhs, rhs); - } - - inline - Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs) - { - return {lhs.real() + rhs.real(), lhs.imag() + rhs.imag()}; - } - - inline - Quaternion operator-(const Quaternion& q) - { - return {q.real(), q.imag()}; - } - - inline - Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs) - { - return {lhs.real() - rhs.real(), lhs.imag() - rhs.imag()}; - } - - inline - Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs) - { - return { - lhs.real() * rhs.real() - dot(lhs.imag(), rhs.imag()), - lhs.real() * rhs.imag() + rhs.real() * lhs.imag() + cross(lhs.imag(), rhs.imag()) - }; - } - - inline - Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs) - { - return lhs * inverse(rhs); - } - - inline - Quaternion operator*(const scalar s, const Quaternion& q) - { - return {s * q.real(), s * q.imag()}; - } - - inline - Quaternion operator*(const Quaternion& q, const scalar s) - { - return {q.real() * s, q.imag() * s}; - } - - inline - Quaternion operator/(const Quaternion& q, const scalar s) - { - return {q.real() / s, q.imag() / s}; - } - - inline - scalar norm(const Quaternion& q) - { - return sqrt(pow(q.real(), 2) + dot(q.imag(), q.imag())); - } - - inline - Quaternion conjugate(const Quaternion& q) - { - return {q.real(), -q.imag()}; - } - - inline - Quaternion inverse(const Quaternion& q) - { - return conjugate(q) / pow(norm(q), 2); - } - - inline - Quaternion normalize(const Quaternion& q) - { - return q / norm(q); - } - - inline - vec3 rotate(const vec3& point, const vec3& axis, const scalar& angle) - { - Quaternion p {point}; - Quaternion q {normalize(axis), angle}; - return (q * p * inverse(q)).imag(); - } - - void decompose(const Quaternion& q, vec3& axis, scalar& angle) - { - const scalar qnorm = norm(q.imag()); - axis = q.imag() / qnorm; - angle = 2 * atan2(qnorm, q.real()); - } - +#pragma once + +#include +#include + + +namespace hpr +{ + // forward declarations + + class Quaternion; + + inline + Quaternion inverse(const Quaternion& q); + + inline + Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs); + + // aliases + + using quat = Quaternion; + + // class declaration + class Quaternion + { + + public: + + enum RotationSequence + { + ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX + }; + + protected: + + scalar p_real; + vec3 p_imag; + + public: + + inline + Quaternion() : + p_real{}, + p_imag{} + {} + + inline + Quaternion(const scalar real, const vec3& imag) : + p_real {real}, + p_imag {imag} + {} + + inline explicit + Quaternion(const scalar real) : + p_real {real}, + p_imag {} + {} + + inline explicit + Quaternion(const vec3& imag) : + p_real {}, + p_imag {imag} + {} + + inline + Quaternion(const vec3& vs, const scalar& theta) : + p_real {cos(0.5 * theta)}, + p_imag {sin(0.5 * theta) * vs / mag(vs)} + {} + + static inline + Quaternion unit(const vec3& vs) + { + return Quaternion(sqrt(1 - norm(vs)), vs); + } + + inline + Quaternion(const RotationSequence rs, const vec3& angles) + { + switch (rs) + { + case XYZ: + *this = Quaternion(vec3(0, 1, 0), angles[0]) * + Quaternion(vec3(0, 1, 0), angles[1]) * + Quaternion(vec3(0, 0, 1), angles[2]); + break; + + default: + throw std::runtime_error("Unknown rotation sequence"); + } + } + + inline + scalar real() const + { + return p_real; + } + + inline + scalar& real() + { + return p_real; + } + + inline + vec3 imag() const + { + return p_imag; + } + + inline + vec3& imag() + { + return p_imag; + } + + inline + scalar& operator[](Size n) + { + if (n > 3) + throw hpr::OutOfRange(); + if (n == 0) + return p_real; + else + return p_imag[n - 1]; + } + + inline + scalar operator[](Size n) const + { + if (n > 3) + throw hpr::OutOfRange(); + if (n == 0) + return p_real; + else + return p_imag[n - 1]; + } + + inline + void operator+=(const Quaternion& q) + { + p_real += q.p_real; + p_imag += q.p_imag; + } + + inline + void operator-=(const Quaternion& q) + { + p_real -= q.p_real; + p_imag -= q.p_imag; + } + + inline + void operator*=(const Quaternion& q) + { + scalar temp = p_real; + p_real = p_real * q.p_real - dot(p_imag, q.p_imag); + p_imag = temp * q.p_imag + q.p_real * p_imag + cross(p_imag, q.p_imag); + } + + inline + void operator/=(const Quaternion& q) + { + operator*=(inverse(q)); + } + + inline + void operator*=(const scalar s) + { + p_real *= s; + p_imag *= s; + } + + inline + void operator/=(const scalar s) + { + p_real /= s; + p_imag /= s; + } + }; + + inline + bool equal(const Quaternion& lhs, const Quaternion& rhs) + { + return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); + } + + inline + bool operator==(const Quaternion& lhs, const Quaternion& rhs) + { + return equal(lhs, rhs); + } + + inline + bool operator!=(const Quaternion& lhs, const Quaternion& rhs) + { + return !equal(lhs, rhs); + } + + inline + Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs) + { + return {lhs.real() + rhs.real(), lhs.imag() + rhs.imag()}; + } + + inline + Quaternion operator-(const Quaternion& q) + { + return {q.real(), q.imag()}; + } + + inline + Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs) + { + return {lhs.real() - rhs.real(), lhs.imag() - rhs.imag()}; + } + + inline + Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs) + { + return { + lhs.real() * rhs.real() - dot(lhs.imag(), rhs.imag()), + lhs.real() * rhs.imag() + rhs.real() * lhs.imag() + cross(lhs.imag(), rhs.imag()) + }; + } + + inline + Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs) + { + return lhs * inverse(rhs); + } + + inline + Quaternion operator*(const scalar s, const Quaternion& q) + { + return {s * q.real(), s * q.imag()}; + } + + inline + Quaternion operator*(const Quaternion& q, const scalar s) + { + return {q.real() * s, q.imag() * s}; + } + + inline + Quaternion operator/(const Quaternion& q, const scalar s) + { + return {q.real() / s, q.imag() / s}; + } + + inline + scalar norm(const Quaternion& q) + { + return sqrt(pow(q.real(), 2) + dot(q.imag(), q.imag())); + } + + inline + Quaternion conjugate(const Quaternion& q) + { + return {q.real(), -q.imag()}; + } + + inline + Quaternion inverse(const Quaternion& q) + { + return conjugate(q) / pow(norm(q), 2); + } + + inline + Quaternion normalize(const Quaternion& q) + { + return q / norm(q); + } + + inline + vec3 rotate(const vec3& point, const vec3& axis, const scalar& angle) + { + Quaternion p {point}; + Quaternion q {normalize(axis), angle}; + return (q * p * inverse(q)).imag(); + } + + void decompose(const Quaternion& q, vec3& axis, scalar& angle) + { + const scalar qnorm = norm(q.imag()); + axis = q.imag() / qnorm; + angle = 2 * atan2(qnorm, q.real()); + } + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/math/vector.hpp b/source/hpr/math/vector.hpp index c2cf8d1..37aefdb 100644 --- a/source/hpr/math/vector.hpp +++ b/source/hpr/math/vector.hpp @@ -1,321 +1,321 @@ -#pragma once - -#include -#include - - -namespace hpr -{ - // forward declarations - - template requires (S >= 0) - class Vector; - - template - using SubVector = typename std::conditional= 2, Vector, Vector>::type; - - // type traits - - template - struct is_vector : public std::false_type {}; - - template - struct is_vector> : public std::true_type {}; - - // concepts - - template - concept IsVector = is_vector::value; - - // aliases - - template - using vec = Vector; - - using vec2 = Vector; - using vec3 = Vector; - using vec4 = Vector; - - - template requires (S >= 0) - class Vector : public StaticArray - { - - using base = StaticArray; - - public: - - using value_type = Type; - using size_type = Size; - using pointer = Type*; - using reference = Type&; - using iterator = Iterator; - using const_iterator = Iterator; - - public: - - //! null constructor - constexpr - Vector() : - base {} - {} - - //! copy constructor - constexpr - Vector(const Vector& vs) : - base {static_cast(vs)} - {} - - //! move constructor - constexpr - Vector(Vector&& vs) noexcept : - base {std::forward(static_cast(vs))} - {} - - //! copy assignment operator - constexpr - Vector& operator=(const Vector& vs) - { - base::operator=(vs); - return *this; - } - - //! move assignment operator - constexpr - Vector& operator=(Vector&& vs) noexcept - { - swap(*this, vs); - return *this; - } - - //! destructor - virtual - ~Vector() = default; - - //! copy constructor from base - constexpr - Vector(const base& arr) : - base {arr} - {} - - //! move constructor from base - constexpr - Vector(base&& arr) : - base {std::forward(arr)} - {} - - //! construct from iterators - constexpr - Vector(typename base::iterator start, typename base::iterator end) : - base {start, end} - {} - - //! construct from constant iterators - constexpr - Vector(typename base::const_iterator start, typename base::const_iterator end) : - base {start, end} - {} - - //! construct from initializer list - constexpr - Vector(std::initializer_list list) : - base {list} - {} - - //! copy constructor with variadic args - template - constexpr - Vector(const value_type& v, const Args& ...args) requires (S == 1 + sizeof...(args)): - base {v, static_cast(args)...} - {} - - //! move constructor with variadic args - template - constexpr - Vector(value_type&& v, Args&& ...args) requires (S == 1 + sizeof...(args)): - base {v, static_cast(std::forward(args))...} - {} - - //! copy constructor with sub vector and value - constexpr - Vector(const SubVector& svs, const value_type& v) requires (S >= 1): - base {} - { - for (auto n = 0; n < svs.size(); ++n) - (*this)[n] = svs[n]; - (*this)[svs.size()] = v; - } - - //! copy constructor from greater vector - template requires (GS > S) - constexpr explicit - Vector(const Vector& vs) : - base {vs.begin(), vs.begin() + S} - {} - - }; - - // global operators - - template inline Vector operator+(const Vector& lhs) { Vector vs; for (Size n = 0; n < S; ++n) vs[n] = lhs[n]; return vs; } - template inline Vector operator-(const Vector& lhs) { Vector vs; for (Size n = 0; n < S; ++n) vs[n] = -lhs[n]; return vs; } - - template inline Vector& operator+=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs[n]; return lhs; } - template inline Vector& operator-=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs[n]; return lhs; } - template inline Vector& operator*=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs[n]; return lhs; } - template inline Vector& operator/=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs[n]; return lhs; } - - template inline Vector operator+(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs[n]; return vs; } - template inline Vector operator-(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs[n]; return vs; } - template inline Vector operator*(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs[n]; return vs; } - template inline Vector operator/(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs[n]; return vs; } - - template inline bool operator==(const Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] != rhs[n]) return false; return true; } - template inline bool operator!=(const Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] == rhs[n]) return false; return true; } - - - template inline Vector& operator+=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs; return lhs; } - template inline Vector& operator-=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs; return lhs; } - template inline Vector& operator*=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs; return lhs; } - template inline Vector& operator/=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs; return lhs; } - - template inline Vector operator+(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs; return vs; } - template inline Vector operator-(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs; return vs; } - template inline Vector operator*(const Vector& lhs, const T2& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= static_cast(rhs); return vs; } - template inline Vector operator/(const Vector& lhs, const T2& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= static_cast(rhs); return vs; } - - template inline Vector operator+(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] += lhs; return vs; } - template inline Vector operator-(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] -= lhs; return vs; } - template inline Vector operator*(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] *= lhs; return vs; } - template inline Vector operator/(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] /= lhs; return vs; } - - // boolean operations - - template - inline - Vector equal(const Vector& lhs, const Vector& rhs, const scalar& precision = hpr::precision()) - { - Vector vs; - for (auto n = 0; n < S; ++n) - vs[n] = equal(lhs[n], rhs[n], precision); - return vs; - } - - template - inline - bool any(const Vector& vs) - { - bool res = false; - for (auto e : vs) - res = res || e; - return res; - } - - template - inline - bool all(const Vector& vs) - { - bool res = true; - for (auto e : vs) - res = res && e; - return res; - } - - // per element operations - - template - inline - Vector abs(const Vector& vs) - { - Vector res; - for (auto n = 0; n < S; ++n) - res[n] = abs(vs[n]); - return res; - } - - template - inline - Type sum(const Vector& vs) - { - Type sum {}; - for (const Type& v : vs) - sum += v; - return sum; - } - - template - inline - Vector pow(const Vector& vs, scalar degree) - { - Vector res; - for (auto n = 0; n < S; ++n) - res[n] = pow(vs[n], degree); - return res; - } - - // vector operations - - template - inline - Type norm(const Vector& vs) - { - return sqrt(sum(pow(abs(vs), 2))); - } - - template - inline - Type dot(const Vector& lhs, const Vector& rhs) - { - return sum(lhs * rhs); - } - - template - inline - Type length(const Vector& vs) - { - return sqrt(dot(vs, vs)); - } - - template - inline - Type mag(const Vector& vs) - { - return length(vs); - } - - template - inline - Type distance(const Vector& vs1, const Vector& vs2) - { - return length(vs1 - vs2); - } - - template - inline - Vector normalize(const Vector& vs) - { - return vs * isqrt(dot(vs, vs)); - } - - template - inline - Type angle(const Vector& lhs, const Vector& rhs) - { - scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs)); - return acos(cos); //clip(cos, -1., 1.)); - } - - // vector 3 operations - - template - inline - Vector cross(const Vector& lhs, const Vector& rhs) - { - return Vector( - lhs[1] * rhs[2] - lhs[2] * rhs[1], - lhs[2] * rhs[0] - lhs[0] * rhs[2], - lhs[0] * rhs[1] - lhs[1] * rhs[0] - ); - } - +#pragma once + +#include +#include + + +namespace hpr +{ + // forward declarations + + template requires (S >= 0) + class Vector; + + template + using SubVector = typename std::conditional= 2, Vector, Vector>::type; + + // type traits + + template + struct is_vector : public std::false_type {}; + + template + struct is_vector> : public std::true_type {}; + + // concepts + + template + concept IsVector = is_vector::value; + + // aliases + + template + using vec = Vector; + + using vec2 = Vector; + using vec3 = Vector; + using vec4 = Vector; + + + template requires (S >= 0) + class Vector : public StaticArray + { + + using base = StaticArray; + + public: + + using value_type = Type; + using size_type = Size; + using pointer = Type*; + using reference = Type&; + using iterator = Iterator; + using const_iterator = Iterator; + + public: + + //! null constructor + constexpr + Vector() : + base {} + {} + + //! copy constructor + constexpr + Vector(const Vector& vs) : + base {static_cast(vs)} + {} + + //! move constructor + constexpr + Vector(Vector&& vs) noexcept : + base {std::forward(static_cast(vs))} + {} + + //! copy assignment operator + constexpr + Vector& operator=(const Vector& vs) + { + base::operator=(vs); + return *this; + } + + //! move assignment operator + constexpr + Vector& operator=(Vector&& vs) noexcept + { + swap(*this, vs); + return *this; + } + + //! destructor + virtual + ~Vector() = default; + + //! copy constructor from base + constexpr + Vector(const base& arr) : + base {arr} + {} + + //! move constructor from base + constexpr + Vector(base&& arr) : + base {std::forward(arr)} + {} + + //! construct from iterators + constexpr + Vector(typename base::iterator start, typename base::iterator end) : + base {start, end} + {} + + //! construct from constant iterators + constexpr + Vector(typename base::const_iterator start, typename base::const_iterator end) : + base {start, end} + {} + + //! construct from initializer list + constexpr + Vector(std::initializer_list list) : + base {list} + {} + + //! copy constructor with variadic args + template + constexpr + Vector(const value_type& v, const Args& ...args) requires (S == 1 + sizeof...(args)): + base {v, static_cast(args)...} + {} + + //! move constructor with variadic args + template + constexpr + Vector(value_type&& v, Args&& ...args) requires (S == 1 + sizeof...(args)): + base {v, static_cast(std::forward(args))...} + {} + + //! copy constructor with sub vector and value + constexpr + Vector(const SubVector& svs, const value_type& v) requires (S >= 1): + base {} + { + for (auto n = 0; n < svs.size(); ++n) + (*this)[n] = svs[n]; + (*this)[svs.size()] = v; + } + + //! copy constructor from greater vector + template requires (GS > S) + constexpr explicit + Vector(const Vector& vs) : + base {vs.begin(), vs.begin() + S} + {} + + }; + + // global operators + + template inline Vector operator+(const Vector& lhs) { Vector vs; for (Size n = 0; n < S; ++n) vs[n] = lhs[n]; return vs; } + template inline Vector operator-(const Vector& lhs) { Vector vs; for (Size n = 0; n < S; ++n) vs[n] = -lhs[n]; return vs; } + + template inline Vector& operator+=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs[n]; return lhs; } + template inline Vector& operator-=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs[n]; return lhs; } + template inline Vector& operator*=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs[n]; return lhs; } + template inline Vector& operator/=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs[n]; return lhs; } + + template inline Vector operator+(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs[n]; return vs; } + template inline Vector operator-(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs[n]; return vs; } + template inline Vector operator*(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs[n]; return vs; } + template inline Vector operator/(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs[n]; return vs; } + + template inline bool operator==(const Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] != rhs[n]) return false; return true; } + template inline bool operator!=(const Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] == rhs[n]) return false; return true; } + + + template inline Vector& operator+=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs; return lhs; } + template inline Vector& operator-=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs; return lhs; } + template inline Vector& operator*=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs; return lhs; } + template inline Vector& operator/=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs; return lhs; } + + template inline Vector operator+(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs; return vs; } + template inline Vector operator-(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs; return vs; } + template inline Vector operator*(const Vector& lhs, const T2& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= static_cast(rhs); return vs; } + template inline Vector operator/(const Vector& lhs, const T2& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= static_cast(rhs); return vs; } + + template inline Vector operator+(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] += lhs; return vs; } + template inline Vector operator-(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] -= lhs; return vs; } + template inline Vector operator*(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] *= lhs; return vs; } + template inline Vector operator/(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] /= lhs; return vs; } + + // boolean operations + + template + inline + Vector equal(const Vector& lhs, const Vector& rhs, const scalar& precision = hpr::precision()) + { + Vector vs; + for (auto n = 0; n < S; ++n) + vs[n] = equal(lhs[n], rhs[n], precision); + return vs; + } + + template + inline + bool any(const Vector& vs) + { + bool res = false; + for (auto e : vs) + res = res || e; + return res; + } + + template + inline + bool all(const Vector& vs) + { + bool res = true; + for (auto e : vs) + res = res && e; + return res; + } + + // per element operations + + template + inline + Vector abs(const Vector& vs) + { + Vector res; + for (auto n = 0; n < S; ++n) + res[n] = abs(vs[n]); + return res; + } + + template + inline + Type sum(const Vector& vs) + { + Type sum {}; + for (const Type& v : vs) + sum += v; + return sum; + } + + template + inline + Vector pow(const Vector& vs, scalar degree) + { + Vector res; + for (auto n = 0; n < S; ++n) + res[n] = pow(vs[n], degree); + return res; + } + + // vector operations + + template + inline + Type norm(const Vector& vs) + { + return sqrt(sum(pow(abs(vs), 2))); + } + + template + inline + Type dot(const Vector& lhs, const Vector& rhs) + { + return sum(lhs * rhs); + } + + template + inline + Type length(const Vector& vs) + { + return sqrt(dot(vs, vs)); + } + + template + inline + Type mag(const Vector& vs) + { + return length(vs); + } + + template + inline + Type distance(const Vector& vs1, const Vector& vs2) + { + return length(vs1 - vs2); + } + + template + inline + Vector normalize(const Vector& vs) + { + return vs * isqrt(dot(vs, vs)); + } + + template + inline + Type angle(const Vector& lhs, const Vector& rhs) + { + scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs)); + return acos(cos); //clip(cos, -1., 1.)); + } + + // vector 3 operations + + template + inline + Vector cross(const Vector& lhs, const Vector& rhs) + { + return Vector( + lhs[1] * rhs[2] - lhs[2] * rhs[1], + lhs[2] * rhs[0] - lhs[0] * rhs[2], + lhs[0] * rhs[1] - lhs[1] * rhs[0] + ); + } + } // end namespace hpr \ No newline at end of file diff --git a/source/hpr/numeric.hpp b/source/hpr/numeric.hpp index 84c0c21..539f556 100644 --- a/source/hpr/numeric.hpp +++ b/source/hpr/numeric.hpp @@ -1,305 +1,305 @@ -#pragma once - -#include -#include -#include -#include - -#ifdef __MSC_VER -#define HPR_CONSTEXPR -#else -#define HPR_CONSTEXPR constexpr -#endif - - -namespace hpr -{ - using Size = std::size_t; - - template - struct is_size : public std::integral_constant::value && std::is_unsigned::value> {}; - - template - concept IsSize = is_size::value || std::convertible_to; - - - template - struct is_integer : public std::is_integral {}; - - template - concept IsInteger = is_integer::value; - - - template - struct is_scalar : public std::is_floating_point {}; - - template - concept IsScalar = is_scalar::value; - - template - concept IsReal = is_integer::value || is_scalar::value; - - -#ifndef HPR_SCALAR -#define HPR_SCALAR float -#endif - -#ifdef HPR_SCALAR_IMPLEMENTATION - template - class Scalar - { - - public: - - using type = Scalar; - using value_type = T; - - protected: - - value_type p_value; - - public: - - // constructors - - constexpr Scalar() : p_value {} {} - - template constexpr Scalar(const Scalar& value) : p_value {static_cast(value.p_value)} {} - - template constexpr Scalar(const X& value) : p_value {static_cast(value)} {} - - template constexpr type& operator=(const Scalar& value) { p_value = static_cast(value.p_value); return *this; } - - template constexpr type& operator=(const X& value) { p_value = static_cast(value); return *this; } - - virtual constexpr ~Scalar() = default; - - // conversion - - constexpr operator double() const { return static_cast(p_value); } - - constexpr operator float() const { return static_cast(p_value); } - - constexpr operator long double() const { return static_cast(p_value); } - - constexpr operator bool() const { return static_cast(p_value); } - - // access - - [[nodiscard]] constexpr value_type value() const { return p_value; } - - constexpr value_type& value() { return p_value; } - }; - - - using scalar_type = HPR_SCALAR; - using scalar = Scalar; - - - // template<> scalar::value_type scalar::s_precision = static_cast(1e-15); - - /// scalar vs scalar - - constexpr scalar operator+(const scalar& s) { return s; } - constexpr scalar operator-(const scalar& s) { return -s.value(); } - constexpr bool operator!(const scalar& s) { return !static_cast(s.value()); } - - constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } - constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } - constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } - constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } - - constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); } - constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); } - constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); } - constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); } - - constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); } - constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); } - constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } - constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } - constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); } - constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); } - constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); } - constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); } - - // std::ostream& operator<<(std::ostream& stream, const scalar& s) { return stream << s.value(); } - - /// scalar vs Scalar - - template constexpr scalar& operator+=(scalar& lhs, const Scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } - template constexpr scalar& operator-=(scalar& lhs, const Scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } - template constexpr scalar& operator*=(scalar& lhs, const Scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } - template constexpr scalar& operator/=(scalar& lhs, const Scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } - - template constexpr scalar operator+(const scalar& lhs, const Scalar& rhs) { return lhs.value() + static_cast(rhs.value()); } - template constexpr scalar operator+(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) + rhs.value(); } - template constexpr scalar operator-(const scalar& lhs, const Scalar& rhs) { return lhs.value() - static_cast(rhs.value()); } - template constexpr scalar operator-(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) - rhs.value(); } - template constexpr scalar operator*(const scalar& lhs, const Scalar& rhs) { return lhs.value() * static_cast(rhs.value()); } - template constexpr scalar operator*(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) * rhs.value(); } - template constexpr scalar operator/(const scalar& lhs, const Scalar& rhs) { return lhs.value() / static_cast(rhs.value()); } - template constexpr scalar operator/(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) / rhs.value(); } - - template constexpr bool operator==(const scalar& lhs, const Scalar& rhs) { return lhs.value() == static_cast(rhs.value()); } - template constexpr bool operator==(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) == rhs.value(); } - template constexpr bool operator!=(const scalar& lhs, const Scalar& rhs) { return lhs.value() != static_cast(rhs.value()); } - template constexpr bool operator!=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) != rhs.value(); } - template constexpr bool operator&&(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } - template constexpr bool operator&&(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } - template constexpr bool operator||(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } - template constexpr bool operator||(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } - template constexpr bool operator>(const scalar& lhs, const Scalar& rhs) { return lhs.value() > static_cast(rhs.value()); } - template constexpr bool operator>(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) > rhs.value(); } - template constexpr bool operator<(const scalar& lhs, const Scalar& rhs) { return lhs.value() < static_cast(rhs.value()); } - template constexpr bool operator<(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) < rhs.value(); } - template constexpr bool operator>=(const scalar& lhs, const Scalar& rhs) { return lhs.value() >= static_cast(rhs.value()); } - template constexpr bool operator>=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) >= rhs.value(); } - template constexpr bool operator<=(const scalar& lhs, const Scalar& rhs) { return lhs.value() <= static_cast(rhs.value()); } - template constexpr bool operator<=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) <= rhs.value(); } - - template std::ostream& operator<<(std::ostream& stream, const Scalar& s) { return stream << s.value(); } - template std::istream& operator>>(std::istream& stream, Scalar& s) { return stream >> s.value(); } - - /// scalar vs real - - template constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast(rhs); return lhs; } - template constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast(rhs); return lhs; } - template constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast(rhs); return lhs; } - template constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast(rhs); return lhs; } - - template constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast(rhs); return lhs; } - template constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast(rhs); return lhs; } - template constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast(rhs); return lhs; } - template constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast(rhs); return lhs; } - - template constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast(rhs); } - template constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast(lhs) + rhs.value(); } - template constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast(rhs); } - template constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast(lhs) - rhs.value(); } - template constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast(rhs); } - template constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast(lhs) * rhs.value(); } - template constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast(rhs); } - template constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast(lhs) / rhs.value(); } - - template constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast(rhs); } - template constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast(lhs) == rhs.value(); } - template constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast(rhs); } - template constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast(lhs) != rhs.value(); } - template constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast(lhs) && static_cast(rhs); } - template constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } - template constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast(lhs) || static_cast(rhs); } - template constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } - template constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast(rhs); } - template constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast(lhs) > rhs.value(); } - template constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast(rhs); } - template constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast(lhs) < rhs.value(); } - template constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast(rhs); } - template constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast(lhs) >= rhs.value(); } - template constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast(rhs); } - template constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast(lhs) <= rhs.value(); } - -#else - - using scalar_type = HPR_SCALAR; - using scalar = HPR_SCALAR; - -#endif - - - // constants - - HPR_CONSTEXPR scalar pi() { return std::numbers::pi_v; } - - HPR_CONSTEXPR scalar e() { return std::numbers::e_v; } - - // transcendentals - - template HPR_CONSTEXPR scalar cos(const T& s) { return std::cos(static_cast(s));} - - template HPR_CONSTEXPR scalar acos(const T& s) { return std::acos(static_cast(s)); } - - template HPR_CONSTEXPR scalar cosh(const T& s) { return std::cosh(static_cast(s)); } - - template HPR_CONSTEXPR scalar acosh(const T& s) { return std::acosh(static_cast(s)); } - - template HPR_CONSTEXPR scalar sin(const T& s) { return std::sin(static_cast(s)); } - - template HPR_CONSTEXPR scalar asin(const T& s) { return std::asin(static_cast(s)); } - - template HPR_CONSTEXPR scalar sinh(const T& s) { return std::sinh(static_cast(s)); } - - template HPR_CONSTEXPR scalar asinh(const T& s) { return std::asinh(static_cast(s)); } - - template HPR_CONSTEXPR scalar tan(const T& s) { return std::tan(static_cast(s)); } - - template HPR_CONSTEXPR scalar atan(const T& s) { return std::atan(static_cast(s)); } - - template HPR_CONSTEXPR scalar atan2(const T& s, const X& s2) { return std::atan2(static_cast(s), static_cast(s2)); } - - template HPR_CONSTEXPR scalar tanh(const T& s) { return std::tanh(static_cast(s)); } - - template HPR_CONSTEXPR scalar atanh(const T& s) { return std::atanh(static_cast(s)); } - - template HPR_CONSTEXPR scalar exp(const T& s) { return std::exp(static_cast(s)); } - - template HPR_CONSTEXPR scalar log(const T& s) { return std::log(static_cast(s)); } - - template HPR_CONSTEXPR scalar log10(const T& s) { return std::log10(static_cast(s)); } - - template HPR_CONSTEXPR scalar pow(const T& s, const X& d) { return std::pow(static_cast(s), static_cast(d)); } - - template HPR_CONSTEXPR scalar sqrt(const T& s) { return std::sqrt(static_cast(s)); } - - template HPR_CONSTEXPR scalar isqrt(const T& s) { return static_cast(1) / sqrt(static_cast(s)); } - - // - - static scalar_type scalar_precision = static_cast(1e-15); - - inline scalar_type precision() - { - return scalar_precision; - } - - template inline void precision(const T& precision) - { - scalar_precision = static_cast(precision); - } - - - HPR_CONSTEXPR scalar inf() { return std::numeric_limits::infinity(); } - - HPR_CONSTEXPR scalar epsilon() { return std::numeric_limits::epsilon(); } - - HPR_CONSTEXPR scalar isnan(const scalar& s) { return std::isnan(static_cast(s)); } - - HPR_CONSTEXPR scalar abs(const scalar& s) { return std::abs(static_cast(s)); } - - HPR_CONSTEXPR scalar mag(const scalar& s) { return std::abs(static_cast(s)); } - - HPR_CONSTEXPR bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = hpr::precision()) { return abs(lhs - rhs) < precision; } - - //! Convert degrees to radians - HPR_CONSTEXPR scalar rad(const scalar& s) { return s * pi() / static_cast(180); } - - //! Convert radians to degrees - HPR_CONSTEXPR scalar deg(const scalar& s) { return s * static_cast(180) / pi(); } - - HPR_CONSTEXPR scalar min(const scalar& s1, const scalar& s2) { return std::min(static_cast(s1), static_cast(s2));} - - HPR_CONSTEXPR scalar max(const scalar& s1, const scalar& s2) { return std::max(static_cast(s1), static_cast(s2)); } - - HPR_CONSTEXPR scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); } - - -} // end namespace hpr - -#ifdef HPR_SCALAR_IMPLEMENTATION - -namespace std -{ - template struct is_floating_point : true_type {}; -} // end namespace std - +#pragma once + +#include +#include +#include +#include + +#ifdef __MSC_VER +#define HPR_CONSTEXPR +#else +#define HPR_CONSTEXPR constexpr +#endif + + +namespace hpr +{ + using Size = std::size_t; + + template + struct is_size : public std::integral_constant::value && std::is_unsigned::value> {}; + + template + concept IsSize = is_size::value || std::convertible_to; + + + template + struct is_integer : public std::is_integral {}; + + template + concept IsInteger = is_integer::value; + + + template + struct is_scalar : public std::is_floating_point {}; + + template + concept IsScalar = is_scalar::value; + + template + concept IsReal = is_integer::value || is_scalar::value; + + +#ifndef HPR_SCALAR +#define HPR_SCALAR float +#endif + +#ifdef HPR_SCALAR_IMPLEMENTATION + template + class Scalar + { + + public: + + using type = Scalar; + using value_type = T; + + protected: + + value_type p_value; + + public: + + // constructors + + constexpr Scalar() : p_value {} {} + + template constexpr Scalar(const Scalar& value) : p_value {static_cast(value.p_value)} {} + + template constexpr Scalar(const X& value) : p_value {static_cast(value)} {} + + template constexpr type& operator=(const Scalar& value) { p_value = static_cast(value.p_value); return *this; } + + template constexpr type& operator=(const X& value) { p_value = static_cast(value); return *this; } + + virtual constexpr ~Scalar() = default; + + // conversion + + constexpr operator double() const { return static_cast(p_value); } + + constexpr operator float() const { return static_cast(p_value); } + + constexpr operator long double() const { return static_cast(p_value); } + + constexpr operator bool() const { return static_cast(p_value); } + + // access + + [[nodiscard]] constexpr value_type value() const { return p_value; } + + constexpr value_type& value() { return p_value; } + }; + + + using scalar_type = HPR_SCALAR; + using scalar = Scalar; + + + // template<> scalar::value_type scalar::s_precision = static_cast(1e-15); + + /// scalar vs scalar + + constexpr scalar operator+(const scalar& s) { return s; } + constexpr scalar operator-(const scalar& s) { return -s.value(); } + constexpr bool operator!(const scalar& s) { return !static_cast(s.value()); } + + constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } + constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } + constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } + constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } + + constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); } + constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); } + constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); } + constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); } + + constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); } + constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); } + constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } + constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } + constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); } + constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); } + constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); } + constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); } + + // std::ostream& operator<<(std::ostream& stream, const scalar& s) { return stream << s.value(); } + + /// scalar vs Scalar + + template constexpr scalar& operator+=(scalar& lhs, const Scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } + template constexpr scalar& operator-=(scalar& lhs, const Scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } + template constexpr scalar& operator*=(scalar& lhs, const Scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } + template constexpr scalar& operator/=(scalar& lhs, const Scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } + + template constexpr scalar operator+(const scalar& lhs, const Scalar& rhs) { return lhs.value() + static_cast(rhs.value()); } + template constexpr scalar operator+(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) + rhs.value(); } + template constexpr scalar operator-(const scalar& lhs, const Scalar& rhs) { return lhs.value() - static_cast(rhs.value()); } + template constexpr scalar operator-(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) - rhs.value(); } + template constexpr scalar operator*(const scalar& lhs, const Scalar& rhs) { return lhs.value() * static_cast(rhs.value()); } + template constexpr scalar operator*(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) * rhs.value(); } + template constexpr scalar operator/(const scalar& lhs, const Scalar& rhs) { return lhs.value() / static_cast(rhs.value()); } + template constexpr scalar operator/(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) / rhs.value(); } + + template constexpr bool operator==(const scalar& lhs, const Scalar& rhs) { return lhs.value() == static_cast(rhs.value()); } + template constexpr bool operator==(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) == rhs.value(); } + template constexpr bool operator!=(const scalar& lhs, const Scalar& rhs) { return lhs.value() != static_cast(rhs.value()); } + template constexpr bool operator!=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) != rhs.value(); } + template constexpr bool operator&&(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } + template constexpr bool operator&&(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } + template constexpr bool operator||(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } + template constexpr bool operator||(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } + template constexpr bool operator>(const scalar& lhs, const Scalar& rhs) { return lhs.value() > static_cast(rhs.value()); } + template constexpr bool operator>(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) > rhs.value(); } + template constexpr bool operator<(const scalar& lhs, const Scalar& rhs) { return lhs.value() < static_cast(rhs.value()); } + template constexpr bool operator<(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) < rhs.value(); } + template constexpr bool operator>=(const scalar& lhs, const Scalar& rhs) { return lhs.value() >= static_cast(rhs.value()); } + template constexpr bool operator>=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) >= rhs.value(); } + template constexpr bool operator<=(const scalar& lhs, const Scalar& rhs) { return lhs.value() <= static_cast(rhs.value()); } + template constexpr bool operator<=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) <= rhs.value(); } + + template std::ostream& operator<<(std::ostream& stream, const Scalar& s) { return stream << s.value(); } + template std::istream& operator>>(std::istream& stream, Scalar& s) { return stream >> s.value(); } + + /// scalar vs real + + template constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast(rhs); return lhs; } + template constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast(rhs); return lhs; } + template constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast(rhs); return lhs; } + template constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast(rhs); return lhs; } + + template constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast(rhs); return lhs; } + template constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast(rhs); return lhs; } + template constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast(rhs); return lhs; } + template constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast(rhs); return lhs; } + + template constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast(rhs); } + template constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast(lhs) + rhs.value(); } + template constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast(rhs); } + template constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast(lhs) - rhs.value(); } + template constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast(rhs); } + template constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast(lhs) * rhs.value(); } + template constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast(rhs); } + template constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast(lhs) / rhs.value(); } + + template constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast(rhs); } + template constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast(lhs) == rhs.value(); } + template constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast(rhs); } + template constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast(lhs) != rhs.value(); } + template constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast(lhs) && static_cast(rhs); } + template constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } + template constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast(lhs) || static_cast(rhs); } + template constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } + template constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast(rhs); } + template constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast(lhs) > rhs.value(); } + template constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast(rhs); } + template constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast(lhs) < rhs.value(); } + template constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast(rhs); } + template constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast(lhs) >= rhs.value(); } + template constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast(rhs); } + template constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast(lhs) <= rhs.value(); } + +#else + + using scalar_type = HPR_SCALAR; + using scalar = HPR_SCALAR; + +#endif + + + // constants + + HPR_CONSTEXPR scalar pi() { return std::numbers::pi_v; } + + HPR_CONSTEXPR scalar e() { return std::numbers::e_v; } + + // transcendentals + + template HPR_CONSTEXPR scalar cos(const T& s) { return std::cos(static_cast(s));} + + template HPR_CONSTEXPR scalar acos(const T& s) { return std::acos(static_cast(s)); } + + template HPR_CONSTEXPR scalar cosh(const T& s) { return std::cosh(static_cast(s)); } + + template HPR_CONSTEXPR scalar acosh(const T& s) { return std::acosh(static_cast(s)); } + + template HPR_CONSTEXPR scalar sin(const T& s) { return std::sin(static_cast(s)); } + + template HPR_CONSTEXPR scalar asin(const T& s) { return std::asin(static_cast(s)); } + + template HPR_CONSTEXPR scalar sinh(const T& s) { return std::sinh(static_cast(s)); } + + template HPR_CONSTEXPR scalar asinh(const T& s) { return std::asinh(static_cast(s)); } + + template HPR_CONSTEXPR scalar tan(const T& s) { return std::tan(static_cast(s)); } + + template HPR_CONSTEXPR scalar atan(const T& s) { return std::atan(static_cast(s)); } + + template HPR_CONSTEXPR scalar atan2(const T& s, const X& s2) { return std::atan2(static_cast(s), static_cast(s2)); } + + template HPR_CONSTEXPR scalar tanh(const T& s) { return std::tanh(static_cast(s)); } + + template HPR_CONSTEXPR scalar atanh(const T& s) { return std::atanh(static_cast(s)); } + + template HPR_CONSTEXPR scalar exp(const T& s) { return std::exp(static_cast(s)); } + + template HPR_CONSTEXPR scalar log(const T& s) { return std::log(static_cast(s)); } + + template HPR_CONSTEXPR scalar log10(const T& s) { return std::log10(static_cast(s)); } + + template HPR_CONSTEXPR scalar pow(const T& s, const X& d) { return std::pow(static_cast(s), static_cast(d)); } + + template HPR_CONSTEXPR scalar sqrt(const T& s) { return std::sqrt(static_cast(s)); } + + template HPR_CONSTEXPR scalar isqrt(const T& s) { return static_cast(1) / sqrt(static_cast(s)); } + + // + + static scalar_type scalar_precision = static_cast(1e-15); + + inline scalar_type precision() + { + return scalar_precision; + } + + template inline void precision(const T& precision) + { + scalar_precision = static_cast(precision); + } + + + HPR_CONSTEXPR scalar inf() { return std::numeric_limits::infinity(); } + + HPR_CONSTEXPR scalar epsilon() { return std::numeric_limits::epsilon(); } + + HPR_CONSTEXPR scalar isnan(const scalar& s) { return std::isnan(static_cast(s)); } + + HPR_CONSTEXPR scalar abs(const scalar& s) { return std::abs(static_cast(s)); } + + HPR_CONSTEXPR scalar mag(const scalar& s) { return std::abs(static_cast(s)); } + + HPR_CONSTEXPR bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = hpr::precision()) { return abs(lhs - rhs) < precision; } + + //! Convert degrees to radians + HPR_CONSTEXPR scalar rad(const scalar& s) { return s * pi() / static_cast(180); } + + //! Convert radians to degrees + HPR_CONSTEXPR scalar deg(const scalar& s) { return s * static_cast(180) / pi(); } + + HPR_CONSTEXPR scalar min(const scalar& s1, const scalar& s2) { return std::min(static_cast(s1), static_cast(s2));} + + HPR_CONSTEXPR scalar max(const scalar& s1, const scalar& s2) { return std::max(static_cast(s1), static_cast(s2)); } + + HPR_CONSTEXPR scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); } + + +} // end namespace hpr + +#ifdef HPR_SCALAR_IMPLEMENTATION + +namespace std +{ + template struct is_floating_point : true_type {}; +} // end namespace std + #endif \ No newline at end of file diff --git a/source/hpr/shape.hpp b/source/hpr/shape.hpp new file mode 100644 index 0000000..7d4ab7c --- /dev/null +++ b/source/hpr/shape.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/source/hpr/shape/shape.hpp b/source/hpr/shape/shape.hpp new file mode 100644 index 0000000..9677e26 --- /dev/null +++ b/source/hpr/shape/shape.hpp @@ -0,0 +1,360 @@ +#pragma once + +#include +#include + + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + + + +namespace hpr::csg +{ + class Shape; +} + +namespace std +{ + template<> + struct less + { + bool operator() (const hpr::csg::Shape& s1, const hpr::csg::Shape& s2) const; + }; +} + +namespace hpr::csg +{ + +// Class declaration + + class Shape + { + + public: + + enum class Type + { + Compound, + Compsolid, + Solid, + Shell, + Face, + Wire, + Edge, + Vertex, + Shape, + Unknown + }; + + enum class Format + { + Unknown, + STEP + }; + + class Metadata + { + public: + std::string label; + public: + Metadata() : + label {"default"} + {} + void merge(const Metadata& data) + { + if (label == "default" && data.label != "default") + label = data.label; + } + }; + + public: + + // TODO: clean up map + static + std::map metadata; + + protected: + + TopoDS_Shape p_shape; + + public: + + [[nodiscard]] + TopoDS_Shape tshape() const { return p_shape; } + + Shape(const TopoDS_Shape& s) : + p_shape {s} + {} + + Shape(TopoDS_Shape&& s) noexcept: + p_shape {std::forward(s)} + {} + + public: + + Shape() : + p_shape {} + {} + + virtual + ~Shape() = default; + //{ + //if (metadata.contains(*this)) + // metadata.erase(*this); + //} + + [[nodiscard]] + Type type() const + { + switch (p_shape.ShapeType()) + { + case TopAbs_VERTEX: + return Type::Vertex; + case TopAbs_EDGE: + return Type::Edge; + case TopAbs_FACE: + return Type::Face; + case TopAbs_WIRE: + return Type::Wire; + case TopAbs_SHELL: + return Type::Shell; + case TopAbs_SOLID: + return Type::Solid; + case TopAbs_COMPOUND: + return Type::Compound; + case TopAbs_COMPSOLID: + return Type::Compsolid; + case TopAbs_SHAPE: + return Type::Shape; + default: + return Type::Unknown; + } + } + + [[nodiscard]] + vec3 center() const + { + GProp_GProps props; + + switch (type()) + { + case Type::Solid: + case Type::Compsolid: + case Type::Compound: + BRepGProp::VolumeProperties(p_shape, props); + case Type::Shell: + case Type::Face: + BRepGProp::SurfaceProperties(p_shape, props); + default: + BRepGProp::LinearProperties(p_shape, props); + } + + gp_Pnt center {props.CentreOfMass()}; + + return vec3 {static_cast(center.X()), static_cast(center.Y()), static_cast(center.Z())}; + } + + [[nodiscard]] + double length() const + { + GProp_GProps props; + + switch (type()) + { + case Type::Vertex: + return 0; + default: + BRepGProp::LinearProperties(p_shape, props); + return props.Mass(); + } + } + + [[nodiscard]] + double area() const + { + GProp_GProps props; + + switch (type()) + { + case Type::Vertex: + case Type::Edge: + case Type::Wire: + return 0; + default: + BRepGProp::SurfaceProperties(p_shape, props); + return props.Mass(); + } + } + + [[nodiscard]] + double volume() const + { + GProp_GProps props; + + switch (type()) + { + case Type::Compsolid: + case Type::Solid: + BRepGProp::VolumeProperties(p_shape, props); + return props.Mass(); + + default: + return 0; + } + } + + void label(const std::string& label) const + { + metadata[*this].label = label; + } + + [[nodiscard]] + std::string label() const + { + return metadata[*this].label; + } + + void dump(const std::string& filename, Format format) const + { + if (p_shape.IsNull()) + throw std::runtime_error("Trying to export null shape"); + + switch (format) + { + case Format::STEP: + { + STEPControl_Writer writer; + Interface_Static::SetCVal("xstep.cascade.unit", "MM"); + Interface_Static::SetCVal("write.step.unit", "MM"); + Interface_Static::SetIVal("write.step.nonmanifold", 1); + + writer.Transfer(p_shape, STEPControl_AsIs); + writer.Write(filename.c_str()); + break; + } + case Format::Unknown: + default: + throw std::invalid_argument("Unknown export format"); + } + } + + // + + [[nodiscard]] + sarray boundingBox() const + { + Bnd_Box bbox; + BRepBndLib::Add(p_shape, bbox, true); + gp_Pnt p1 {bbox.CornerMin()}; + gp_Pnt p2 {bbox.CornerMax()}; + + return sarray { + {static_cast(p1.X()), static_cast(p1.Y()), static_cast(p1.Z())}, + {static_cast(p2.X()), static_cast(p2.Y()), static_cast(p2.Z())} + }; + } + + void incrementalMesh(double deflection) + { + BRepTools::Clean(p_shape); + BRepMesh_IncrementalMesh(p_shape, deflection, true); + } + + darray subShapes(Type type) const + { + darray shapes; + for (TopExp_Explorer exp(p_shape, static_cast(type)); exp.More(); exp.Next()) + shapes.push(Shape(exp.Current())); + return shapes; + } + + darray edges() const + { + return subShapes(Type::Edge); + } + + darray faces() const + { + return subShapes(Type::Face); + } + + darray shells() const + { + return subShapes(Type::Shell); + } + + + + + + }; + + double distance(const Shape& lhs, const Shape& rhs) + { + return BRepExtrema_DistShapeShape(lhs.tshape(), rhs.tshape()).Value(); + } + +} + diff --git a/source/hpr/shape/shape_impl_occ.cpp b/source/hpr/shape/shape_impl_occ.cpp new file mode 100644 index 0000000..ab83a8e --- /dev/null +++ b/source/hpr/shape/shape_impl_occ.cpp @@ -0,0 +1,5 @@ + + + + + diff --git a/source/hpr/tests/main.cpp b/source/hpr/tests/main.cpp index a39743a..e20fbbb 100644 --- a/source/hpr/tests/main.cpp +++ b/source/hpr/tests/main.cpp @@ -1,7 +1,7 @@ -#include - -int main(int argc, char **argv) -{ - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +#include + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/source/hpr/tests/test_container.cpp b/source/hpr/tests/test_container.cpp index 395a7d4..17beb39 100644 --- a/source/hpr/tests/test_container.cpp +++ b/source/hpr/tests/test_container.cpp @@ -1,94 +1,94 @@ -#pragma once - -#include - -#include -#include -#include - - -TEST(containers, StaticArray) -{ - hpr::StaticArray arr {7, 3, 2}; - hpr::StaticArray sarr {arr, 5}; - hpr::StaticArray sarr2 {7, 3, 2, 5}; - //hpr::StaticArray sarr4; - - EXPECT_EQ(sarr, sarr2); - //EXPECT_EQ(sarr4.data(), nullptr); - //EXPECT_EQ(sarr4.is_empty(), true); - EXPECT_EQ(sarr.size(), 4); - EXPECT_EQ(sarr2.size(), 4); - EXPECT_EQ(sarr[0], 7); - EXPECT_EQ(sarr[1], 3); - EXPECT_EQ(sarr[2], 2); - EXPECT_EQ(sarr[3], 5); -} - -TEST(containers, DynamicArray) -{ - hpr::DynamicArray arr {1, 3, 2}; - hpr::DynamicArray arr2 {1, 3, 2}; - EXPECT_EQ(arr, arr2); - EXPECT_TRUE(arr == arr2); - arr.remove(1); - EXPECT_EQ(arr, hpr::darray({1, 2})); - auto iter = arr2.begin(); - ++iter; - arr2.remove(iter); - EXPECT_EQ(arr2, hpr::darray({1, 2})); - - hpr::DynamicArray arr3 {1, 3, 0, 2, 9, 0, 5}; - arr3.remove([](float num) { return num == 0; }); - EXPECT_EQ(arr3, hpr::darray({1, 3, 2, 9, 5})); - EXPECT_EQ(arr3.size(), 5); - arr3.insert(3, 19); - EXPECT_EQ(arr3.size(), 6); - EXPECT_EQ(arr3[3], 19); - EXPECT_EQ(arr3.pop(), 5); - EXPECT_EQ(arr3.size(), 5); - arr3.resize(3); - EXPECT_EQ(arr3.size(), 3); - EXPECT_EQ(arr3.capacity(), 3); - EXPECT_EQ(arr3.back(), 2); - arr3.resize(4); - EXPECT_EQ(arr3.back(), 2); - arr3.push(17); - arr3.push(14); - EXPECT_EQ(arr3.back(), 14); - EXPECT_EQ(arr3.size(), 5); - - arr3.clear(); - EXPECT_EQ(arr3.is_empty(), true); - - hpr::DynamicArray arr4; - arr4.push(new float(5)); - arr4.push(new float(7)); - arr4.push(new float(9)); - EXPECT_EQ(*arr4[0], 5.f); - EXPECT_EQ(*arr4[2], 9.f); - for (auto& v : arr4) - delete v; - - -} - -TEST(containers, TreeNode) -{ - hpr::TreeNode node1 (5); - //std::shared_ptr> ptr {node1}; - hpr::TreeNode node2 {7, {&node1}}; - hpr::TreeNode node3 {9, {&node2, &node1}}; - hpr::TreeNode node4 {11, {&node3}}; - - EXPECT_EQ(*node1.data(), 5); - //EXPECT_EQ(*node1->data(), *node2.ancestor()->data()); - - hpr::darray*> tr = node1.traverse_descendants(); - EXPECT_EQ(tr.size(), 0); - hpr::darray*> tr2 = node4.traverse_descendants(); - EXPECT_EQ(tr2.size(), 4); - hpr::darray*> tr3 = node1.traverse_ancestors(); - EXPECT_EQ(tr3.size(), 2); // node1 has changed ancestor - // -} +#pragma once + +#include + +#include +#include +#include + + +TEST(containers, StaticArray) +{ + hpr::StaticArray arr {7, 3, 2}; + hpr::StaticArray sarr {arr, 5}; + hpr::StaticArray sarr2 {7, 3, 2, 5}; + //hpr::StaticArray sarr4; + + EXPECT_EQ(sarr, sarr2); + //EXPECT_EQ(sarr4.data(), nullptr); + //EXPECT_EQ(sarr4.is_empty(), true); + EXPECT_EQ(sarr.size(), 4); + EXPECT_EQ(sarr2.size(), 4); + EXPECT_EQ(sarr[0], 7); + EXPECT_EQ(sarr[1], 3); + EXPECT_EQ(sarr[2], 2); + EXPECT_EQ(sarr[3], 5); +} + +TEST(containers, DynamicArray) +{ + hpr::DynamicArray arr {1, 3, 2}; + hpr::DynamicArray arr2 {1, 3, 2}; + EXPECT_EQ(arr, arr2); + EXPECT_TRUE(arr == arr2); + arr.remove(1); + EXPECT_EQ(arr, hpr::darray({1, 2})); + auto iter = arr2.begin(); + ++iter; + arr2.remove(iter); + EXPECT_EQ(arr2, hpr::darray({1, 2})); + + hpr::DynamicArray arr3 {1, 3, 0, 2, 9, 0, 5}; + arr3.remove([](float num) { return num == 0; }); + EXPECT_EQ(arr3, hpr::darray({1, 3, 2, 9, 5})); + EXPECT_EQ(arr3.size(), 5); + arr3.insert(3, 19); + EXPECT_EQ(arr3.size(), 6); + EXPECT_EQ(arr3[3], 19); + EXPECT_EQ(arr3.pop(), 5); + EXPECT_EQ(arr3.size(), 5); + arr3.resize(3); + EXPECT_EQ(arr3.size(), 3); + EXPECT_EQ(arr3.capacity(), 3); + EXPECT_EQ(arr3.back(), 2); + arr3.resize(4); + EXPECT_EQ(arr3.back(), 2); + arr3.push(17); + arr3.push(14); + EXPECT_EQ(arr3.back(), 14); + EXPECT_EQ(arr3.size(), 5); + + arr3.clear(); + EXPECT_EQ(arr3.is_empty(), true); + + hpr::DynamicArray arr4; + arr4.push(new float(5)); + arr4.push(new float(7)); + arr4.push(new float(9)); + EXPECT_EQ(*arr4[0], 5.f); + EXPECT_EQ(*arr4[2], 9.f); + for (auto& v : arr4) + delete v; + + +} + +TEST(containers, TreeNode) +{ + hpr::TreeNode node1 (5); + //std::shared_ptr> ptr {node1}; + hpr::TreeNode node2 {7, {&node1}}; + hpr::TreeNode node3 {9, {&node2, &node1}}; + hpr::TreeNode node4 {11, {&node3}}; + + EXPECT_EQ(*node1.data(), 5); + //EXPECT_EQ(*node1->data(), *node2.ancestor()->data()); + + hpr::darray*> tr = node1.traverse_descendants(); + EXPECT_EQ(tr.size(), 0); + hpr::darray*> tr2 = node4.traverse_descendants(); + EXPECT_EQ(tr2.size(), 4); + hpr::darray*> tr3 = node1.traverse_ancestors(); + EXPECT_EQ(tr3.size(), 2); // node1 has changed ancestor + // +} diff --git a/source/hpr/tests/test_math.cpp b/source/hpr/tests/test_math.cpp index 33f68d3..886c03e 100644 --- a/source/hpr/tests/test_math.cpp +++ b/source/hpr/tests/test_math.cpp @@ -1,63 +1,63 @@ -#pragma once - -#include - -#include -#include -#include - - -TEST(math, Vector) -{ - hpr::vec3 v1 {1, 3, 2}; - hpr::vec3 v2 {5, 7, -1}; - hpr::vec2 v31 {13, -2}; - hpr::vec3 v32 (v31, 9); - EXPECT_EQ((hpr::vec3(v2.begin(), v2.end())), v2); - EXPECT_EQ(v32, hpr::vec3(13, -2, 9)); - EXPECT_EQ(-v1, hpr::vec3(-1, -3, -2)); - EXPECT_EQ(v1 + v2, hpr::vec3(6, 10, 1)); - EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3)); - EXPECT_EQ((hpr::dot(v1, v2) ), 24); - EXPECT_EQ((hpr::cross(hpr::vec3(1, 0, 0), hpr::vec3(0, 1, 0))), hpr::vec3(0, 0, 1)); - EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::pi() * 0.5); - EXPECT_EQ((hpr::normalize(hpr::vec3(1, 1, 1))), hpr::vec3(0.5773502691896258, 0.5773502691896258, 0.5773502691896258)); -} - -TEST(math, Matrix) -{ - hpr::mat2 m1; - hpr::vec4 v1; - EXPECT_FALSE(v1 == m1); - EXPECT_FALSE(m1 == v1); - hpr::mat2 m2 {3, 2, 7, 4}; - hpr::vec2 v2 {2, 4}; - EXPECT_EQ(m2.col(1), v2); - hpr::vec2 v3 {13, 51}; - m2.col(1, v3); - EXPECT_EQ(m2.col(1), v3); - hpr::mat3 m4 {1, 2, 3, 4, 5, 6, 7, 8, 9}; - hpr::mat2 m41 {5, 6, 8, 9}; - //EXPECT_EQ(minor(m41, 0, 0), 9); - hpr::mat2 m5 {1, 2, 3, 4}; - - EXPECT_EQ(det(m4), 0); - EXPECT_EQ(hpr::det(m4), 0); - EXPECT_EQ(det(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9)), -786); - - hpr::mat2 m6 {2, 1, 7, 4}; - EXPECT_EQ(det(m6), 1); - EXPECT_EQ(adj(m6), hpr::mat2(4, -1, -7, 2)); - EXPECT_EQ(inv(m6), hpr::mat2(4, -1, -7, 2)); - EXPECT_EQ(det(hpr::mat3(1, 0, 0, 0, 1, 0, 0, 0, 1)), 1.); - //EXPECT_EQ(m4.det(), 0); - -} - -TEST(math, Quaternion) -{ - hpr::quat q; - hpr::vec3 np = hpr::rotate(hpr::vec3(0, 1, 0), {1, 0, 0}, hpr::pi() * 0.5); - EXPECT_TRUE(hpr::all(hpr::equal(np, hpr::vec3(0, 0, 1)))); - EXPECT_EQ(hpr::norm(hpr::quat(np)), 1); -} +#pragma once + +#include + +#include +#include +#include + + +TEST(math, Vector) +{ + hpr::vec3 v1 {1, 3, 2}; + hpr::vec3 v2 {5, 7, -1}; + hpr::vec2 v31 {13, -2}; + hpr::vec3 v32 (v31, 9); + EXPECT_EQ((hpr::vec3(v2.begin(), v2.end())), v2); + EXPECT_EQ(v32, hpr::vec3(13, -2, 9)); + EXPECT_EQ(-v1, hpr::vec3(-1, -3, -2)); + EXPECT_EQ(v1 + v2, hpr::vec3(6, 10, 1)); + EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3)); + EXPECT_EQ((hpr::dot(v1, v2) ), 24); + EXPECT_EQ((hpr::cross(hpr::vec3(1, 0, 0), hpr::vec3(0, 1, 0))), hpr::vec3(0, 0, 1)); + EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::pi() * 0.5); + EXPECT_EQ((hpr::normalize(hpr::vec3(1, 1, 1))), hpr::vec3(0.5773502691896258, 0.5773502691896258, 0.5773502691896258)); +} + +TEST(math, Matrix) +{ + hpr::mat2 m1; + hpr::vec4 v1; + EXPECT_FALSE(v1 == m1); + EXPECT_FALSE(m1 == v1); + hpr::mat2 m2 {3, 2, 7, 4}; + hpr::vec2 v2 {2, 4}; + EXPECT_EQ(m2.col(1), v2); + hpr::vec2 v3 {13, 51}; + m2.col(1, v3); + EXPECT_EQ(m2.col(1), v3); + hpr::mat3 m4 {1, 2, 3, 4, 5, 6, 7, 8, 9}; + hpr::mat2 m41 {5, 6, 8, 9}; + //EXPECT_EQ(minor(m41, 0, 0), 9); + hpr::mat2 m5 {1, 2, 3, 4}; + + EXPECT_EQ(det(m4), 0); + EXPECT_EQ(hpr::det(m4), 0); + EXPECT_EQ(det(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9)), -786); + + hpr::mat2 m6 {2, 1, 7, 4}; + EXPECT_EQ(det(m6), 1); + EXPECT_EQ(adj(m6), hpr::mat2(4, -1, -7, 2)); + EXPECT_EQ(inv(m6), hpr::mat2(4, -1, -7, 2)); + EXPECT_EQ(det(hpr::mat3(1, 0, 0, 0, 1, 0, 0, 0, 1)), 1.); + //EXPECT_EQ(m4.det(), 0); + +} + +TEST(math, Quaternion) +{ + hpr::quat q; + hpr::vec3 np = hpr::rotate(hpr::vec3(0, 1, 0), {1, 0, 0}, hpr::pi() * 0.5); + EXPECT_TRUE(hpr::all(hpr::equal(np, hpr::vec3(0, 0, 1)))); + EXPECT_EQ(hpr::norm(hpr::quat(np)), 1); +} diff --git a/source/hpr/tests/test_numeric.cpp b/source/hpr/tests/test_numeric.cpp index 7fb0da5..38994cc 100644 --- a/source/hpr/tests/test_numeric.cpp +++ b/source/hpr/tests/test_numeric.cpp @@ -1,41 +1,41 @@ -#pragma once -#include - -#include -#include - - -TEST(numeric, Scalar) -{ - EXPECT_EQ(hpr::scalar(5) + hpr::scalar(7), hpr::scalar(12)); -#ifdef HPR_SCALAR_IMPLEMENTATION - EXPECT_TRUE(std::is_floating_point_v>); - EXPECT_TRUE(std::is_arithmetic_v>); -#endif - //EXPECT_EQ(5.f, hpr::Scalar(5)); - EXPECT_EQ(hpr::rad(180), hpr::pi()); - EXPECT_EQ(hpr::deg(hpr::pi()), 180); - EXPECT_EQ(hpr::cos(0), 1); - EXPECT_EQ(hpr::sin(0), 0); - EXPECT_EQ(hpr::abs(hpr::scalar(-1)), 1); - EXPECT_EQ(hpr::pow(2, 2), 4); - EXPECT_EQ(hpr::precision(), static_cast(1e-15)); - - EXPECT_TRUE(typeid(static_cast(hpr::scalar(5))) == typeid(float)); - EXPECT_FALSE(!hpr::scalar(-1.)); - - std::stringstream oss; - oss << hpr::cos(0); - EXPECT_EQ(oss.str(), "1"); - hpr::scalar s; - oss >> s; - EXPECT_EQ(s, 1); - - EXPECT_TRUE(hpr::equal(5.5453535353535395818593, 5.5453535353535395817592, 1e-18)); - EXPECT_EQ(hpr::min(7., 5), 5); - EXPECT_EQ(hpr::max(7., 5), 7); - EXPECT_EQ(hpr::clip(7., 5, 10), 7); - EXPECT_EQ(hpr::clip(1., 5, 10), 5); - EXPECT_EQ(hpr::clip(72., 5, 10), 10); - -} +#pragma once +#include + +#include +#include + + +TEST(numeric, Scalar) +{ + EXPECT_EQ(hpr::scalar(5) + hpr::scalar(7), hpr::scalar(12)); +#ifdef HPR_SCALAR_IMPLEMENTATION + EXPECT_TRUE(std::is_floating_point_v>); + EXPECT_TRUE(std::is_arithmetic_v>); +#endif + //EXPECT_EQ(5.f, hpr::Scalar(5)); + EXPECT_EQ(hpr::rad(180), hpr::pi()); + EXPECT_EQ(hpr::deg(hpr::pi()), 180); + EXPECT_EQ(hpr::cos(0), 1); + EXPECT_EQ(hpr::sin(0), 0); + EXPECT_EQ(hpr::abs(hpr::scalar(-1)), 1); + EXPECT_EQ(hpr::pow(2, 2), 4); + EXPECT_EQ(hpr::precision(), static_cast(1e-15)); + + EXPECT_TRUE(typeid(static_cast(hpr::scalar(5))) == typeid(float)); + EXPECT_FALSE(!hpr::scalar(-1.)); + + std::stringstream oss; + oss << hpr::cos(0); + EXPECT_EQ(oss.str(), "1"); + hpr::scalar s; + oss >> s; + EXPECT_EQ(s, 1); + + EXPECT_TRUE(hpr::equal(5.5453535353535395818593, 5.5453535353535395817592, 1e-18)); + EXPECT_EQ(hpr::min(7., 5), 5); + EXPECT_EQ(hpr::max(7., 5), 7); + EXPECT_EQ(hpr::clip(7., 5, 10), 7); + EXPECT_EQ(hpr::clip(1., 5, 10), 5); + EXPECT_EQ(hpr::clip(72., 5, 10), 10); + +} diff --git a/source/hpr/xmake.lua b/source/hpr/xmake.lua index 03f7012..e750ede 100644 --- a/source/hpr/xmake.lua +++ b/source/hpr/xmake.lua @@ -1,72 +1,72 @@ -target("hpr") - set_kind("shared") - set_languages("c++20") - - set_policy("build.c++.modules", false) - - add_options("scalar", "scalar_implementation") - - add_includedirs("..", { public = true }) - - add_headerfiles("../(hpr/*.hpp)") - add_headerfiles("../(hpr/*/*.hpp)") - - add_files("hpr.cpp") - - -- export all symbols for windows/dll - if is_plat("windows") and is_kind("shared") then - if is_mode("release") then - set_optimize("fastest") - end - add_rules("utils.symbols.export_all") - end - - -- install importfiles for pkg-config/cmake - add_rules("utils.install.cmake_importfiles") - add_rules("utils.install.pkgconfig_importfiles") - - -- add packages - for _, name in ipairs({"imgui", "implot", "glfw", "opencascade"}) do - add_packages(name) - if has_package(name) then - set_configvar("HPR_HAVE_PACKAGE_" .. name:upper(), 1) - end - end -target_end() - - - -target("tests") - set_kind("binary") - set_default(false) - set_languages("c++20") - - if is_plat("mingw") or is_plat("windows") then - add_ldflags("-static", { force = true} ) - end - - set_policy("build.c++.modules", false) - - add_options("scalar", "scalar_implementation") - - add_packages("gtest") - - add_includedirs("..", { public = true }) - - add_files("tests/main.cpp") - - on_load(function (target) - for _, file in ipairs(os.files("source/hpr/tests/test_*.cpp")) do - target:add("files", file) - - for line in io.lines(file) do - local group, name = string.match(line:gsub("%s+", ""), "TEST%a*%((%a+),(%a+)%)") - - if group then - target:add("tests", group .. "/" .. name, { group = group, runargs = "--gtest_filter=" .. group .. "." .. name}) - end - end - end - end) -target_end() - +target("hpr") + set_kind("shared") + set_languages("c++20") + + set_policy("build.c++.modules", false) + + add_options("scalar", "scalar_implementation") + + add_includedirs("..", { public = true }) + + add_headerfiles("../(hpr/*.hpp)") + add_headerfiles("../(hpr/*/*.hpp)") + + add_files("hpr.cpp") + + -- export all symbols for windows/dll + if is_plat("windows") and is_kind("shared") then + if is_mode("release") then + set_optimize("fastest") + end + add_rules("utils.symbols.export_all") + end + + -- install importfiles for pkg-config/cmake + add_rules("utils.install.cmake_importfiles") + add_rules("utils.install.pkgconfig_importfiles") + + -- add packages + for _, name in ipairs({"imgui", "implot", "glfw", "opencascade"}) do + add_packages(name) + if has_package(name) then + set_configvar("HPR_HAVE_PACKAGE_" .. name:upper(), 1) + end + end +target_end() + + + +target("tests") + set_kind("binary") + set_default(false) + set_languages("c++20") + + if is_plat("mingw") or is_plat("windows") then + add_ldflags("-static", { force = true} ) + end + + set_policy("build.c++.modules", false) + + add_options("scalar", "scalar_implementation") + + add_packages("gtest") + + add_includedirs("..", { public = true }) + + add_files("tests/main.cpp") + + on_load(function (target) + for _, file in ipairs(os.files("source/hpr/tests/test_*.cpp")) do + target:add("files", file) + + for line in io.lines(file) do + local group, name = string.match(line:gsub("%s+", ""), "TEST%a*%((%a+),(%a+)%)") + + if group then + target:add("tests", group .. "/" .. name, { group = group, runargs = "--gtest_filter=" .. group .. "." .. name}) + end + end + end + end) +target_end() + diff --git a/source/xmake.lua b/source/xmake.lua index 704f1eb..d274815 100644 --- a/source/xmake.lua +++ b/source/xmake.lua @@ -1,65 +1,65 @@ - --- options: general -option("creator") - set_category("General") - set_default(false) - set_showmenu(true) - set_description("Build creator application") -option_end() - -option("tests") - set_category("General") - set_default(false) - set_showmenu(true) - set_description("Build tests") -option_end() - --- options: modules -for _, name in ipairs({"csg", "mesh"}) do - option(name) - set_category("Modules") - set_default(true) - set_showmenu(true) - set_description(format("Module %s", name)) - set_configvar("HPR_HAVE_MODULE_" .. name:upper(), 1) - option_end() -end - --- packages -add_requires("imgui v1.90-docking") -add_requires("implot v0.15") -add_requires("glfw 3.3.8") - -if has_config("csg") then - add_requires("conan::opencascade/7.6.2") -end - -if has_config("tests") then - add_requires("gtest") -end - --- - -option("scalar_implementation") - set_category("Internal") - set_default(true) - set_description("Use internal scalar implementation") - add_defines("HPR_SCALAR_IMPLEMENTATION") -option_end() - -option("scalar") - set_category("Internal") - set_values("float", "double", "long double") - set_default("float") - set_description("Internal scalar value type") - after_check(function(option) - option:add("defines", format("HPR_SCALAR=%s", option:value())) - end) -option_end() - - --- includes project dirs -includes("hpr") -if has_config("creator") then - includes("creator") + +-- options: general +option("creator") + set_category("General") + set_default(false) + set_showmenu(true) + set_description("Build creator application") +option_end() + +option("tests") + set_category("General") + set_default(false) + set_showmenu(true) + set_description("Build tests") +option_end() + +-- options: modules +for _, name in ipairs({"csg", "mesh"}) do + option(name) + set_category("Modules") + set_default(true) + set_showmenu(true) + set_description(format("Module %s", name)) + set_configvar("HPR_HAVE_MODULE_" .. name:upper(), 1) + option_end() +end + +-- packages +add_requires("imgui v1.90-docking") +add_requires("implot v0.15") +add_requires("glfw 3.3.8") + +if has_config("csg") then + add_requires("pacman::opencascade 7.7.2", {alias = "opencascade"}) +end + +if has_config("tests") then + add_requires("gtest") +end + +-- + +option("scalar_implementation") + set_category("Internal") + set_default(true) + set_description("Use internal scalar implementation") + add_defines("HPR_SCALAR_IMPLEMENTATION") +option_end() + +option("scalar") + set_category("Internal") + set_values("float", "double", "long double") + set_default("float") + set_description("Internal scalar value type") + after_check(function(option) + option:add("defines", format("HPR_SCALAR=%s", option:value())) + end) +option_end() + + +-- includes project dirs +includes("hpr") +if has_config("creator") then + includes("creator") end \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index 1673467..5fdedba 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,17 +1,17 @@ -set_project("hpr") - -set_version("0.0.1") - -add_rules("mode.debug", "mode.release") - -if is_mode("debug") then - add_defines("HPR_DEBUG") -end - -if is_plat("linux") and is_mode("debug") then - add_ldflags("-rdynamic") -end - -set_optimize("fastest") - +set_project("hpr") + +set_version("0.0.1") + +add_rules("mode.debug", "mode.release") + +if is_mode("debug") then + add_defines("HPR_DEBUG") +end + +if is_plat("linux") and is_mode("debug") then + add_ldflags("-rdynamic") +end + +set_optimize("fastest") + includes("source") \ No newline at end of file