LeviLamina
Loading...
Searching...
No Matches
VectorBase.h
1#pragma once
2
3#include <concepts>
4#include <cstddef>
5#include <functional>
6#include <string>
7#include <string_view>
8#include <type_traits>
9#include <utility>
10
11#include "ll/api/base/Concepts.h"
12#include "ll/api/base/Macro.h"
13#include "ll/api/base/Meta.h"
14#include "ll/api/utils/HashUtils.h"
15
16#include "fmt/format.h"
17
18namespace ll::math {
19
20template <typename T, typename = void>
21struct has_toString : std::false_type {};
22
23template <typename T>
24struct has_toString<T, std::void_t<decltype(std::declval<T>().toString())>> : std::true_type {};
25
26template <typename T, typename = void>
27struct has_hash : std::false_type {};
28
29template <typename T>
30struct has_hash<T, std::void_t<decltype(std::declval<T>().hash())>> : std::true_type {};
31
32struct LL_EBO BoolNTag {};
33
34template <typename T>
35concept IsBoolN = std::is_base_of_v<BoolNTag, T>;
36
37struct LL_EBO IntNTag {};
38
39template <typename T>
40concept IsIntN = std::is_base_of_v<IntNTag, T>;
41
42struct LL_EBO FloatNTag {};
43
44template <typename T>
45concept IsFloatN = std::is_base_of_v<FloatNTag, T>;
46
47template <size_t N>
48class boolN;
49
50template <typename T, typename... Components>
52
53 static_assert((std::is_trivially_copyable_v<Components> && ...));
54
55 using first_type = typename ll::traits::max_type<Components...>::type;
56
57 using size_type = size_t;
58
59 [[nodiscard]] consteval static size_t size() noexcept { return sizeof...(Components); }
60
61 template <typename F>
62 static constexpr void forEachComponent(F&& func) noexcept {
63 meta::unrollType<Components...>(func);
64 }
65
66 [[nodiscard]] constexpr std::string toString() const noexcept {
67 std::string res("(");
68 forEachComponent([&]<typename axis_type, size_t iter> {
69 res = fmt::format("{}{}", res, static_cast<T const*>(this)->template get<axis_type, iter>());
70 res += ((iter < size() - 1) ? ", " : ")");
71 });
72 return res;
73 }
74
75 [[nodiscard]] constexpr bool operator==(T const& b) const noexcept {
76 bool res = true;
77 forEachComponent([&]<typename axis_type, size_t iter> {
78 res = res
79 && (b.template get<axis_type, iter>() == static_cast<T const*>(this)->template get<axis_type, iter>());
80 });
81 return res;
82 }
83
84 [[nodiscard]] constexpr bool operator!=(T const& b) const noexcept {
85 return !(static_cast<bool>((static_cast<T const*>(this))->operator==(b)));
86 }
87
88 [[nodiscard]] constexpr first_type& operator[](size_t index) noexcept
89 requires(traits::is_all_same_v<first_type, Components...>)
90 {
91 return ::ll::meta::visitIndex<size()>(index, [&]<size_t I>() -> first_type& {
92 return static_cast<T*>(this)->template get<first_type, I>();
93 });
94 }
95
96 [[nodiscard]] constexpr first_type const& operator[](size_t index) const noexcept
97 requires(traits::is_all_same_v<first_type, Components...>)
98 {
99 return ::ll::meta::visitIndex<size()>(index, [&]<size_t I>() -> first_type const& {
100 return static_cast<T*>(this)->template get<first_type, I>();
101 });
102 }
103
104 [[nodiscard]] constexpr size_t hash() const noexcept {
105 hash_utils::HashCombiner res{};
106 forEachComponent([&]<typename axis_type, size_t iter> {
107 if constexpr (has_hash<axis_type>::value) {
108 res.add(static_cast<T const*>(this)->template get<axis_type, iter>().hash());
109 } else {
110 res.add(std::hash<axis_type>()(static_cast<T const*>(this)->template get<axis_type, iter>()));
111 }
112 });
113 return res;
114 }
115
116 template <ll::concepts::IsVectorBase V>
117 [[nodiscard]] constexpr V as() const noexcept
118 requires(V::size() == size() && std::convertible_to<T, V>)
119 {
120 return static_cast<V>(*this);
121 }
122
123 [[nodiscard]] constexpr class boolN<sizeof...(Components)> eq(T const& b) const noexcept
124 requires(sizeof...(Components) >= 2 && sizeof...(Components) <= 4)
125 {
126 boolN<sizeof...(Components)> res = true;
127 forEachComponent([&]<typename axis_type, size_t iter> {
128 res[iter] =
129 (b.template get<axis_type, iter>() == static_cast<T const*>(this)->template get<axis_type, iter>());
130 });
131 return res;
132 }
133
134 [[nodiscard]] constexpr class boolN<sizeof...(Components)> ne(T const& b) const noexcept
135 requires(sizeof...(Components) >= 2 && sizeof...(Components) <= 4)
136 {
137 boolN<sizeof...(Components)> res = true;
138 forEachComponent([&]<typename axis_type, size_t iter> {
139 res[iter] =
140 (b.template get<axis_type, iter>() != static_cast<T const*>(this)->template get<axis_type, iter>());
141 });
142 return res;
143 }
144};
145} // namespace ll::math
146
147// NOLINTBEGIN
148
149namespace std {
150
151template <ll::concepts::IsVectorBase T, class CharT>
152struct formatter<T, CharT> : public std::formatter<basic_string_view<CharT>, CharT> {
153 template <class FormatContext>
154 auto format(T const& t, FormatContext& ctx) const noexcept {
155 return std::formatter<string_view>::format(t.toString(), ctx);
156 }
157};
158
159template <ll::concepts::IsVectorBase T>
160struct hash<T> {
161 constexpr size_t operator()(T const& vec) const noexcept { return vec.hash(); }
162};
163
164} // namespace std
165
166// fmt support
167template <ll::concepts::IsVectorBase T, class CharT>
168struct fmt::formatter<T, CharT> : fmt::formatter<std::basic_string_view<CharT>, CharT> {
169 template <class FormatContext>
170 auto format(T const& t, FormatContext& ctx) const {
171 return fmt::formatter<std::string_view>::format(t.toString(), ctx);
172 }
173};
174
175// NOLINTEND
Definition boolN.h:10
Definition VectorBase.h:35
Definition VectorBase.h:45
Definition VectorBase.h:40
STL namespace.
Definition ctx.h:5
Definition Concepts.h:71
Definition VectorBase.h:32
Definition VectorBase.h:42
Definition VectorBase.h:37
Definition VectorBase.h:51
Definition VectorBase.h:27
Definition VectorBase.h:21
Definition TypeTraits.h:27