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 size_t res = 0;
106 forEachComponent([&]<typename axis_type, size_t iter> {
107 if constexpr (has_hash<axis_type>::value) {
108 hash_utils::hashCombine(static_cast<T const*>(this)->template get<axis_type, iter>().hash(), res);
109 } else {
110 hash_utils::hashCombine(
111 std::hash<axis_type>()(static_cast<T const*>(this)->template get<axis_type, iter>()),
112 res
113 );
114 }
115 });
116 return res;
117 }
118
119 template <ll::concepts::IsVectorBase V>
120 [[nodiscard]] constexpr V as() const noexcept
121 requires(V::size() == size() && std::convertible_to<T, V>)
122 {
123 return static_cast<V>(*this);
124 }
125
126 [[nodiscard]] constexpr class boolN<sizeof...(Components)> eq(T const& b) const noexcept
127 requires(sizeof...(Components) >= 2 && sizeof...(Components) <= 4)
128 {
129 boolN<sizeof...(Components)> res = true;
130 forEachComponent([&]<typename axis_type, size_t iter> {
131 res[iter] =
132 (b.template get<axis_type, iter>() == static_cast<T const*>(this)->template get<axis_type, iter>());
133 });
134 return res;
135 }
136
137 [[nodiscard]] constexpr class boolN<sizeof...(Components)> ne(T const& b) const noexcept
138 requires(sizeof...(Components) >= 2 && sizeof...(Components) <= 4)
139 {
140 boolN<sizeof...(Components)> res = true;
141 forEachComponent([&]<typename axis_type, size_t iter> {
142 res[iter] =
143 (b.template get<axis_type, iter>() != static_cast<T const*>(this)->template get<axis_type, iter>());
144 });
145 return res;
146 }
147};
148} // namespace ll::math
149
150// NOLINTBEGIN
151
152namespace std {
153
154template <ll::concepts::IsVectorBase T, class CharT>
155struct formatter<T, CharT> : public std::formatter<basic_string_view<CharT>, CharT> {
156 template <class FormatContext>
157 auto format(T const& t, FormatContext& ctx) const noexcept {
158 return std::formatter<string_view>::format(t.toString(), ctx);
159 }
160};
161
162template <ll::concepts::IsVectorBase T>
163struct hash<T> {
164 constexpr size_t operator()(T const& vec) const noexcept { return vec.hash(); }
165};
166
167} // namespace std
168
169// fmt support
170template <ll::concepts::IsVectorBase T, class CharT>
171struct fmt::formatter<T, CharT> : fmt::formatter<std::basic_string_view<CharT>, CharT> {
172 template <class FormatContext>
173 auto format(T const& t, FormatContext& ctx) const {
174 return fmt::formatter<std::string_view>::format(t.toString(), ctx);
175 }
176};
177
178// 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