vector.hpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141
  1. // TODO: this file is getting huge, need to break it up somehow
  2. #ifndef SIMPLE_GEOM_VECTOR_HPP
  3. #define SIMPLE_GEOM_VECTOR_HPP
  4. #include <algorithm>
  5. #include <type_traits>
  6. #include <ostream>
  7. #include <numeric>
  8. #include <tuple>
  9. #include <cassert>
  10. #include "simple/support/carcdr.hpp"
  11. #include "simple/support/array.hpp"
  12. #include "simple/support/array_utils.hpp"
  13. #include "simple/support/array_operators.hpp"
  14. #include "simple/support/function_utils.hpp"
  15. #include "simple/support/meta/integer_sequence.hpp"
  16. #include "simple/support/tuple_utils/transform.hpp"
  17. #include "simple/support/algorithm/traits.hpp"
  18. #include "simple/support/math/abs.hpp"
  19. namespace simple::geom
  20. {
  21. template <typename Type, size_t Size>
  22. struct vector_array
  23. {
  24. using type = support::array<Type, Size>;
  25. };
  26. template <typename Type, size_t Size>
  27. using vector_array_t = typename vector_array<Type, Size>::type;
  28. // TODO; in an optional header
  29. // template <size_t Size>
  30. // struct vector_array<unsigned int, Size>
  31. // {
  32. // using value_type = unsigned int;
  33. // typedef value_type type __attribute__ ((vector_size (Size * sizeof(value_type))));
  34. // };
  35. //
  36. // template <size_t Size>
  37. // struct vector_array<int, Size>
  38. // {
  39. // using value_type = int;
  40. // typedef value_type type __attribute__ ((vector_size (Size * sizeof(value_type))));
  41. // };
  42. template <typename Coordinate, size_t Dimensions,
  43. typename Order = std::make_index_sequence<Dimensions>,
  44. std::enable_if_t<Order::size() == Dimensions>* = nullptr>
  45. class vector
  46. {
  47. public:
  48. using array = vector_array_t<Coordinate, Dimensions>;
  49. using coordinate_type = Coordinate;
  50. using order = Order;
  51. using value_type = Coordinate;
  52. static constexpr size_t dimensions = Dimensions;
  53. class meta
  54. {
  55. template <typename T, typename = std::nullptr_t>
  56. struct has_dimesntions_s { constexpr static bool value = false; };
  57. template <typename T>
  58. struct has_dimesntions_s<T, decltype(void(T::dimensions), nullptr)> { constexpr static bool value = true; };
  59. template <typename T>
  60. constexpr static bool has_dimesntions = has_dimesntions_s<T>::value;
  61. public:
  62. template <typename C = coordinate_type,
  63. std::enable_if_t<has_dimesntions<C>>* = nullptr>
  64. constexpr static size_t depth()
  65. {
  66. return depth<typename C::coordinate_type>() + 1;
  67. }
  68. template <typename C = coordinate_type,
  69. std::enable_if_t<not has_dimesntions<C>>* = nullptr>
  70. constexpr static size_t depth()
  71. {
  72. return 1;
  73. }
  74. private:
  75. template <size_t DepthIndex = depth(), typename Vector = vector>
  76. static constexpr size_t get_sub_dimentions()
  77. {
  78. static_assert( DepthIndex < depth(), "Invalid depth" );
  79. if constexpr (DepthIndex == 0)
  80. return Vector::dimensions;
  81. else return get_sub_dimentions<DepthIndex-1, typename Vector::coordinate_type>();
  82. }
  83. template <typename O, typename SizeType = size_t, size_t DepthIndex = 0, size_t Depth = depth()>
  84. static constexpr void set_sub_dimentions(vector<SizeType,Depth,O>& out)
  85. {
  86. out[Depth - 1 - DepthIndex] = get_sub_dimentions<DepthIndex>();
  87. if constexpr (DepthIndex+1 < Depth)
  88. set_sub_dimentions<O,SizeType,DepthIndex+1>(out);
  89. }
  90. template <typename SizeType = size_t, size_t Depth = depth()>
  91. static constexpr auto get_dimensions()
  92. {
  93. vector<SizeType,Depth> ret{};
  94. set_sub_dimentions(ret);
  95. return ret;
  96. }
  97. public:
  98. template <typename SizeType = size_t, size_t Depth = meta::depth()> // have to explicitly qualify for depth gcc-7
  99. static constexpr vector<SizeType,Depth> dimensions = get_dimensions<SizeType,Depth>();
  100. // this little convenience crashes all clangs currently supporting c++17 (5,6,7,8,9,10)
  101. // update: clang 11.1.0 - complains about duplicate member "dimensions", previous declared on the same line -_-
  102. // seems like it's caused by the recursion of vector::meta::size::meta::size::meta::size... which are all vector<size_t,1>s,
  103. // but gcc is ok with it, and why wouldn't it be??
  104. // static constexpr auto size = dimensions<>;
  105. // unused typename to work around gcc bug
  106. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282
  107. template <typename, size_t Depth = depth(), typename Enabled = void>
  108. struct get_coordinate;
  109. template <typename U>
  110. struct get_coordinate<U, 1, void>
  111. { using type = vector::coordinate_type; };
  112. template <typename U, size_t Depth>
  113. struct get_coordinate<U, Depth, std::enable_if_t<(Depth > 1)>>
  114. { using type = typename vector::coordinate_type::meta:: template get_coordinate<U, Depth -1>::type; };
  115. using coordinate_type = typename get_coordinate<void, depth()>::type;
  116. // ffs this crashes clang 11.1.0 on bool_algebra operator* -_-
  117. // template <typename Indices> struct size_of_depths {};
  118. // template <size_t... I> struct size_of_depths<std::index_sequence<I...>>
  119. // {
  120. // using type = std::index_sequence<meta::dimensions<>[I]...>;
  121. // };
  122. };
  123. // template <typename Indices = std::make_index_sequence<meta::depth()>>
  124. // using shape = typename meta::template size_of_depths<Indices>::type;
  125. template <typename NewCoord, typename Meta = meta, typename Enabled = void>
  126. struct map_coordinate;
  127. template <typename NewCoord, typename Meta>
  128. struct map_coordinate<NewCoord, Meta, std::enable_if_t<Meta::depth() <= 1>>
  129. { using type = vector<NewCoord, dimensions, order>; };
  130. template <typename NewCoord, typename Meta>
  131. struct map_coordinate<NewCoord, Meta, std::enable_if_t<(Meta::depth() > 1)>>
  132. { using type =
  133. vector<typename Coordinate::template map_coordinate<NewCoord>::type, dimensions, order>; };
  134. template <typename NewCoord>
  135. using map_coordinate_t = typename map_coordinate<NewCoord>::type;
  136. [[nodiscard]]
  137. static constexpr vector zero() { return vector{}; }
  138. [[nodiscard]]
  139. static constexpr vector one() { return vector{support::filled_array<Dimensions>(value_type{1})}; }
  140. [[nodiscard]]
  141. static constexpr vector one(const Coordinate& scaler) { return vector{support::filled_array<Dimensions>(scaler)}; }
  142. enum : size_t
  143. {
  144. non_index = std::numeric_limits<size_t>::max(),
  145. new_index = non_index,
  146. x_index = support::car<Order, 0, non_index>,
  147. y_index = support::car<Order, 1, non_index>,
  148. z_index = support::car<Order, 2, non_index>,
  149. w_index = support::car<Order, 3, non_index>
  150. };
  151. template <size_t index>
  152. [[nodiscard]]
  153. static constexpr vector unit()
  154. {
  155. return unit<index>(Coordinate{1});
  156. }
  157. template <size_t index>
  158. [[nodiscard]]
  159. static constexpr vector unit(const Coordinate& one)
  160. {
  161. return unit<index>(one, Coordinate{});
  162. }
  163. template <size_t index>
  164. [[nodiscard]]
  165. static constexpr vector unit(const Coordinate& one, const Coordinate& zero)
  166. {
  167. static_assert(index < dimensions, "");
  168. return vector{support::make_array<dimensions>([one, zero](size_t i)
  169. { return index == i ? one : zero; } )};
  170. }
  171. [[nodiscard]]
  172. static constexpr vector unit(size_t index)
  173. {
  174. return unit(index, Coordinate{1});
  175. }
  176. [[nodiscard]]
  177. static constexpr vector unit(size_t index, const Coordinate& one)
  178. {
  179. vector ret{};
  180. ret[index] = one;
  181. return ret;
  182. }
  183. [[nodiscard]]
  184. static constexpr vector unit(size_t index, const Coordinate& one, const Coordinate& zero)
  185. {
  186. vector ret = vector::one(zero);
  187. ret[index] = one;
  188. return ret;
  189. }
  190. [[nodiscard]] static constexpr vector i() { return unit<x_index>(); }
  191. [[nodiscard]] static constexpr vector j() { return unit<y_index>(); }
  192. [[nodiscard]] static constexpr vector k() { return unit<z_index>(); }
  193. [[nodiscard]] static constexpr vector l() { return unit<w_index>(); }
  194. [[nodiscard]] static constexpr vector i(const Coordinate& scaler) { return unit<x_index>(scaler); }
  195. [[nodiscard]] static constexpr vector j(const Coordinate& scaler) { return unit<y_index>(scaler); }
  196. [[nodiscard]] static constexpr vector k(const Coordinate& scaler) { return unit<z_index>(scaler); }
  197. [[nodiscard]] static constexpr vector l(const Coordinate& scaler) { return unit<w_index>(scaler); }
  198. array raw; // no real reason to keep this private, and now we are structural yay
  199. private:
  200. template<typename Vector, size_t n>
  201. constexpr void set_mixed_index(Vector&) const
  202. {}
  203. template<typename Vector, size_t n>
  204. constexpr void set_mixed_index(Vector&, const Coordinate&) const
  205. {}
  206. template<typename Vector, size_t n, size_t index, size_t... Rest>
  207. constexpr void set_mixed_index(Vector& vec) const
  208. {
  209. static_assert(index < dimensions, " Invalid mix index. ");
  210. vec[n] = raw[index];
  211. set_mixed_index<Vector, n+1, Rest...>(vec);
  212. }
  213. template<typename Vector, size_t n, size_t index, size_t... Rest,
  214. std::enable_if_t<index < Dimensions>* = nullptr>
  215. constexpr void set_mixed_index(Vector& vec, const Coordinate& default_value) const
  216. {
  217. vec[n] = raw[index];
  218. set_mixed_index<Vector, n+1, Rest...>(vec, default_value);
  219. }
  220. template<typename Vector, size_t n, size_t index, size_t... Rest,
  221. std::enable_if_t<index >= Dimensions>* = nullptr>
  222. constexpr void set_mixed_index(Vector& vec, const Coordinate& default_value) const
  223. {
  224. vec[n] = default_value;
  225. set_mixed_index<Vector, n+1, Rest...>(vec, default_value);
  226. }
  227. template <typename Another, std::enable_if_t<
  228. Another::dimensions == Dimensions
  229. && !std::is_same<Another, vector>::value
  230. && !std::is_base_of<vector, Another>::value
  231. && std::is_convertible<typename Another::coordinate_type, Coordinate>::value
  232. && std::is_constructible<Coordinate, typename Another::coordinate_type>::value
  233. >* = nullptr>
  234. struct is_implicitly_convertible_to_me {};
  235. template <typename Another, std::enable_if_t<
  236. Another::dimensions == Dimensions
  237. && !std::is_same<Another, vector>::value
  238. && !std::is_base_of<vector, Another>::value
  239. && !std::is_convertible<typename Another::coordinate_type, Coordinate>::value
  240. // TODO: this does not cover aggregates and enums
  241. && std::is_constructible<Coordinate, typename Another::coordinate_type>::value
  242. >* = nullptr>
  243. struct is_explicitly_convertible_to_me {};
  244. template <typename Another, size_t dimension = Dimensions - 1>
  245. constexpr void set_in_order(const Another& another)
  246. {
  247. if constexpr (dimension > 0)
  248. set_in_order<Another, dimension - 1>(another);
  249. get<dimension>() = another.template get<dimension>();
  250. }
  251. public:
  252. constexpr vector() = default;
  253. template <typename... Coordinates,
  254. typename std::enable_if_t<sizeof...(Coordinates) == Dimensions> * = nullptr,
  255. typename std::enable_if_t<(std::is_convertible_v<Coordinates, Coordinate> && ...)> * = nullptr>
  256. constexpr vector(Coordinates&&... coordinates)
  257. : raw {std::forward<Coordinates>(coordinates)...}
  258. {}
  259. // TODO: forwarding
  260. template <typename Another, is_explicitly_convertible_to_me<Another>* = nullptr,
  261. std::enable_if_t<std::is_same_v<typename Another::order, Order>> *...>
  262. constexpr explicit vector(const Another& another) : raw{}
  263. {
  264. for(size_t i = 0; i < Dimensions; ++i)
  265. raw[i] = Coordinate(another[i]);
  266. }
  267. // TODO: forwarding
  268. template <typename Another, is_explicitly_convertible_to_me<Another>* = nullptr,
  269. std::enable_if_t<!std::is_same_v<typename Another::order, Order>> *...>
  270. constexpr explicit vector(const Another& another) : raw{}
  271. {
  272. set_in_order<Another>(another);
  273. }
  274. // TODO: forwarding
  275. template <typename Another, is_implicitly_convertible_to_me<Another>* = nullptr,
  276. std::enable_if_t<std::is_same_v<typename Another::order, Order>> *...>
  277. constexpr vector(const Another& another) : raw{}
  278. {
  279. for(size_t i = 0; i < Dimensions; ++i)
  280. raw[i] = another[i];
  281. }
  282. // TODO: forwarding
  283. template <typename Another, is_implicitly_convertible_to_me<Another>* = nullptr,
  284. std::enable_if_t<!std::is_same_v<typename Another::order, Order>> *...>
  285. constexpr vector(const Another& another) : raw{}
  286. {
  287. set_in_order<Another>(another);
  288. }
  289. explicit constexpr vector(const array & coordinates) : raw(coordinates)
  290. {
  291. }
  292. explicit constexpr vector(array && coordinates) : raw(std::move(coordinates))
  293. {
  294. }
  295. [[nodiscard]]
  296. explicit constexpr operator const array () const noexcept
  297. {
  298. return raw;
  299. }
  300. template<size_t D = Dimensions, std::enable_if_t<D == 1>* = nullptr>
  301. [[nodiscard]]
  302. constexpr operator const Coordinate & () const noexcept
  303. {
  304. return raw[0];
  305. }
  306. template <typename Function, typename AnotherCoord = std::invoke_result_t<Function, Coordinate>>
  307. [[nodiscard]]
  308. constexpr vector<AnotherCoord, Dimensions, Order> transformed(Function&& transform) const&
  309. {
  310. vector<AnotherCoord, Dimensions, Order> another{};
  311. for(size_t i = 0; i < Dimensions; ++i)
  312. {
  313. another[i] = support::invoke(
  314. std::forward<Function>(transform),
  315. (*this)[i]
  316. );
  317. }
  318. return another;
  319. }
  320. // TODO: mix should preserve order if mixed size >= original size
  321. template<size_t... CoordinateIndices, typename Mixed = vector<Coordinate, sizeof...(CoordinateIndices)> >
  322. [[nodiscard]]
  323. constexpr Mixed mix() const
  324. {
  325. Mixed result{};
  326. set_mixed_index<Mixed, 0, CoordinateIndices...>(result);
  327. return result;
  328. }
  329. template<size_t... CoordinateIndices, typename Mixed = vector<Coordinate, sizeof...(CoordinateIndices)> >
  330. [[nodiscard]]
  331. constexpr Mixed mix(const Coordinate& default_value) const
  332. {
  333. Mixed result{};
  334. set_mixed_index<Mixed, 0, CoordinateIndices...>(result, default_value);
  335. return result;
  336. }
  337. template <size_t N, typename Mixed = vector<Coordinate, N>>
  338. [[nodiscard]]
  339. constexpr Mixed mix(const support::array<size_t,N>& indices) const
  340. {
  341. Mixed result{};
  342. size_t index{};
  343. for(size_t i = 0; i < N; ++i)
  344. {
  345. index = indices[i];
  346. if(index >= Dimensions)
  347. throw std::logic_error("simple::geom::vector invalid mix index");
  348. result[i] = raw[index];
  349. }
  350. return result;
  351. }
  352. template <size_t N, typename Mixed = vector<Coordinate, N>>
  353. [[nodiscard]]
  354. constexpr Mixed mix(const support::array<size_t,N>& indices, const Coordinate& default_value) const
  355. {
  356. Mixed result{};
  357. size_t index{};
  358. for(size_t i = 0; i < N; ++i)
  359. {
  360. index = indices[i];
  361. result[i] = index < Dimensions ? raw[index] : default_value;
  362. }
  363. return result;
  364. }
  365. template <size_t N,
  366. std::enable_if_t<N <= Dimensions>* = nullptr>
  367. [[nodiscard]]
  368. constexpr vector<Coordinate,N> last() const
  369. {
  370. vector<Coordinate,N> result{};
  371. for(size_t i = 0; i < N; ++i)
  372. result[i] = (*this)[Dimensions-N+i];
  373. return result;
  374. }
  375. template <size_t N,
  376. std::enable_if_t<N <= Dimensions>* = nullptr>
  377. [[nodiscard]]
  378. constexpr vector<Coordinate,N> first() const
  379. {
  380. vector<Coordinate,N> result{};
  381. for(size_t i = 0; i < N; ++i)
  382. result[i] = (*this)[i];
  383. return result;
  384. }
  385. template <size_t N, typename O>
  386. [[nodiscard]] constexpr
  387. auto concat(vector<Coordinate, N, O> other) const
  388. {
  389. vector<Coordinate,Dimensions + N, support::meta::concat_sequence_t<
  390. Order, support::meta::offset_sequence_t<O, Dimensions> >>
  391. result{};
  392. for(size_t i = 0; i < Dimensions; ++i)
  393. result[i] = (*this)[i];
  394. for(size_t i = 0; i < N; ++i)
  395. result[Dimensions + i] = other[i];
  396. return result;
  397. }
  398. // NOTE: emmm... ok??
  399. // emmm yes, this is ok, bitwise not on a bool is a warning anyways, so in context of vector we make it elementwise logical not,
  400. // as that logicaly behaves similar to bitwise not on flags
  401. // what? you prefer it promoting to int? a freakin signed int?! gtfo!
  402. template <typename C = Coordinate, std::enable_if_t<std::is_same_v<C,bool>>* = nullptr>
  403. [[nodiscard]]
  404. friend
  405. constexpr vector operator ~(vector one) noexcept
  406. {
  407. for(size_t i = 0; i < Dimensions; ++i)
  408. one[i] = !one[i];
  409. return one;
  410. }
  411. // now this is the one I would say is kind of dubious, because it creates an expectation of proper boolean logic, but it's not.
  412. // not sure why I have this, other than the consistency with other elementwise operations,
  413. // maybe it was different at some point, but right now removing this breaks nothing but a couple targeted unit tests.
  414. // note that comparison ops return a reduction type, not vector<bool,D>,
  415. // and nothing promotes to bool or anything like that, so this shouldn't bite you unless you ask for it
  416. template <typename C = typename meta::coordinate_type,
  417. std::enable_if_t<std::is_same_v<C,bool>>* = nullptr>
  418. [[nodiscard]] [[deprecated("use operator~ instead")]]
  419. friend
  420. constexpr vector operator !(vector one) noexcept
  421. {
  422. for(size_t i = 0; i < Dimensions; ++i)
  423. one[i] = !one[i];
  424. return one;
  425. }
  426. template <size_t dimension>
  427. [[nodiscard]]
  428. constexpr const coordinate_type & get() const&
  429. {
  430. static_assert(dimension < Dimensions);
  431. constexpr size_t index = support::car<Order, dimension>;
  432. return (*this)[index];
  433. }
  434. template <size_t dimension>
  435. [[nodiscard]]
  436. constexpr coordinate_type & get() &
  437. {
  438. static_assert(dimension < Dimensions);
  439. constexpr size_t index = support::car<Order, dimension>;
  440. return (*this)[index];
  441. }
  442. template <size_t dimension>
  443. [[nodiscard]]
  444. constexpr coordinate_type && get() &&
  445. {
  446. static_assert(dimension < Dimensions);
  447. constexpr size_t index = support::car<Order, dimension>;
  448. return std::move(*this)[index];
  449. }
  450. [[nodiscard]] constexpr const coordinate_type &
  451. operator[](size_t dimension) const&
  452. {
  453. assert(dimension < Dimensions);
  454. return raw[dimension];
  455. }
  456. [[nodiscard]] constexpr coordinate_type &
  457. operator[](size_t dimension) &
  458. {
  459. assert(dimension < Dimensions);
  460. return raw[dimension];
  461. }
  462. [[nodiscard]] constexpr coordinate_type &&
  463. operator[](size_t dimension) &&
  464. {
  465. assert(dimension < Dimensions);
  466. return std::move(raw[dimension]);
  467. }
  468. // TODO: not sure if it's ok that this is backwards
  469. // make sure to change meta::dimensions as well if change this
  470. // maybe make use of order parameter to decide
  471. // also definitely not ok that const and non const are so duplicated
  472. template <typename IndexType, size_t Size, typename O, size_t Depth = Size,
  473. std::enable_if_t<(Depth > 1)>* = nullptr>
  474. [[nodiscard]]
  475. constexpr auto & operator[](vector<IndexType,Size,O> index) &
  476. {
  477. return operator[](index[Depth - 1])
  478. .template operator[]<IndexType, Size, O, Depth-1>(index);
  479. }
  480. template <typename IndexType, size_t Size, typename O, size_t Depth,
  481. std::enable_if_t<Depth == 1>* = nullptr>
  482. [[nodiscard]]
  483. constexpr coordinate_type & operator[](vector<IndexType,Size,O> index) &
  484. {
  485. return operator[](index[0]);
  486. }
  487. template <typename IndexType, size_t Size, typename O, size_t Depth = Size,
  488. std::enable_if_t<(Depth > 1)>* = nullptr>
  489. [[nodiscard]]
  490. constexpr const auto & operator[](vector<IndexType,Size,O> index) const&
  491. {
  492. return raw[index[Depth - 1]]
  493. .template operator[]<IndexType, Size, O, Depth-1>(index);
  494. }
  495. template <typename IndexType, size_t Size, typename O, size_t Depth,
  496. std::enable_if_t<Depth == 1>* = nullptr>
  497. [[nodiscard]]
  498. constexpr const coordinate_type & operator[](vector<IndexType,Size,O> index) const&
  499. {
  500. return raw[index[0]];
  501. }
  502. [[nodiscard]] constexpr auto begin() noexcept { using std::begin; return begin(raw); }
  503. [[nodiscard]] constexpr auto end() noexcept { using std::end; return end(raw); }
  504. [[nodiscard]] constexpr auto begin() const noexcept { using std::cbegin; return cbegin(raw); }
  505. [[nodiscard]] constexpr auto end() const noexcept { using std::cend; return cend(raw); }
  506. [[nodiscard]] constexpr auto cbegin() const noexcept { using std::cbegin; return cbegin(raw); }
  507. [[nodiscard]] constexpr auto cend() const noexcept { using std::cend; return cend(raw); }
  508. [[nodiscard]] constexpr auto rbegin() noexcept { using std::rbegin; return rbegin(raw); }
  509. [[nodiscard]] constexpr auto rend() noexcept { using std::rend; return rend(raw); }
  510. [[nodiscard]] constexpr auto rbegin() const noexcept { using std::crbegin; return crbegin(raw); }
  511. [[nodiscard]] constexpr auto rend() const noexcept { using std::crend; return crend(raw); }
  512. [[nodiscard]] constexpr auto crbegin() const noexcept { using std::crbegin; return crbegin(raw); }
  513. [[nodiscard]] constexpr auto crend() const noexcept { using std::crend; return crend(raw); }
  514. constexpr vector& min(const vector& other)
  515. {
  516. using std::min;
  517. for(size_t i = 0; i < dimensions; ++i)
  518. raw[i] = min(raw[i], other[i]);
  519. return *this;
  520. }
  521. constexpr vector& max(const vector& other)
  522. {
  523. using std::max;
  524. for(size_t i = 0; i < dimensions; ++i)
  525. raw[i] = max(raw[i], other[i]);
  526. return *this;
  527. }
  528. constexpr vector& clamp(const vector& lo, const vector& hi)
  529. {
  530. using std::clamp;
  531. for(size_t i = 0; i < dimensions; ++i)
  532. raw[i] = clamp(raw[i], lo[i], hi[i]);
  533. return *this;
  534. }
  535. constexpr vector& floor()
  536. {
  537. using std::floor;
  538. for(auto&& coord : raw)
  539. coord = floor(coord);
  540. return *this;
  541. }
  542. constexpr vector& ceil()
  543. {
  544. using std::ceil;
  545. for(auto&& coord : raw)
  546. coord = ceil(coord);
  547. return *this;
  548. }
  549. constexpr vector& round()
  550. {
  551. using std::round;
  552. for(auto&& coord : raw)
  553. coord = round(coord);
  554. return *this;
  555. }
  556. constexpr vector& trunc()
  557. {
  558. using std::trunc;
  559. for(auto&& coord : raw)
  560. coord = trunc(coord);
  561. return *this;
  562. }
  563. constexpr vector& abs()
  564. {
  565. using support::abs;
  566. for(auto&& coord : raw)
  567. coord = abs(coord);
  568. return *this;
  569. }
  570. constexpr vector& signum()
  571. {
  572. using support::abs;
  573. for(auto&& coord : raw)
  574. coord = !(coord != Coordinate{}) ? Coordinate{} : coord/abs(coord);
  575. return *this;
  576. };
  577. [[nodiscard]]
  578. constexpr Coordinate magnitude() const
  579. {
  580. Coordinate result = Coordinate{};
  581. for(auto&& coord : raw)
  582. result += coord * coord;
  583. return result;
  584. }
  585. [[nodiscard]]
  586. constexpr Coordinate quadrance() const
  587. {
  588. return magnitude();
  589. }
  590. [[nodiscard]]
  591. constexpr Coordinate length() const
  592. {
  593. using std::sqrt;
  594. return sqrt(magnitude());
  595. }
  596. // TODO: concider return type deduction for these as well -_-
  597. constexpr vector & operator++()
  598. {
  599. for(auto& coord : raw) ++coord;
  600. return *this;
  601. }
  602. constexpr vector & operator--()
  603. {
  604. for(auto& coord : raw) --coord;
  605. return *this;
  606. }
  607. [[nodiscard]]
  608. constexpr vector operator++(int) &
  609. {
  610. vector temp{};
  611. for(size_t i = 0; i < Dimensions; ++i)
  612. temp.raw[i] = raw[i]++;
  613. return temp;
  614. }
  615. [[nodiscard]]
  616. constexpr vector operator--(int) &
  617. {
  618. vector temp{};
  619. for(size_t i = 0; i < Dimensions; ++i)
  620. temp.raw[i] = raw[i]--;
  621. return temp;
  622. }
  623. template <typename T, typename = std::nullptr_t>
  624. struct can_apply_s { constexpr static bool value = false; };
  625. template <typename T>
  626. struct can_apply_s<T, decltype(void(std::declval<vector>()(std::declval<T>())), nullptr)> { constexpr static bool value = true; };
  627. template <typename T>
  628. constexpr static bool can_apply = can_apply_s<T>::value;
  629. // TODO: common declval code between this and can_apply
  630. template <typename T, typename = std::nullptr_t>
  631. struct product_result_s { using type = Coordinate; };
  632. template <typename T>
  633. struct product_result_s<T, decltype(void(std::declval<vector>()(std::declval<T>())), nullptr)> { using type = decltype(std::declval<vector>()(std::declval<T>())); };
  634. template <typename T>
  635. using product_result = typename product_result_s<T>::type;
  636. // TODO: gotta deduce return coordinate type now that we're doing it -_-
  637. // matrix multiplication and matrix-vector multiplication/dot product fusion mutant operator
  638. template<typename AnotherComponent, size_t AnotherDimesnions, typename AnotherOrder,
  639. std::enable_if_t<std::is_same_v<Order,AnotherOrder> || can_apply<AnotherComponent>>* = nullptr,
  640. typename Return = std::conditional_t<can_apply<AnotherComponent>,
  641. vector<product_result<AnotherComponent>, AnotherDimesnions, AnotherOrder>,
  642. Coordinate
  643. >
  644. >
  645. [[nodiscard]]
  646. constexpr Return operator()(const vector<AnotherComponent, AnotherDimesnions, AnotherOrder> & another) const
  647. {
  648. Return ret{};
  649. for(size_t i = 0; i < AnotherDimesnions; ++i)
  650. if constexpr (can_apply<AnotherComponent>)
  651. ret[i] = (*this)(another[i]);
  652. else
  653. ret += (*this)[i] * another[i];
  654. return ret;
  655. }
  656. [[nodiscard]]
  657. constexpr Coordinate& x()
  658. {
  659. static_assert( Dimensions > x_index );
  660. return raw[x_index];
  661. }
  662. [[nodiscard]]
  663. constexpr const Coordinate& x() const
  664. {
  665. static_assert( Dimensions > x_index );
  666. return raw[x_index];
  667. }
  668. [[nodiscard]]
  669. constexpr Coordinate& y()
  670. {
  671. static_assert( Dimensions > y_index );
  672. return raw[y_index];
  673. }
  674. [[nodiscard]]
  675. constexpr const Coordinate& y() const
  676. {
  677. static_assert( Dimensions > y_index );
  678. return raw[y_index];
  679. }
  680. [[nodiscard]]
  681. constexpr Coordinate& z()
  682. {
  683. static_assert( Dimensions > z_index );
  684. return raw[z_index];
  685. }
  686. [[nodiscard]]
  687. constexpr const Coordinate& z() const
  688. {
  689. static_assert( Dimensions > z_index );
  690. return raw[z_index];
  691. }
  692. [[nodiscard]]
  693. constexpr Coordinate& w()
  694. {
  695. static_assert( Dimensions > w_index );
  696. return raw[w_index];
  697. }
  698. [[nodiscard]]
  699. constexpr const Coordinate& w() const
  700. {
  701. static_assert( Dimensions > w_index );
  702. return raw[w_index];
  703. }
  704. [[nodiscard]]
  705. constexpr vector<Coordinate,2> xy() const
  706. {
  707. return mix<x_index, y_index>();
  708. }
  709. [[nodiscard]]
  710. constexpr vector<Coordinate,3> xyz() const
  711. {
  712. return mix<x_index, y_index, z_index>();
  713. }
  714. [[nodiscard]]
  715. constexpr vector<Coordinate,3> xyz(const Coordinate& default_value) const
  716. {
  717. return mix<x_index, y_index, z_index>(default_value);
  718. }
  719. };
  720. template <typename C, size_t D, typename O>
  721. [[nodiscard]]
  722. constexpr
  723. vector<C,D,O> min(const vector<C,D,O> & one, const vector<C,D,O> & other)
  724. {
  725. auto result = one;
  726. return result.min(other);
  727. }
  728. template <typename C, size_t D, typename O>
  729. [[nodiscard]]
  730. constexpr
  731. vector<C,D,O> max(const vector<C,D,O> & one, const vector<C,D,O> & other)
  732. {
  733. auto result = one;
  734. return result.max(other);
  735. }
  736. // TODO: the in place guys dodged the bullet, but these guys below should deduce result element type...
  737. // TODO: lo and hi can have different element types
  738. template <typename C, size_t D, typename O>
  739. [[nodiscard]]
  740. constexpr
  741. vector<C,D,O> clamp(vector<C,D,O> v, const vector<C,D,O> & lo, const vector<C,D,O> & hi)
  742. {
  743. v.clamp(lo, hi);
  744. return v;
  745. }
  746. template <typename C, size_t D, typename O>
  747. [[nodiscard]]
  748. constexpr
  749. vector<C,D,O> floor(vector<C,D,O> v)
  750. {
  751. v.floor();
  752. return v;
  753. }
  754. template <typename C, size_t D, typename O>
  755. [[nodiscard]]
  756. constexpr
  757. vector<C,D,O> ceil(vector<C,D,O> v)
  758. {
  759. v.ceil();
  760. return v;
  761. }
  762. template <typename C, size_t D, typename O>
  763. [[nodiscard]]
  764. constexpr
  765. vector<C,D,O> round(vector<C,D,O> v)
  766. {
  767. v.round();
  768. return v;
  769. }
  770. template <typename C, size_t D, typename O>
  771. [[nodiscard]]
  772. constexpr
  773. vector<C,D,O> trunc(vector<C,D,O> v)
  774. {
  775. v.trunc();
  776. return v;
  777. }
  778. template <typename C, size_t D, typename O>
  779. [[nodiscard]]
  780. constexpr
  781. auto abs(const vector<C,D,O>& v)
  782. {
  783. return v.transformed([](auto&& x){ using support::abs; return abs(x); });
  784. }
  785. template <typename C, size_t D, typename O>
  786. [[nodiscard]]
  787. constexpr
  788. C magnitude(const vector<C,D,O>& v)
  789. {
  790. return v.magnitude();
  791. }
  792. template <typename C, size_t D, typename O>
  793. [[nodiscard]]
  794. constexpr
  795. C quadrance(const vector<C,D,O>& v)
  796. {
  797. return v.quadrance();
  798. }
  799. template <typename C, size_t D, typename O>
  800. [[nodiscard]]
  801. constexpr
  802. C length(const vector<C,D,O>& v)
  803. {
  804. return v.length();
  805. }
  806. template <typename C, size_t D, typename O>
  807. [[nodiscard]]
  808. constexpr
  809. auto signum(vector<C,D,O> v)
  810. {
  811. v.signum();
  812. return v;
  813. }
  814. template <typename It, size_t Size, typename O,
  815. std::enable_if_t<support::is_iterable<It>{}>* = nullptr>
  816. auto operator*(vector<It, Size, O> v)
  817. {
  818. return support::transform([](auto&& x) -> decltype(auto) {return *x;}, v);
  819. }
  820. // for ADL to find these
  821. using ::operator~;
  822. using ::operator+;
  823. using ::operator-;
  824. using ::operator*;
  825. using ::operator/;
  826. using ::operator%;
  827. using ::operator&;
  828. using ::operator|;
  829. using ::operator^;
  830. using ::operator<<;
  831. using ::operator>>;
  832. using ::operator+=;
  833. using ::operator-=;
  834. using ::operator*=;
  835. using ::operator/=;
  836. using ::operator%=;
  837. using ::operator&=;
  838. using ::operator|=;
  839. using ::operator^=;
  840. using ::operator<<=;
  841. using ::operator>>=;
  842. template<typename Coordinate, size_t Dimensions, typename Order>
  843. std::ostream & operator<<(std::ostream & out, const vector<Coordinate, Dimensions, Order> & vector)
  844. {
  845. out << '(';
  846. constexpr size_t last = Dimensions - 1;
  847. for(size_t i = 0; i < last; ++i)
  848. out << vector[i] << ", ";
  849. out << vector[last] << ')';
  850. return out;
  851. }
  852. template<typename Coordinate, size_t N, size_t M, typename O1, typename O2>
  853. std::ostream & operator<<(std::ostream & out, const vector<vector<Coordinate, N, O1>, M, O2> & vector)
  854. {
  855. for(size_t i = 0; i < N; ++i)
  856. out << "^";
  857. out << "\n";
  858. for(size_t i = 0; i < M; ++i)
  859. out << vector[i] << "\n";
  860. for(size_t i = 0; i < N; ++i)
  861. out << "v";
  862. out << "\n";
  863. return out;
  864. }
  865. template <typename F, typename... R> vector(F firts, R... rest)
  866. -> vector<F, sizeof...(R) + 1>;
  867. // TODO: ugh, clang
  868. // https://bugs.llvm.org/show_bug.cgi?id=42757
  869. // very annoying in many different places :/
  870. template <typename C, size_t D, typename O, void* SFINAE> vector(vector<C,D,O,SFINAE>)
  871. -> vector<vector<C,D,O,SFINAE>,1>;
  872. template <typename>
  873. struct is_vector_instance : public std::false_type {};
  874. template <typename C, size_t D, typename O>
  875. struct is_vector_instance<vector<C,D,O>> : public std::true_type {};
  876. template <typename V>
  877. constexpr auto is_vector_instance_v = is_vector_instance<V>::value;
  878. template <size_t I, typename V,
  879. std::enable_if_t<is_vector_instance_v<std::decay_t<V>>>* = nullptr>
  880. constexpr decltype(auto) get(V&& v)
  881. { return std::forward<V>(v).template get<I>(); }
  882. // implementing this and similar things as part of vector class crashes clang
  883. // see meta class above
  884. template<typename Vector>
  885. struct vector_traits
  886. {
  887. using vector = Vector;
  888. using meta = typename vector::meta;
  889. template <typename Indices> struct size_of_depths {};
  890. template <size_t... I> struct size_of_depths<std::index_sequence<I...>>
  891. {
  892. using type = std::index_sequence<meta::template dimensions<>[I]...>;
  893. };
  894. using shape = typename size_of_depths<std::make_index_sequence<meta::depth()>>::type;
  895. };
  896. } // namespace simple::geom
  897. namespace simple
  898. {
  899. template<typename C, size_t D, typename O>
  900. struct support::define_array_operators<geom::vector<C,D,O>> :
  901. public support::trivial_array_accessor<geom::vector<C,D,O>, geom::vector<C,D,O>::dimensions>
  902. {
  903. template <typename V>
  904. constexpr static bool has_scalar_shape = std::is_same_v<
  905. typename geom::vector_traits<V>::shape,
  906. std::index_sequence<1>
  907. >;
  908. constexpr static auto enabled_operators = array_operator::all;
  909. constexpr static auto enabled_right_element_operators = array_operator::binary | array_operator::in_place;
  910. constexpr static auto enabled_left_element_operators = []()
  911. {
  912. // workaround for a bug in gcc
  913. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101004
  914. if constexpr (has_scalar_shape<geom::vector<C,D,O>>)
  915. return array_operator::binary | array_operator::in_place;
  916. else
  917. return array_operator::binary
  918. ^ array_operator::lshift
  919. ^ array_operator::rshift;
  920. }();
  921. // demote a 1D vector when mingling with scalars
  922. template <typename T, bool Element>
  923. using result_shape = std::conditional_t<
  924. Element && has_scalar_shape<geom::vector<T,D,O>>,
  925. T, geom::vector<T,D,O>
  926. >;
  927. template <typename Deduced, array_operator op, typename Other, bool Element>
  928. using result = result_shape
  929. <
  930. // prevent bool promotion for bitwise ops.
  931. // cause it dun make no sense, mr std! and we's actually's ave sum
  932. // use for ese in dis ere multidimensional world of ours...
  933. std::conditional_t
  934. <
  935. std::is_same_v<C,bool> &&
  936. std::is_same_v<Other,bool> &&
  937. (op && array_operator::bitwise),
  938. bool, Deduced
  939. >,
  940. Element
  941. >;
  942. // initially went with geom::vector_traits<geom::vector<C,D,O>>::shape
  943. // but then couldn't add a column vector Nx1 to a matrix NxM, so ended up with this,
  944. // it's a bit arbitrary though, doesn't have a name, feels fragile
  945. using compatibility_tag = std::tuple<O,
  946. std::index_sequence<D, geom::vector<C,D,O>::meta::depth()>
  947. >;
  948. };
  949. } // namespace simple
  950. template<typename T, size_t C, typename O>
  951. class std::numeric_limits<simple::geom::vector<T,C,O>>
  952. {
  953. using vec = simple::geom::vector<T,C,O>;
  954. using limits = std::numeric_limits<T>;
  955. public:
  956. constexpr static bool is_specialized = limits::is_specialized;
  957. [[nodiscard]]
  958. constexpr static vec min()
  959. {
  960. static_assert(limits::is_specialized);
  961. vec m{};
  962. for(auto&& c : m)
  963. c = limits::min();
  964. return m;
  965. }
  966. [[nodiscard]]
  967. constexpr static vec lowest()
  968. {
  969. static_assert(limits::is_specialized);
  970. vec m{};
  971. for(auto&& c : m)
  972. c = limits::lowest();
  973. return m;
  974. }
  975. [[nodiscard]]
  976. constexpr static vec max()
  977. {
  978. static_assert(limits::is_specialized);
  979. vec m{};
  980. for(auto&& c : m)
  981. c = limits::max();
  982. return m;
  983. }
  984. };
  985. template <typename C, size_t D, typename O>
  986. struct std::tuple_size<simple::geom::vector<C,D,O>> :
  987. std::integral_constant<size_t, D> {};
  988. template <size_t I, typename C, size_t D, typename O>
  989. struct std::tuple_element<I, simple::geom::vector<C,D,O>>
  990. {
  991. using type = C;
  992. };
  993. #endif /* end of include guard */