From 4f71b3ac9084bf0292b8bfdd045d6bb88da9d9fc Mon Sep 17 00:00:00 2001 From: Slendi Date: Wed, 11 Mar 2026 23:52:54 +0200 Subject: [PATCH] Add .clang-format and format codebase Signed-off-by: Slendi --- .clang-format | 51 ++++++ examples/projection.cpp | 352 ++++++++++++++++++++------------------ examples/random_steps.cpp | 29 ++-- examples/tour.cpp | 81 ++++----- include/smath.hpp | 131 ++++++++------ tests/angles.cpp | 15 +- tests/interop.cpp | 27 ++- tests/vec.cpp | 251 ++++++++++++++------------- 8 files changed, 526 insertions(+), 411 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..749c245 --- /dev/null +++ b/.clang-format @@ -0,0 +1,51 @@ +--- +Language: Cpp +BasedOnStyle: LLVM + +IndentWidth: 4 +TabWidth: 4 +UseTab: ForIndentation + +ColumnLimit: 80 +AlignAfterOpenBracket: DontAlign +AlignOperands: false +BreakBeforeBinaryOperators: All +ContinuationIndentWidth: 4 +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Never + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + BeforeCatch: false + BeforeElse: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortBlocksOnASingleLine: Empty +SpaceInEmptyBlock: true +BinPackArguments: false +BinPackParameters: false +Cpp11BracedListStyle: false +SpaceBeforeCpp11BracedList: true +IndentRequiresClause: false +RequiresClausePosition: OwnLine + +PointerAlignment: Right +ReferenceAlignment: Right +IndentAccessModifiers: false +AccessModifierOffset: -4 + +SortIncludes: CaseSensitive +SpaceAfterTemplateKeyword: false +AlignEscapedNewlines: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +... diff --git a/examples/projection.cpp b/examples/projection.cpp index ba419ed..7621b60 100644 --- a/examples/projection.cpp +++ b/examples/projection.cpp @@ -13,202 +13,216 @@ #include using smath::Vec2; -enum Color : uint8_t { - CLR_NONE = 0, // default - CLR_AXES = 90, // bright black (gray) - CLR_A = 32, // green - CLR_B = 33, // yellow - CLR_P = 35, // magenta - CLR_DOT = 36 // cyan +enum Color : uint8_t +{ + CLR_NONE = 0, // default + CLR_AXES = 90, // bright black (gray) + CLR_A = 32, // green + CLR_B = 33, // yellow + CLR_P = 35, // magenta + CLR_DOT = 36 // cyan }; -struct Cell { - char ch{' '}; - uint8_t color{CLR_NONE}; - int prio{0}; +struct Cell +{ + char ch { ' ' }; + uint8_t color { CLR_NONE }; + int prio { 0 }; }; -struct Canvas { - int w, h; - std::vector pix; - Canvas(int W, int H) : w(W), h(H), pix(W * H) {} +struct Canvas +{ + int w, h; + std::vector pix; + Canvas(int W, int H) : w(W), h(H), pix(W * H) { } - void put(int x, int y, char c, int prio, uint8_t color) { - if (x < 0 || x >= w || y < 0 || y >= h) - return; - Cell &cell = pix[y * w + x]; - if (prio >= cell.prio) { - cell.ch = c; - cell.prio = prio; - cell.color = color; - } - } - void hline(int y, char c, int prio, uint8_t color) { - for (int x = 0; x < w; ++x) - put(x, y, c, prio, color); - } - void vline(int x, char c, int prio, uint8_t color) { - for (int y = 0; y < h; ++y) - put(x, y, c, prio, color); - } + void put(int x, int y, char c, int prio, uint8_t color) + { + if (x < 0 || x >= w || y < 0 || y >= h) + return; + Cell &cell = pix[y * w + x]; + if (prio >= cell.prio) { + cell.ch = c; + cell.prio = prio; + cell.color = color; + } + } + void hline(int y, char c, int prio, uint8_t color) + { + for (int x = 0; x < w; ++x) + put(x, y, c, prio, color); + } + void vline(int x, char c, int prio, uint8_t color) + { + for (int y = 0; y < h; ++y) + put(x, y, c, prio, color); + } - void line_dir(int x0, int y0, int x1, int y1, int prio, uint8_t color) { - int dx = std::abs(x1 - x0), sx = x0 < x1 ? 1 : -1; - int dy = -std::abs(y1 - y0), sy = y0 < y1 ? 1 : -1; - int err = dx + dy; + void line_dir(int x0, int y0, int x1, int y1, int prio, uint8_t color) + { + int dx = std::abs(x1 - x0), sx = x0 < x1 ? 1 : -1; + int dy = -std::abs(y1 - y0), sy = y0 < y1 ? 1 : -1; + int err = dx + dy; - int px = x0, py = y0; - put(px, py, '+', prio, color); + int px = x0, py = y0; + put(px, py, '+', prio, color); - while (true) { - if (px == x1 && py == y1) - break; - int e2 = 2 * err; - int nx = px, ny = py; - if (e2 >= dy) { - err += dy; - nx += sx; - } - if (e2 <= dx) { - err += dx; - ny += sy; - } + while (true) { + if (px == x1 && py == y1) + break; + int e2 = 2 * err; + int nx = px, ny = py; + if (e2 >= dy) { + err += dy; + nx += sx; + } + if (e2 <= dx) { + err += dx; + ny += sy; + } - int sdx = nx - px; - int sdy = ny - py; - int adx = std::abs(sdx); - int ady = std::abs(sdy); - char g; - if (adx >= 2 * ady) - g = '-'; - else if (ady >= 2 * adx) - g = '|'; - else - g = ((sdx > 0 && sdy > 0) || (sdx < 0 && sdy < 0)) ? '\\' : '/'; + int sdx = nx - px; + int sdy = ny - py; + int adx = std::abs(sdx); + int ady = std::abs(sdy); + char g; + if (adx >= 2 * ady) + g = '-'; + else if (ady >= 2 * adx) + g = '|'; + else + g = ((sdx > 0 && sdy > 0) || (sdx < 0 && sdy < 0)) ? '\\' : '/'; - put(nx, ny, g, prio, color); - px = nx; - py = ny; - } - } + put(nx, ny, g, prio, color); + px = nx; + py = ny; + } + } - void flush() const { - uint8_t cur = 255; - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - const Cell &c = pix[y * w + x]; - if (c.color != cur) { - if (c.color == CLR_NONE) - std::print("\x1b[0m"); - else - std::print("\x1b[{}m", c.color); - cur = c.color; - } - std::print("{}", c.ch); - } - std::println(""); - } - std::print("\x1b[0m"); - } + void flush() const + { + uint8_t cur = 255; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + const Cell &c = pix[y * w + x]; + if (c.color != cur) { + if (c.color == CLR_NONE) + std::print("\x1b[0m"); + else + std::print("\x1b[{}m", c.color); + cur = c.color; + } + std::print("{}", c.ch); + } + std::println(""); + } + std::print("\x1b[0m"); + } }; -struct Mapper { - int W, H; - double scale; - int cx, cy; - Mapper(int w, int h, double s) : W(w), H(h), scale(s), cx(w / 2), cy(h / 2) {} - std::pair map(Vec2 v) const { - int x = cx + (int)std::llround(v.x() * scale); - int y = cy - (int)std::llround(v.y() * scale); - return {x, y}; - } +struct Mapper +{ + int W, H; + double scale; + int cx, cy; + Mapper(int w, int h, double s) : W(w), H(h), scale(s), cx(w / 2), cy(h / 2) + { } + std::pair map(Vec2 v) const + { + int x = cx + (int)std::llround(v.x() * scale); + int y = cy - (int)std::llround(v.y() * scale); + return { x, y }; + } }; -int main() { +int main() +{ #if defined(_WIN32) - HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); - if (h != INVALID_HANDLE_VALUE) { - DWORD m; - if (GetConsoleMode(h, &m)) - SetConsoleMode(h, m | ENABLE_VIRTUAL_TERMINAL_PROCESSING); - } + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + if (h != INVALID_HANDLE_VALUE) { + DWORD m; + if (GetConsoleMode(h, &m)) + SetConsoleMode(h, m | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + } #endif - std::print("Enter vector a (ax ay): "); - double ax, ay; - if (!(std::cin >> ax >> ay)) - return 0; - std::print("Enter vector b (bx by): "); - double bx, by; - if (!(std::cin >> bx >> by)) - return 0; + std::print("Enter vector a (ax ay): "); + double ax, ay; + if (!(std::cin >> ax >> ay)) + return 0; + std::print("Enter vector b (bx by): "); + double bx, by; + if (!(std::cin >> bx >> by)) + return 0; - Vec2 a{(float)ax, (float)ay}; - Vec2 b{(float)bx, (float)by}; - Vec2 p = a.project_onto(b); + Vec2 a { (float)ax, (float)ay }; + Vec2 b { (float)bx, (float)by }; + Vec2 p = a.project_onto(b); - std::println("\nResults:"); - std::println("a = {}", a); - std::println("b = {}", b); - std::println("proj_b(a) = p = {}", p); - std::println("|a|={} |b|={} |p|={}", a.magnitude(), b.magnitude(), - p.magnitude()); - double dot = a.dot(b); - double ang = (a.magnitude() > 0 && b.magnitude() > 0) - ? std::acos(std::clamp(dot / (a.magnitude() * b.magnitude()), - -1.0, 1.0)) * - 180.0 / M_PI - : 0.0; - std::println("a·b={} angle(a,b)={} deg\n", dot, ang); + std::println("\nResults:"); + std::println("a = {}", a); + std::println("b = {}", b); + std::println("proj_b(a) = p = {}", p); + std::println( + "|a|={} |b|={} |p|={}", a.magnitude(), b.magnitude(), p.magnitude()); + double dot = a.dot(b); + double ang = (a.magnitude() > 0 && b.magnitude() > 0) + ? std::acos( + std::clamp(dot / (a.magnitude() * b.magnitude()), -1.0, 1.0)) + * 180.0 / M_PI + : 0.0; + std::println("a·b={} angle(a,b)={} deg\n", dot, ang); - const int W = 73, H = 33; - double maxr = std::max({(double)a.magnitude(), (double)b.magnitude(), - (double)p.magnitude(), 1.0}); - double usable = 0.45 * std::min(W, H); - double scale = usable / maxr; + const int W = 73, H = 33; + double maxr = std::max({ (double)a.magnitude(), + (double)b.magnitude(), + (double)p.magnitude(), + 1.0 }); + double usable = 0.45 * std::min(W, H); + double scale = usable / maxr; - Canvas cvs(W, H); - Mapper mp(W, H, scale); + Canvas cvs(W, H); + Mapper mp(W, H, scale); - int pr_axes = 1; - auto [cx, cy] = mp.map({0, 0}); - cvs.hline(H / 2, '-', pr_axes, CLR_AXES); - cvs.vline(W / 2, '|', pr_axes, CLR_AXES); - cvs.put(W / 2, H / 2, 'O', pr_axes + 1, CLR_AXES); + int pr_axes = 1; + auto [cx, cy] = mp.map({ 0, 0 }); + cvs.hline(H / 2, '-', pr_axes, CLR_AXES); + cvs.vline(W / 2, '|', pr_axes, CLR_AXES); + cvs.put(W / 2, H / 2, 'O', pr_axes + 1, CLR_AXES); - auto [ox, oy] = mp.map({0, 0}); - auto [ax1, ay1] = mp.map(a); - auto [bx1, by1] = mp.map(b); - auto [px1, py1] = mp.map(p); + auto [ox, oy] = mp.map({ 0, 0 }); + auto [ax1, ay1] = mp.map(a); + auto [bx1, by1] = mp.map(b); + auto [px1, py1] = mp.map(p); - int pr_a = 3, pr_b = 3, pr_p = 4; + int pr_a = 3, pr_b = 3, pr_p = 4; - cvs.line_dir(ox, oy, ax1, ay1, pr_a, CLR_A); - cvs.line_dir(ox, oy, bx1, by1, pr_b, CLR_B); - cvs.line_dir(ox, oy, px1, py1, pr_p, CLR_P); + cvs.line_dir(ox, oy, ax1, ay1, pr_a, CLR_A); + cvs.line_dir(ox, oy, bx1, by1, pr_b, CLR_B); + cvs.line_dir(ox, oy, px1, py1, pr_p, CLR_P); - if (!a.approx_equal(p) && b.magnitude() > 0) { - int steps = std::max(std::abs(ax1 - px1), std::abs(ay1 - py1)); - for (int i = 0; i <= steps; ++i) { - double t = steps ? double(i) / steps : 0.0; - int x = (int)std::llround(px1 + t * (ax1 - px1)); - int y = (int)std::llround(py1 + t * (ay1 - py1)); - if (i % 2 == 0) - cvs.put(x, y, '.', 2, CLR_DOT); - } - } + if (!a.approx_equal(p) && b.magnitude() > 0) { + int steps = std::max(std::abs(ax1 - px1), std::abs(ay1 - py1)); + for (int i = 0; i <= steps; ++i) { + double t = steps ? double(i) / steps : 0.0; + int x = (int)std::llround(px1 + t * (ax1 - px1)); + int y = (int)std::llround(py1 + t * (ay1 - py1)); + if (i % 2 == 0) + cvs.put(x, y, '.', 2, CLR_DOT); + } + } - auto place_label = [&](Vec2 v, const char *txt, uint8_t c, int pr) { - auto tip = mp.map(v * 1.05f); - for (int i = 0; txt[i]; ++i) - cvs.put(tip.first + i, tip.second, txt[i], pr, c); - }; - place_label(a, "A", CLR_A, pr_a + 1); - place_label(b, "B", CLR_B, pr_b + 1); - place_label(p, "P", CLR_P, pr_p + 1); + auto place_label = [&](Vec2 v, const char *txt, uint8_t c, int pr) { + auto tip = mp.map(v * 1.05f); + for (int i = 0; txt[i]; ++i) + cvs.put(tip.first + i, tip.second, txt[i], pr, c); + }; + place_label(a, "A", CLR_A, pr_a + 1); + place_label(b, "B", CLR_B, pr_b + 1); + place_label(p, "P", CLR_P, pr_p + 1); - std::println("Legend: axes(gray), a(green), b(yellow), p=proj(magenta), " - "dotted=cross-perp\n"); - cvs.flush(); - return 0; + std::println("Legend: axes(gray), a(green), b(yellow), p=proj(magenta), " + "dotted=cross-perp\n"); + cvs.flush(); + return 0; } diff --git a/examples/random_steps.cpp b/examples/random_steps.cpp index 9c2b684..c0b4d1c 100644 --- a/examples/random_steps.cpp +++ b/examples/random_steps.cpp @@ -24,20 +24,21 @@ #include -auto main() -> int { - using namespace smath; +auto main() -> int +{ + using namespace smath; - Vec2d point; - std::random_device rd; - std::mt19937 rng{rd()}; - std::uniform_real_distribution<> dis(-5, 5); - int i = 0; - do { - Vec2d add{dis(rng), dis(rng)}; - auto const n = point + add; - std::println("{}: {:.2f} + {:.2f} -> {:.2f}", i, point, add, n); - point = n; + Vec2d point; + std::random_device rd; + std::mt19937 rng { rd() }; + std::uniform_real_distribution<> dis(-5, 5); + int i = 0; + do { + Vec2d add { dis(rng), dis(rng) }; + auto const n = point + add; + std::println("{}: {:.2f} + {:.2f} -> {:.2f}", i, point, add, n); + point = n; - i++; - } while (i < 15); + i++; + } while (i < 15); } diff --git a/examples/tour.cpp b/examples/tour.cpp index f1d45ce..2e577ee 100644 --- a/examples/tour.cpp +++ b/examples/tour.cpp @@ -19,51 +19,52 @@ #include -int main() { - using namespace smath; - Vec3 v{1, 2, 3}; - std::println("v: {}", v); - auto v2 = swizzle<"zyx">(v); - std::println("v2: {}", v2); - std::println("+: {}", v + v2); - std::println("-: {}", v - v2); - std::println("*: {}", v * v2); - std::println("/: {}", v / v2); - std::println("dot: {}", v.dot(v2)); - std::println("rrggbb: {}", swizzle<"rrggbb">(v)); - std::println("Magnitude: {}", v.magnitude()); - std::println("Normalized: {}", v.normalized()); - std::println("(alias) Unit: {}", v.unit()); - std::println("(alias) Normalize: {}", v.normalize()); - std::println("(alias) Length: {}", v.length()); - std::println("std::get<1>(v): {}", std::get<1>(v)); - auto [x, y, z] = v; - std::println("Bindings: [{}, {}, {}]", x, y, z); - float x1{}, y1{}, z1{}; - v.unpack(x1, y1, z1); - std::println("Unpacked: {}, {}, {}", x1, y1, z1); +int main() +{ + using namespace smath; + Vec3 v { 1, 2, 3 }; + std::println("v: {}", v); + auto v2 = swizzle<"zyx">(v); + std::println("v2: {}", v2); + std::println("+: {}", v + v2); + std::println("-: {}", v - v2); + std::println("*: {}", v * v2); + std::println("/: {}", v / v2); + std::println("dot: {}", v.dot(v2)); + std::println("rrggbb: {}", swizzle<"rrggbb">(v)); + std::println("Magnitude: {}", v.magnitude()); + std::println("Normalized: {}", v.normalized()); + std::println("(alias) Unit: {}", v.unit()); + std::println("(alias) Normalize: {}", v.normalize()); + std::println("(alias) Length: {}", v.length()); + std::println("std::get<1>(v): {}", std::get<1>(v)); + auto [x, y, z] = v; + std::println("Bindings: [{}, {}, {}]", x, y, z); + float x1 {}, y1 {}, z1 {}; + v.unpack(x1, y1, z1); + std::println("Unpacked: {}, {}, {}", x1, y1, z1); - // Let's mix and match! - Vec<6> v3(v, 7, swizzle<"zy">(v2)); - std::println("{{v, 7, XZ(v2)}}: {}", v3); + // Let's mix and match! + Vec<6> v3(v, 7, swizzle<"zy">(v2)); + std::println("{{v, 7, XZ(v2)}}: {}", v3); - // Scalar operations - std::println("v + 3: {}", v + 3); - std::println("v - 3: {}", v - 3); - std::println("v * 3: {}", v * 3); - std::println("v / 3: {}", v / 3); + // Scalar operations + std::println("v + 3: {}", v + 3); + std::println("v - 3: {}", v - 3); + std::println("v * 3: {}", v * 3); + std::println("v / 3: {}", v / 3); - std::println("3 + v: {}", 3 + v); - std::println("3 - v: {}", 3 - v); - std::println("3 * v: {}", 3 * v); - std::println("3 / v: {}", 3 / v); + std::println("3 + v: {}", 3 + v); + std::println("3 - v: {}", 3 - v); + std::println("3 * v: {}", 3 * v); + std::println("3 / v: {}", 3 / v); - // Casting - auto v4 = static_cast(v); + // Casting + auto v4 = static_cast(v); #ifdef SMATH_IMPLICIT_CONVERSIONS - Vec3d v5 = v; + Vec3d v5 = v; #else - Vec3d v5 = static_cast(v); + Vec3d v5 = static_cast(v); #endif // SMATH_IMPLICIT_CONVERSIONS - std::println("Are v4 and v5 same? {}", v4 == v5); + std::println("Are v4 and v5 same? {}", v4 == v5); } diff --git a/include/smath.hpp b/include/smath.hpp index 46e2899..9097704 100644 --- a/include/smath.hpp +++ b/include/smath.hpp @@ -32,20 +32,23 @@ #include #ifndef SMATH_ANGLE_UNIT -# define SMATH_ANGLE_UNIT rad +#define SMATH_ANGLE_UNIT rad #endif // SMATH_ANGLE_UNIT -namespace smath { +namespace smath +{ template -requires std::is_arithmetic_v struct Vec; +requires std::is_arithmetic_v +struct Vec; -namespace detail { +namespace detail +{ #define SMATH_STR(x) #x #define SMATH_XSTR(x) SMATH_STR(x) -consteval bool streq(const char *a, const char *b) +consteval auto streq(const char *a, const char *b) -> bool { for (;; ++a, ++b) { if (*a != *b) @@ -55,13 +58,14 @@ consteval bool streq(const char *a, const char *b) } } -enum class AngularUnit { +enum class AngularUnit +{ Radians, Degrees, Turns, }; -consteval std::optional parse_unit(char const *s) +consteval auto parse_unit(char const *s) -> std::optional { if (streq(s, "rad")) return AngularUnit::Radians; @@ -76,7 +80,8 @@ constexpr auto SMATH_ANGLE_UNIT_ID = parse_unit(SMATH_XSTR(SMATH_ANGLE_UNIT)); static_assert(SMATH_ANGLE_UNIT_ID != std::nullopt, "Invalid SMATH_ANGLE_UNIT. Should be rad, deg, or turns."); -template struct FixedString { +template struct FixedString +{ char data[N] {}; static constexpr std::size_t size = N - 1; constexpr FixedString(char const (&s)[N]) @@ -86,8 +91,10 @@ template struct FixedString { } constexpr char operator[](std::size_t i) const { return data[i]; } }; -template struct is_Vec : std::false_type { }; -template struct is_Vec> : std::true_type { }; +template struct is_Vec : std::false_type +{ }; +template struct is_Vec> : std::true_type +{ }; template inline constexpr bool is_Vec_v = is_Vec>::value; template @@ -95,7 +102,8 @@ inline constexpr bool is_scalar_v = std::is_arithmetic_v>; template struct Vec_size; template -struct Vec_size> : std::integral_constant { }; +struct Vec_size> : std::integral_constant +{ }; template constexpr auto pack_unorm8(T v) -> std::uint8_t { @@ -144,9 +152,11 @@ template constexpr auto unpack_snorm8(std::int8_t b) -> T } // namespace detail template -requires std::is_arithmetic_v struct Vec : std::array { +requires std::is_arithmetic_v +struct Vec : std::array +{ private: - template static consteval std::size_t extent() + template static consteval auto extent() -> std::size_t { if constexpr (detail::is_Vec_v) return detail::Vec_size>::value; @@ -155,7 +165,7 @@ private: else return 0; // Should be unreachable } - template static consteval std::size_t total_extent() + template static consteval auto total_extent() -> std::size_t { return (extent() + ... + 0); } @@ -188,12 +198,9 @@ public: // NOTE: This can (probably) be improved with C++26 reflection in the // future. #define VEC_ACC(component, req, idx) \ - constexpr auto component() noexcept -> T & \ - requires(N >= req) \ - { \ + constexpr auto component() noexcept -> T &requires(N >= req) { \ return (*this)[idx]; \ - } \ - constexpr auto component() const -> T const & \ + } constexpr auto component() const->T const & \ requires(N >= req) \ { \ return (*this)[idx]; \ @@ -225,7 +232,8 @@ public: ((args = (*this)[Is]), ...); } - template constexpr void unpack(Args &...args) noexcept + template + constexpr auto unpack(Args &...args) noexcept -> void { unpack_impl(std::index_sequence_for {}, args...); } @@ -284,13 +292,13 @@ public: VEC_OP(/) #undef VEC_OP #define VEC_OP_ASSIGN(sym) \ - constexpr Vec &operator sym## = (Vec const &rhs) noexcept \ + constexpr Vec &operator sym##=(Vec const &rhs) noexcept \ { \ for (std::size_t i = 0; i < N; ++i) \ (*this)[i] sym## = rhs[i]; \ return *this; \ } \ - constexpr Vec &operator sym## = (T const &s) noexcept \ + constexpr Vec &operator sym##=(T const &s) noexcept \ { \ for (std::size_t i = 0; i < N; ++i) \ (*this)[i] sym## = s; \ @@ -393,11 +401,14 @@ public: } template - requires(N == 3) constexpr auto cross(Vec const &r) const noexcept -> Vec + requires(N == 3) + constexpr auto cross(Vec const &r) const noexcept -> Vec { - return { (*this)[1] * r[2] - (*this)[2] * r[1], + return { + (*this)[1] * r[2] - (*this)[2] * r[1], (*this)[2] * r[0] - (*this)[0] * r[2], - (*this)[0] * r[1] - (*this)[1] * r[0] }; + (*this)[0] * r[1] - (*this)[1] * r[0], + }; } constexpr auto distance(Vec const &r) const noexcept -> T @@ -425,8 +436,8 @@ public: template requires(std::is_arithmetic_v && N >= 1) - constexpr explicit(!std::is_convertible_v) - operator Vec() const noexcept + constexpr explicit( + !std::is_convertible_v) operator Vec() const noexcept { Vec r {}; for (std::size_t i = 0; i < N; ++i) @@ -444,26 +455,26 @@ public: } private: - constexpr void fill_one(std::size_t &i, T const &v) noexcept + constexpr auto fill_one(std::size_t &i, T const &v) noexcept -> void { (*this)[i++] = v; } #ifdef SMATH_IMPLICIT_CONVERSIONS template - requires std::is_arithmetic_v && (!std::is_same_v)constexpr void - fill_one(std::size_t &i, const U &v) noexcept + requires std::is_arithmetic_v && (!std::is_same_v) + constexpr auto fill_one(std::size_t &i, const U &v) noexcept -> void { (*this)[i++] = static_cast(v); } template - constexpr void fill_one(std::size_t &i, Vec const &v) noexcept + constexpr auto fill_one(std::size_t &i, Vec const &v) noexcept -> void { for (std::size_t k = 0; k < M; ++k) (*this)[i++] = static_cast(v[k]); } #endif // SMATH_IMPLICIT_CONVERSIONS template - constexpr void fill_one(std::size_t &i, const Vec &v) noexcept + constexpr auto fill_one(std::size_t &i, const Vec &v) noexcept -> void { for (std::size_t k = 0; k < M; ++k) (*this)[i++] = static_cast(v[k]); @@ -497,7 +508,8 @@ template requires std::is_arithmetic_v using VecOrScalar = std::conditional_t>; -namespace detail { +namespace detail +{ consteval auto char_to_idx(char c) -> std::size_t { @@ -627,9 +639,11 @@ template constexpr auto turns(T value) } } template -requires std::is_arithmetic_v struct Mat; +requires std::is_arithmetic_v +struct Mat; -template struct Quaternion : Vec<4, T> { +template struct Quaternion : Vec<4, T> +{ using Base = Vec<4, T>; using Base::Base; using Base::operator=; @@ -759,7 +773,9 @@ requires std::is_floating_point_v } template -requires std::is_arithmetic_v struct Mat : std::array, C> { +requires std::is_arithmetic_v +struct Mat : std::array, C> +{ using Base = std::array, C>; using Base::operator[]; @@ -792,10 +808,8 @@ requires std::is_arithmetic_v struct Mat : std::array, C> { template requires(sizeof...(Cols) == C && (std::same_as, Vec> && ...)) - constexpr Mat(Cols const &...cols) noexcept - : Base { cols... } - { - } + constexpr Mat(Cols const &...cols) noexcept : Base { cols... } + { } constexpr auto col(std::size_t j) noexcept -> Vec & { @@ -1100,8 +1114,12 @@ template } template -[[nodiscard]] inline auto matrix_ortho3d(T const left, T const right, - T const bottom, T const top, T const near, T const far, +[[nodiscard]] inline auto matrix_ortho3d(T const left, + T const right, + T const bottom, + T const top, + T const near, + T const far, bool const flip_z_axis = true) -> Mat<4, 4, T> { Mat<4, 4, T> res {}; @@ -1148,8 +1166,9 @@ inline auto matrix_perspective( } template -[[nodiscard]] inline auto matrix_look_at(Vec<3, T> const eye, - Vec<3, T> const center, Vec<3, T> const up) -> Mat<4, 4, T> +[[nodiscard]] inline auto matrix_look_at( + Vec<3, T> const eye, Vec<3, T> const center, Vec<3, T> const up) + -> Mat<4, 4, T> { auto f = (center - eye).normalized_safe(); auto s = f.cross(up).normalized_safe(); @@ -1164,8 +1183,9 @@ template } template -[[nodiscard]] inline auto matrix_infinite_perspective(T const fovy, - T const aspect, T const znear, bool flip_z_axis = false) -> Mat<4, 4, T> +[[nodiscard]] inline auto matrix_infinite_perspective( + T const fovy, T const aspect, T const znear, bool flip_z_axis = false) + -> Mat<4, 4, T> { Mat<4, 4, T> m {}; @@ -1186,12 +1206,11 @@ template return m; } - template struct interop_adapter; template -constexpr auto from_external(Ext const &ext) - -> typename interop_adapter::smath_type +constexpr auto from_external(Ext const &ext) -> + typename interop_adapter::smath_type { return interop_adapter::to_smath(ext); } @@ -1202,12 +1221,12 @@ constexpr auto to_external(SMathT const &value) -> Ext return interop_adapter::from_smath(value); } - } // namespace smath template requires std::formattable -struct std::formatter> : std::formatter { +struct std::formatter> : std::formatter +{ constexpr auto parse(std::format_parse_context &ctx) { return std::formatter::parse(ctx); @@ -1230,12 +1249,14 @@ struct std::formatter> : std::formatter { } }; -namespace std { +namespace std +{ template -struct tuple_size> : std::integral_constant { }; +struct tuple_size> : std::integral_constant +{ }; -template -struct tuple_element> { +template struct tuple_element> +{ static_assert(I < N); using type = T; }; diff --git a/tests/angles.cpp b/tests/angles.cpp index f454e14..6453a4e 100644 --- a/tests/angles.cpp +++ b/tests/angles.cpp @@ -2,14 +2,17 @@ #include -TEST(AngleReturnRadians, DegInput) { - EXPECT_NEAR(smath::deg(180.0), std::numbers::pi, 1e-12); +TEST(AngleReturnRadians, DegInput) +{ + EXPECT_NEAR(smath::deg(180.0), std::numbers::pi, 1e-12); } -TEST(AngleReturnRadians, RadInput) { - EXPECT_DOUBLE_EQ(smath::rad(std::numbers::pi), std::numbers::pi); +TEST(AngleReturnRadians, RadInput) +{ + EXPECT_DOUBLE_EQ(smath::rad(std::numbers::pi), std::numbers::pi); } -TEST(AngleReturnRadians, TurnsInput) { - EXPECT_NEAR(smath::turns(0.5), std::numbers::pi, 1e-12); +TEST(AngleReturnRadians, TurnsInput) +{ + EXPECT_NEAR(smath::turns(0.5), std::numbers::pi, 1e-12); } diff --git a/tests/interop.cpp b/tests/interop.cpp index 30f9d13..d7dc2e9 100644 --- a/tests/interop.cpp +++ b/tests/interop.cpp @@ -4,22 +4,26 @@ #include -struct ExternalVec3f { +struct ExternalVec3f +{ float x; float y; float z; }; -struct ExternalMat2f { +struct ExternalMat2f +{ float m00; float m01; float m10; float m11; }; -namespace smath { +namespace smath +{ -template<> struct interop_adapter { +template<> struct interop_adapter +{ using smath_type = Vec<3, float>; static constexpr auto to_smath(ExternalVec3f const &v) -> smath_type @@ -33,7 +37,8 @@ template<> struct interop_adapter { } }; -template<> struct interop_adapter { +template<> struct interop_adapter +{ using smath_type = Mat<2, 2, float>; static constexpr auto to_smath(ExternalMat2f const &m) -> smath_type @@ -54,7 +59,8 @@ template<> struct interop_adapter { } // namespace smath -TEST(Interop, FromExternalVec) { +TEST(Interop, FromExternalVec) +{ ExternalVec3f ext { 1.0f, 2.0f, 3.0f }; auto v = smath::from_external(ext); @@ -64,7 +70,8 @@ TEST(Interop, FromExternalVec) { EXPECT_EQ(v[2], 3.0f); } -TEST(Interop, ToExternalVec) { +TEST(Interop, ToExternalVec) +{ smath::Vec3 v { 4.0f, 5.0f, 6.0f }; auto ext = smath::to_external(v); @@ -73,7 +80,8 @@ TEST(Interop, ToExternalVec) { EXPECT_EQ(ext.z, 6.0f); } -TEST(Interop, RoundtripVec) { +TEST(Interop, RoundtripVec) +{ ExternalVec3f ext { 7.0f, 8.0f, 9.0f }; auto v = smath::from_external(ext); auto ext2 = smath::to_external(v); @@ -83,7 +91,8 @@ TEST(Interop, RoundtripVec) { EXPECT_EQ(ext2.z, 9.0f); } -TEST(Interop, MatrixConversion) { +TEST(Interop, MatrixConversion) +{ ExternalMat2f ext { 1.0f, 2.0f, 3.0f, 4.0f }; auto m = smath::from_external(ext); diff --git a/tests/vec.cpp b/tests/vec.cpp index b4d6502..ce23ce5 100644 --- a/tests/vec.cpp +++ b/tests/vec.cpp @@ -11,169 +11,184 @@ using smath::Vec2; using smath::Vec3; using smath::Vec4; -template -static void ExpectVecNear(const Vec<3, T> &a, const Vec<3, T> &b, - T eps = T(1e-6)) { - for (int i = 0; i < 3; ++i) - EXPECT_NEAR(double(a[i]), double(b[i]), double(eps)); +template +static void ExpectVecNear( + const Vec<3, T> &a, const Vec<3, T> &b, T eps = T(1e-6)) +{ + for (int i = 0; i < 3; ++i) + EXPECT_NEAR(double(a[i]), double(b[i]), double(eps)); } // Constructors and accessors -TEST(Vec, DefaultZero) { - Vec3 v; - EXPECT_EQ(v[0], 0.0f); - EXPECT_EQ(v[1], 0.0f); - EXPECT_EQ(v[2], 0.0f); +TEST(Vec, DefaultZero) +{ + Vec3 v; + EXPECT_EQ(v[0], 0.0f); + EXPECT_EQ(v[1], 0.0f); + EXPECT_EQ(v[2], 0.0f); } -TEST(Vec, ScalarFillCtor) { - Vec4 v{2.0f}; - EXPECT_EQ(v.x(), 2.0f); - EXPECT_EQ(v.y(), 2.0f); - EXPECT_EQ(v.z(), 2.0f); - EXPECT_EQ(v.w(), 2.0f); +TEST(Vec, ScalarFillCtor) +{ + Vec4 v { 2.0f }; + EXPECT_EQ(v.x(), 2.0f); + EXPECT_EQ(v.y(), 2.0f); + EXPECT_EQ(v.z(), 2.0f); + EXPECT_EQ(v.w(), 2.0f); } -TEST(Vec, VariadicCtorScalarsAndSubvectors) { - Vec2 a{1.0f, 2.0f}; - Vec2 b{3.0f, 4.0f}; - Vec4 v{a, b}; - EXPECT_EQ(v.r(), 1.0f); - EXPECT_EQ(v.g(), 2.0f); - EXPECT_EQ(v.b(), 3.0f); - EXPECT_EQ(v.a(), 4.0f); +TEST(Vec, VariadicCtorScalarsAndSubvectors) +{ + Vec2 a { 1.0f, 2.0f }; + Vec2 b { 3.0f, 4.0f }; + Vec4 v { a, b }; + EXPECT_EQ(v.r(), 1.0f); + EXPECT_EQ(v.g(), 2.0f); + EXPECT_EQ(v.b(), 3.0f); + EXPECT_EQ(v.a(), 4.0f); } -TEST(Vec, NamedAccessorsAliases) { - Vec3 v{1.0f, 2.0f, 3.0f}; - EXPECT_EQ(v.x(), v.r()); - EXPECT_EQ(v.y(), v.g()); - EXPECT_EQ(v.z(), v.b()); +TEST(Vec, NamedAccessorsAliases) +{ + Vec3 v { 1.0f, 2.0f, 3.0f }; + EXPECT_EQ(v.x(), v.r()); + EXPECT_EQ(v.y(), v.g()); + EXPECT_EQ(v.z(), v.b()); } // Arithmetic -TEST(Vec, ElementwiseAndScalarOps) { - Vec3 a{1.0f, 2.0f, 3.0f}; - Vec3 b{4.0f, 5.0f, 6.0f}; +TEST(Vec, ElementwiseAndScalarOps) +{ + Vec3 a { 1.0f, 2.0f, 3.0f }; + Vec3 b { 4.0f, 5.0f, 6.0f }; - auto s1 = a + b; - EXPECT_EQ(s1[0], 5.0f); - EXPECT_EQ(s1[1], 7.0f); - EXPECT_EQ(s1[2], 9.0f); + auto s1 = a + b; + EXPECT_EQ(s1[0], 5.0f); + EXPECT_EQ(s1[1], 7.0f); + EXPECT_EQ(s1[2], 9.0f); - auto s2 = a * 2.0f; - EXPECT_EQ(s2[0], 2.0f); - EXPECT_EQ(s2[1], 4.0f); - EXPECT_EQ(s2[2], 6.0f); + auto s2 = a * 2.0f; + EXPECT_EQ(s2[0], 2.0f); + EXPECT_EQ(s2[1], 4.0f); + EXPECT_EQ(s2[2], 6.0f); - auto s3 = 2.0f * a; // RHS overloads - EXPECT_EQ(s3[0], 2.0f); - EXPECT_EQ(s3[1], 4.0f); - EXPECT_EQ(s3[2], 6.0f); + auto s3 = 2.0f * a; // RHS overloads + EXPECT_EQ(s3[0], 2.0f); + EXPECT_EQ(s3[1], 4.0f); + EXPECT_EQ(s3[2], 6.0f); - Vec3 c{1.0f, 2.0f, 3.0f}; - c += Vec3{1.0f, 1.0f, 1.0f}; - EXPECT_EQ(c[0], 2.0f); - EXPECT_EQ(c[1], 3.0f); - EXPECT_EQ(c[2], 4.0f); + Vec3 c { 1.0f, 2.0f, 3.0f }; + c += Vec3 { 1.0f, 1.0f, 1.0f }; + EXPECT_EQ(c[0], 2.0f); + EXPECT_EQ(c[1], 3.0f); + EXPECT_EQ(c[2], 4.0f); - c *= 2.0f; - EXPECT_EQ(c[0], 4.0f); - EXPECT_EQ(c[1], 6.0f); - EXPECT_EQ(c[2], 8.0f); + c *= 2.0f; + EXPECT_EQ(c[0], 4.0f); + EXPECT_EQ(c[1], 6.0f); + EXPECT_EQ(c[2], 8.0f); } // Length, dot, cross, normalize -TEST(Vec, MagnitudeAndDot) { - Vec3 v{3.0f, 4.0f, 12.0f}; - EXPECT_FLOAT_EQ(v.magnitude(), 13.0f); - EXPECT_FLOAT_EQ(v.length(), 13.0f); +TEST(Vec, MagnitudeAndDot) +{ + Vec3 v { 3.0f, 4.0f, 12.0f }; + EXPECT_FLOAT_EQ(v.magnitude(), 13.0f); + EXPECT_FLOAT_EQ(v.length(), 13.0f); - Vec3 u{1.0f, 0.0f, 2.0f}; - EXPECT_FLOAT_EQ(v.dot(u), 27.0f); + Vec3 u { 1.0f, 0.0f, 2.0f }; + EXPECT_FLOAT_EQ(v.dot(u), 27.0f); } -TEST(Vec, Cross3D) { - Vec3 x{1.0f, 0.0f, 0.0f}; - Vec3 y{0.0f, 1.0f, 0.0f}; - auto z = x.cross(y); - EXPECT_EQ(z[0], 0.0f); - EXPECT_EQ(z[1], 0.0f); - EXPECT_EQ(z[2], 1.0f); +TEST(Vec, Cross3D) +{ + Vec3 x { 1.0f, 0.0f, 0.0f }; + Vec3 y { 0.0f, 1.0f, 0.0f }; + auto z = x.cross(y); + EXPECT_EQ(z[0], 0.0f); + EXPECT_EQ(z[1], 0.0f); + EXPECT_EQ(z[2], 1.0f); } -TEST(Vec, NormalizeAndSafeNormalize) { - Vec3 v{10.0f, 0.0f, 0.0f}; - auto n = v.normalized(); - auto ns = v.normalized_safe(); - ExpectVecNear(n, Vec3{1.0f, 0.0f, 0.0f}); +TEST(Vec, NormalizeAndSafeNormalize) +{ + Vec3 v { 10.0f, 0.0f, 0.0f }; + auto n = v.normalized(); + auto ns = v.normalized_safe(); + ExpectVecNear(n, Vec3 { 1.0f, 0.0f, 0.0f }); - Vec3 zero{}; - auto zs = zero.normalized_safe(); - EXPECT_EQ(zs[0], 0.0f); - EXPECT_EQ(zs[1], 0.0f); - EXPECT_EQ(zs[2], 0.0f); + Vec3 zero {}; + auto zs = zero.normalized_safe(); + EXPECT_EQ(zs[0], 0.0f); + EXPECT_EQ(zs[1], 0.0f); + EXPECT_EQ(zs[2], 0.0f); } -TEST(Vec, DistanceAndProjection) { - Vec3 a{1.0f, 2.0f, 3.0f}; - Vec3 b{4.0f, 6.0f, 3.0f}; - EXPECT_FLOAT_EQ(a.distance(b), 5.0f); +TEST(Vec, DistanceAndProjection) +{ + Vec3 a { 1.0f, 2.0f, 3.0f }; + Vec3 b { 4.0f, 6.0f, 3.0f }; + EXPECT_FLOAT_EQ(a.distance(b), 5.0f); - Vec3 n{2.0f, 0.0f, 0.0f}; // onto x-axis scaled - auto p = a.project_onto(n); // (a·n)/(n·n) * n = (2)/4 * n = 0.5 * n - ExpectVecNear(p, Vec3{1.0f, 0.0f, 0.0f}); + Vec3 n { 2.0f, 0.0f, 0.0f }; // onto x-axis scaled + auto p = a.project_onto(n); // (a·n)/(n·n) * n = (2)/4 * n = 0.5 * n + ExpectVecNear(p, Vec3 { 1.0f, 0.0f, 0.0f }); } // Approx equal -TEST(Vec, ApproxEqual) { - Vec3 a{1.0f, 2.0f, 3.0f}; - Vec3 b{1.0f + 1e-7f, 2.0f - 1e-7f, 3.0f}; - EXPECT_TRUE(a.approx_equal(b, 1e-6f)); - EXPECT_FALSE(a.approx_equal(b, 1e-9f)); +TEST(Vec, ApproxEqual) +{ + Vec3 a { 1.0f, 2.0f, 3.0f }; + Vec3 b { 1.0f + 1e-7f, 2.0f - 1e-7f, 3.0f }; + EXPECT_TRUE(a.approx_equal(b, 1e-6f)); + EXPECT_FALSE(a.approx_equal(b, 1e-9f)); } // std::get & tuple interop -TEST(Vec, StdGetAndTuple) { - Vec3 v{7.0f, 8.0f, 9.0f}; - static_assert(std::tuple_size_v == 3); - static_assert(std::is_same_v, float>); - EXPECT_EQ(std::get<0>(v), 7.0f); - EXPECT_EQ(std::get<1>(v), 8.0f); - EXPECT_EQ(std::get<2>(v), 9.0f); +TEST(Vec, StdGetAndTuple) +{ + Vec3 v { 7.0f, 8.0f, 9.0f }; + static_assert(std::tuple_size_v == 3); + static_assert(std::is_same_v, float>); + EXPECT_EQ(std::get<0>(v), 7.0f); + EXPECT_EQ(std::get<1>(v), 8.0f); + EXPECT_EQ(std::get<2>(v), 9.0f); } // Swizzle -TEST(Vec, SwizzleBasic) { - const Vec3 v{1.0f, 2.0f, 3.0f}; +TEST(Vec, SwizzleBasic) +{ + const Vec3 v { 1.0f, 2.0f, 3.0f }; - auto yz = smath::swizzle<"yz">(v); - EXPECT_EQ(yz[0], 2.0f); - EXPECT_EQ(yz[1], 3.0f); + auto yz = smath::swizzle<"yz">(v); + EXPECT_EQ(yz[0], 2.0f); + EXPECT_EQ(yz[1], 3.0f); - auto rxx = smath::swizzle<"xxy">(v); - EXPECT_EQ(rxx[0], 1.0f); - EXPECT_EQ(rxx[1], 1.0f); - EXPECT_EQ(rxx[2], 2.0f); + auto rxx = smath::swizzle<"xxy">(v); + EXPECT_EQ(rxx[0], 1.0f); + EXPECT_EQ(rxx[1], 1.0f); + EXPECT_EQ(rxx[2], 2.0f); } // std::formatter -TEST(Vec, Formatter) { - smath::Vec<3, int> vi{1, 2, 3}; - std::string s = std::format("{}", vi); - EXPECT_EQ(s, "{1, 2, 3}"); +TEST(Vec, Formatter) +{ + smath::Vec<3, int> vi { 1, 2, 3 }; + std::string s = std::format("{}", vi); + EXPECT_EQ(s, "{1, 2, 3}"); } // Conversions -TEST(Vec, ExplicitConversionBetweenScalarTypes) { - smath::Vec<3, int> vi{1, 2, 3}; - smath::Vec<3, float> vf{vi}; - EXPECT_EQ(vf[0], 1.0f); - EXPECT_EQ(vf[1], 2.0f); - EXPECT_EQ(vf[2], 3.0f); +TEST(Vec, ExplicitConversionBetweenScalarTypes) +{ + smath::Vec<3, int> vi { 1, 2, 3 }; + smath::Vec<3, float> vf { vi }; + EXPECT_EQ(vf[0], 1.0f); + EXPECT_EQ(vf[1], 2.0f); + EXPECT_EQ(vf[2], 3.0f); - auto vi2 = static_cast>(vf); - EXPECT_EQ(vi2[0], 1); - EXPECT_EQ(vi2[1], 2); - EXPECT_EQ(vi2[2], 3); + auto vi2 = static_cast>(vf); + EXPECT_EQ(vi2[0], 1); + EXPECT_EQ(vi2[1], 2); + EXPECT_EQ(vi2[2], 3); }