vector.hpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  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. private:
  199. // Coordinate raw[Dimensions];
  200. array raw;
  201. template<typename Vector, size_t n>
  202. constexpr void set_mixed_index(Vector&) const
  203. {}
  204. template<typename Vector, size_t n>
  205. constexpr void set_mixed_index(Vector&, const Coordinate&) const
  206. {}
  207. template<typename Vector, size_t n, size_t index, size_t... Rest>
  208. constexpr void set_mixed_index(Vector& vec) const
  209. {
  210. static_assert(index < dimensions, " Invalid mix index. ");
  211. vec[n] = raw[index];
  212. set_mixed_index<Vector, n+1, Rest...>(vec);
  213. }
  214. template<typename Vector, size_t n, size_t index, size_t... Rest,
  215. std::enable_if_t<index < Dimensions>* = nullptr>
  216. constexpr void set_mixed_index(Vector& vec, const Coordinate& default_value) const
  217. {
  218. vec[n] = raw[index];
  219. set_mixed_index<Vector, n+1, Rest...>(vec, default_value);
  220. }
  221. template<typename Vector, size_t n, size_t index, size_t... Rest,
  222. std::enable_if_t<index >= Dimensions>* = nullptr>
  223. constexpr void set_mixed_index(Vector& vec, const Coordinate& default_value) const
  224. {
  225. vec[n] = default_value;
  226. set_mixed_index<Vector, n+1, Rest...>(vec, default_value);
  227. }
  228. template <typename Another, std::enable_if_t<
  229. Another::dimensions == Dimensions
  230. && !std::is_same<Another, vector>::value
  231. && !std::is_base_of<vector, Another>::value
  232. && std::is_convertible<typename Another::coordinate_type, Coordinate>::value
  233. && std::is_constructible<Coordinate, typename Another::coordinate_type>::value
  234. >* = nullptr>
  235. struct is_implicitly_convertible_to_me {};
  236. template <typename Another, std::enable_if_t<
  237. Another::dimensions == Dimensions
  238. && !std::is_same<Another, vector>::value
  239. && !std::is_base_of<vector, Another>::value
  240. && !std::is_convertible<typename Another::coordinate_type, Coordinate>::value
  241. // TODO: this does not cover aggregates and enums
  242. && std::is_constructible<Coordinate, typename Another::coordinate_type>::value
  243. >* = nullptr>
  244. struct is_explicitly_convertible_to_me {};
  245. template <typename Another, size_t dimension = Dimensions - 1>
  246. constexpr void set_in_order(const Another& another)
  247. {
  248. if constexpr (dimension > 0)
  249. set_in_order<Another, dimension - 1>(another);
  250. get<dimension>() = another.template get<dimension>();
  251. }
  252. public:
  253. constexpr vector() = default;
  254. template <typename... Coordinates,
  255. typename std::enable_if_t<sizeof...(Coordinates) == Dimensions> * = nullptr,
  256. typename std::enable_if_t<(std::is_convertible_v<Coordinates, Coordinate> && ...)> * = nullptr>
  257. constexpr vector(Coordinates&&... coordinates)
  258. : raw {std::forward<Coordinates>(coordinates)...}
  259. {}
  260. // TODO: forwarding
  261. template <typename Another, is_explicitly_convertible_to_me<Another>* = nullptr,
  262. std::enable_if_t<std::is_same_v<typename Another::order, Order>> *...>
  263. constexpr explicit vector(const Another& another) : raw{}
  264. {
  265. for(size_t i = 0; i < Dimensions; ++i)
  266. raw[i] = Coordinate(another[i]);
  267. }
  268. // TODO: forwarding
  269. template <typename Another, is_explicitly_convertible_to_me<Another>* = nullptr,
  270. std::enable_if_t<!std::is_same_v<typename Another::order, Order>> *...>
  271. constexpr explicit vector(const Another& another) : raw{}
  272. {
  273. set_in_order<Another>(another);
  274. }
  275. // TODO: forwarding
  276. template <typename Another, is_implicitly_convertible_to_me<Another>* = nullptr,
  277. std::enable_if_t<std::is_same_v<typename Another::order, Order>> *...>
  278. constexpr vector(const Another& another) : raw{}
  279. {
  280. for(size_t i = 0; i < Dimensions; ++i)
  281. raw[i] = another[i];
  282. }
  283. // TODO: forwarding
  284. template <typename Another, is_implicitly_convertible_to_me<Another>* = nullptr,
  285. std::enable_if_t<!std::is_same_v<typename Another::order, Order>> *...>
  286. constexpr vector(const Another& another) : raw{}
  287. {
  288. set_in_order<Another>(another);
  289. }
  290. explicit constexpr vector(const array & coordinates) : raw(coordinates)
  291. {
  292. }
  293. explicit constexpr vector(array && coordinates) : raw(std::move(coordinates))
  294. {
  295. }
  296. [[nodiscard]]
  297. explicit constexpr operator const array () const noexcept
  298. {
  299. return raw;
  300. }
  301. template<size_t D = Dimensions, std::enable_if_t<D == 1>* = nullptr>
  302. [[nodiscard]]
  303. constexpr operator const Coordinate & () const noexcept
  304. {
  305. return raw[0];
  306. }
  307. template <typename Function, typename AnotherCoord = std::invoke_result_t<Function, Coordinate>>
  308. [[nodiscard]]
  309. constexpr vector<AnotherCoord, Dimensions, Order> transformed(Function&& transform) const&
  310. {
  311. vector<AnotherCoord, Dimensions, Order> another{};
  312. for(size_t i = 0; i < Dimensions; ++i)
  313. {
  314. another[i] = support::invoke(
  315. std::forward<Function>(transform),
  316. (*this)[i]
  317. );
  318. }
  319. return another;
  320. }
  321. // TODO: mix should preserve order if mixed size >= original size
  322. template<size_t... CoordinateIndices, typename Mixed = vector<Coordinate, sizeof...(CoordinateIndices)> >
  323. [[nodiscard]]
  324. constexpr Mixed mix() const
  325. {
  326. Mixed result{};
  327. set_mixed_index<Mixed, 0, CoordinateIndices...>(result);
  328. return result;
  329. }
  330. template<size_t... CoordinateIndices, typename Mixed = vector<Coordinate, sizeof...(CoordinateIndices)> >
  331. [[nodiscard]]
  332. constexpr Mixed mix(const Coordinate& default_value) const
  333. {
  334. Mixed result{};
  335. set_mixed_index<Mixed, 0, CoordinateIndices...>(result, default_value);
  336. return result;
  337. }
  338. template <size_t N, typename Mixed = vector<Coordinate, N>>
  339. [[nodiscard]]
  340. constexpr Mixed mix(const support::array<size_t,N>& indices) const
  341. {
  342. Mixed result{};
  343. size_t index{};
  344. for(size_t i = 0; i < N; ++i)
  345. {
  346. index = indices[i];
  347. if(index >= Dimensions)
  348. throw std::logic_error("simple::geom::vector invalid mix index");
  349. result[i] = raw[index];
  350. }
  351. return result;
  352. }
  353. template <size_t N, typename Mixed = vector<Coordinate, N>>
  354. [[nodiscard]]
  355. constexpr Mixed mix(const support::array<size_t,N>& indices, const Coordinate& default_value) const
  356. {
  357. Mixed result{};
  358. size_t index{};
  359. for(size_t i = 0; i < N; ++i)
  360. {
  361. index = indices[i];
  362. result[i] = index < Dimensions ? raw[index] : default_value;
  363. }
  364. return result;
  365. }
  366. template <size_t N,
  367. std::enable_if_t<N <= Dimensions>* = nullptr>
  368. [[nodiscard]]
  369. constexpr vector<Coordinate,N> last() const
  370. {
  371. vector<Coordinate,N> result{};
  372. for(size_t i = 0; i < N; ++i)
  373. result[i] = (*this)[Dimensions-N+i];
  374. return result;
  375. }
  376. template <size_t N,
  377. std::enable_if_t<N <= Dimensions>* = nullptr>
  378. [[nodiscard]]
  379. constexpr vector<Coordinate,N> first() const
  380. {
  381. vector<Coordinate,N> result{};
  382. for(size_t i = 0; i < N; ++i)
  383. result[i] = (*this)[i];
  384. return result;
  385. }
  386. template <size_t N, typename O>
  387. [[nodiscard]] constexpr
  388. auto concat(vector<Coordinate, N, O> other) const
  389. {
  390. vector<Coordinate,Dimensions + N, support::meta::concat_sequence_t<
  391. Order, support::meta::offset_sequence_t<O, Dimensions> >>
  392. result{};
  393. for(size_t i = 0; i < Dimensions; ++i)
  394. result[i] = (*this)[i];
  395. for(size_t i = 0; i < N; ++i)
  396. result[Dimensions + i] = other[i];
  397. return result;
  398. }
  399. // NOTE: emmm... ok??
  400. // 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,
  401. // as that logicaly behaves similar to bitwise not on flags
  402. // what? you prefer it promoting to int? a freakin signed int?! gtfo!
  403. template <typename C = Coordinate, std::enable_if_t<std::is_same_v<C,bool>>* = nullptr>
  404. [[nodiscard]]
  405. friend
  406. constexpr vector operator ~(vector one) noexcept
  407. {
  408. for(size_t i = 0; i < Dimensions; ++i)
  409. one[i] = !one[i];
  410. return one;
  411. }
  412. // 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.
  413. // not sure why I have this, other than the consistency with other elementwise operations,
  414. // maybe it was different at some point, but right now removing this breaks nothing but a couple targeted unit tests.
  415. // note that comparison ops return a reduction type, not vector<bool,D>,
  416. // and nothing promotes to bool or anything like that, so this shouldn't bite you unless you ask for it
  417. template <typename C = typename meta::coordinate_type,
  418. std::enable_if_t<std::is_same_v<C,bool>>* = nullptr>
  419. [[nodiscard]] [[deprecated("use operator~ instead")]]
  420. friend
  421. constexpr vector operator !(vector one) noexcept
  422. {
  423. for(size_t i = 0; i < Dimensions; ++i)
  424. one[i] = !one[i];
  425. return one;
  426. }
  427. template <size_t dimension>
  428. [[nodiscard]]
  429. constexpr const coordinate_type & get() const&
  430. {
  431. static_assert(dimension < Dimensions);
  432. constexpr size_t index = support::car<Order, dimension>;
  433. return (*this)[index];
  434. }
  435. template <size_t dimension>
  436. [[nodiscard]]
  437. constexpr coordinate_type & get() &
  438. {
  439. static_assert(dimension < Dimensions);
  440. constexpr size_t index = support::car<Order, dimension>;
  441. return (*this)[index];
  442. }
  443. template <size_t dimension>
  444. [[nodiscard]]
  445. constexpr coordinate_type && get() &&
  446. {
  447. static_assert(dimension < Dimensions);
  448. constexpr size_t index = support::car<Order, dimension>;
  449. return std::move(*this)[index];
  450. }
  451. [[nodiscard]] constexpr const coordinate_type &
  452. operator[](size_t dimension) const&
  453. {
  454. assert(dimension < Dimensions);
  455. return raw[dimension];
  456. }
  457. [[nodiscard]] constexpr coordinate_type &
  458. operator[](size_t dimension) &
  459. {
  460. assert(dimension < Dimensions);
  461. return raw[dimension];
  462. }
  463. [[nodiscard]] constexpr coordinate_type &&
  464. operator[](size_t dimension) &&
  465. {
  466. assert(dimension < Dimensions);
  467. return std::move(raw[dimension]);
  468. }
  469. // TODO: not sure if it's ok that this is backwards
  470. // make sure to change meta::dimensions as well if change this
  471. // maybe make use of order parameter to decide
  472. // also definitely not ok that const and non const are so duplicated
  473. template <typename IndexType, size_t Size, typename O, size_t Depth = Size,
  474. std::enable_if_t<(Depth > 1)>* = nullptr>
  475. [[nodiscard]]
  476. constexpr auto & operator[](vector<IndexType,Size,O> index) &
  477. {
  478. return operator[](index[Depth - 1])
  479. .template operator[]<IndexType, Size, O, Depth-1>(index);
  480. }
  481. template <typename IndexType, size_t Size, typename O, size_t Depth,
  482. std::enable_if_t<Depth == 1>* = nullptr>
  483. [[nodiscard]]
  484. constexpr coordinate_type & operator[](vector<IndexType,Size,O> index) &
  485. {
  486. return operator[](index[0]);
  487. }
  488. template <typename IndexType, size_t Size, typename O, size_t Depth = Size,
  489. std::enable_if_t<(Depth > 1)>* = nullptr>
  490. [[nodiscard]]
  491. constexpr const auto & operator[](vector<IndexType,Size,O> index) const&
  492. {
  493. return raw[index[Depth - 1]]
  494. .template operator[]<IndexType, Size, O, Depth-1>(index);
  495. }
  496. template <typename IndexType, size_t Size, typename O, size_t Depth,
  497. std::enable_if_t<Depth == 1>* = nullptr>
  498. [[nodiscard]]
  499. constexpr const coordinate_type & operator[](vector<IndexType,Size,O> index) const&
  500. {
  501. return raw[index[0]];
  502. }
  503. [[nodiscard]] constexpr auto begin() noexcept { using std::begin; return begin(raw); }
  504. [[nodiscard]] constexpr auto end() noexcept { using std::end; return end(raw); }
  505. [[nodiscard]] constexpr auto begin() const noexcept { using std::cbegin; return cbegin(raw); }
  506. [[nodiscard]] constexpr auto end() const noexcept { using std::cend; return cend(raw); }
  507. [[nodiscard]] constexpr auto cbegin() const noexcept { using std::cbegin; return cbegin(raw); }
  508. [[nodiscard]] constexpr auto cend() const noexcept { using std::cend; return cend(raw); }
  509. [[nodiscard]] constexpr auto rbegin() noexcept { using std::rbegin; return rbegin(raw); }
  510. [[nodiscard]] constexpr auto rend() noexcept { using std::rend; return rend(raw); }
  511. [[nodiscard]] constexpr auto rbegin() const noexcept { using std::crbegin; return crbegin(raw); }
  512. [[nodiscard]] constexpr auto rend() const noexcept { using std::crend; return crend(raw); }
  513. [[nodiscard]] constexpr auto crbegin() const noexcept { using std::crbegin; return crbegin(raw); }
  514. [[nodiscard]] constexpr auto crend() const noexcept { using std::crend; return crend(raw); }
  515. constexpr vector& min(const vector& other)
  516. {
  517. using std::min;
  518. for(size_t i = 0; i < dimensions; ++i)
  519. raw[i] = min(raw[i], other[i]);
  520. return *this;
  521. }
  522. constexpr vector& max(const vector& other)
  523. {
  524. using std::max;
  525. for(size_t i = 0; i < dimensions; ++i)
  526. raw[i] = max(raw[i], other[i]);
  527. return *this;
  528. }
  529. constexpr vector& clamp(const vector& lo, const vector& hi)
  530. {
  531. using std::clamp;
  532. for(size_t i = 0; i < dimensions; ++i)
  533. raw[i] = clamp(raw[i], lo[i], hi[i]);
  534. return *this;
  535. }
  536. constexpr vector& floor()
  537. {
  538. using std::floor;
  539. for(auto&& coord : raw)
  540. coord = floor(coord);
  541. return *this;
  542. }
  543. constexpr vector& ceil()
  544. {
  545. using std::ceil;
  546. for(auto&& coord : raw)
  547. coord = ceil(coord);
  548. return *this;
  549. }
  550. constexpr vector& round()
  551. {
  552. using std::round;
  553. for(auto&& coord : raw)
  554. coord = round(coord);
  555. return *this;
  556. }
  557. constexpr vector& trunc()
  558. {
  559. using std::trunc;
  560. for(auto&& coord : raw)
  561. coord = trunc(coord);
  562. return *this;
  563. }
  564. constexpr vector& abs()
  565. {
  566. using support::abs;
  567. for(auto&& coord : raw)
  568. coord = abs(coord);
  569. return *this;
  570. }
  571. constexpr vector& signum()
  572. {
  573. using support::abs;
  574. for(auto&& coord : raw)
  575. coord = !(coord != Coordinate{}) ? Coordinate{} : coord/abs(coord);
  576. return *this;
  577. };
  578. [[nodiscard]]
  579. constexpr Coordinate magnitude() const
  580. {
  581. Coordinate result = Coordinate{};
  582. for(auto&& coord : raw)
  583. result += coord * coord;
  584. return result;
  585. }
  586. [[nodiscard]]
  587. constexpr Coordinate quadrance() const
  588. {
  589. return magnitude();
  590. }
  591. [[nodiscard]]
  592. constexpr Coordinate length() const
  593. {
  594. using std::sqrt;
  595. return sqrt(magnitude());
  596. }
  597. // TODO: concider return type deduction for these as well -_-
  598. constexpr vector & operator++()
  599. {
  600. for(auto& coord : raw) ++coord;
  601. return *this;
  602. }
  603. constexpr vector & operator--()
  604. {
  605. for(auto& coord : raw) --coord;
  606. return *this;
  607. }
  608. [[nodiscard]]
  609. constexpr vector operator++(int) &
  610. {
  611. vector temp{};
  612. for(size_t i = 0; i < Dimensions; ++i)
  613. temp.raw[i] = raw[i]++;
  614. return temp;
  615. }
  616. [[nodiscard]]
  617. constexpr vector operator--(int) &
  618. {
  619. vector temp{};
  620. for(size_t i = 0; i < Dimensions; ++i)
  621. temp.raw[i] = raw[i]--;
  622. return temp;
  623. }
  624. template <typename T, typename = std::nullptr_t>
  625. struct can_apply_s { constexpr static bool value = false; };
  626. template <typename T>
  627. struct can_apply_s<T, decltype(void(std::declval<vector>()(std::declval<T>())), nullptr)> { constexpr static bool value = true; };
  628. template <typename T>
  629. constexpr static bool can_apply = can_apply_s<T>::value;
  630. // TODO: common declval code between this and can_apply
  631. template <typename T, typename = std::nullptr_t>
  632. struct product_result_s { using type = Coordinate; };
  633. template <typename T>
  634. struct product_result_s<T, decltype(void(std::declval<vector>()(std::declval<T>())), nullptr)> { using type = decltype(std::declval<vector>()(std::declval<T>())); };
  635. template <typename T>
  636. using product_result = typename product_result_s<T>::type;
  637. // TODO: gotta deduce return coordinate type now that we're doing it -_-
  638. // matrix multiplication and matrix-vector multiplication/dot product fusion mutant operator
  639. template<typename AnotherComponent, size_t AnotherDimesnions, typename AnotherOrder,
  640. std::enable_if_t<std::is_same_v<Order,AnotherOrder> || can_apply<AnotherComponent>>* = nullptr,
  641. typename Return = std::conditional_t<can_apply<AnotherComponent>,
  642. vector<product_result<AnotherComponent>, AnotherDimesnions, AnotherOrder>,
  643. Coordinate
  644. >
  645. >
  646. [[nodiscard]]
  647. constexpr Return operator()(const vector<AnotherComponent, AnotherDimesnions, AnotherOrder> & another) const
  648. {
  649. Return ret{};
  650. for(size_t i = 0; i < AnotherDimesnions; ++i)
  651. if constexpr (can_apply<AnotherComponent>)
  652. ret[i] = (*this)(another[i]);
  653. else
  654. ret += (*this)[i] * another[i];
  655. return ret;
  656. }
  657. [[nodiscard]]
  658. constexpr Coordinate& x()
  659. {
  660. static_assert( Dimensions > x_index );
  661. return raw[x_index];
  662. }
  663. [[nodiscard]]
  664. constexpr const Coordinate& x() const
  665. {
  666. static_assert( Dimensions > x_index );
  667. return raw[x_index];
  668. }
  669. [[nodiscard]]
  670. constexpr Coordinate& y()
  671. {
  672. static_assert( Dimensions > y_index );
  673. return raw[y_index];
  674. }
  675. [[nodiscard]]
  676. constexpr const Coordinate& y() const
  677. {
  678. static_assert( Dimensions > y_index );
  679. return raw[y_index];
  680. }
  681. [[nodiscard]]
  682. constexpr Coordinate& z()
  683. {
  684. static_assert( Dimensions > z_index );
  685. return raw[z_index];
  686. }
  687. [[nodiscard]]
  688. constexpr const Coordinate& z() const
  689. {
  690. static_assert( Dimensions > z_index );
  691. return raw[z_index];
  692. }
  693. [[nodiscard]]
  694. constexpr Coordinate& w()
  695. {
  696. static_assert( Dimensions > w_index );
  697. return raw[w_index];
  698. }
  699. [[nodiscard]]
  700. constexpr const Coordinate& w() const
  701. {
  702. static_assert( Dimensions > w_index );
  703. return raw[w_index];
  704. }
  705. [[nodiscard]]
  706. constexpr vector<Coordinate,2> xy() const
  707. {
  708. return mix<x_index, y_index>();
  709. }
  710. [[nodiscard]]
  711. constexpr vector<Coordinate,3> xyz() const
  712. {
  713. return mix<x_index, y_index, z_index>();
  714. }
  715. [[nodiscard]]
  716. constexpr vector<Coordinate,3> xyz(const Coordinate& default_value) const
  717. {
  718. return mix<x_index, y_index, z_index>(default_value);
  719. }
  720. };
  721. template <typename C, size_t D, typename O>
  722. [[nodiscard]]
  723. constexpr
  724. vector<C,D,O> min(const vector<C,D,O> & one, const vector<C,D,O> & other)
  725. {
  726. auto result = one;
  727. return result.min(other);
  728. }
  729. template <typename C, size_t D, typename O>
  730. [[nodiscard]]
  731. constexpr
  732. vector<C,D,O> max(const vector<C,D,O> & one, const vector<C,D,O> & other)
  733. {
  734. auto result = one;
  735. return result.max(other);
  736. }
  737. // TODO: the in place guys dodged the bullet, but these guys below should deduce result element type...
  738. // TODO: lo and hi can have different element types
  739. template <typename C, size_t D, typename O>
  740. [[nodiscard]]
  741. constexpr
  742. vector<C,D,O> clamp(vector<C,D,O> v, const vector<C,D,O> & lo, const vector<C,D,O> & hi)
  743. {
  744. v.clamp(lo, hi);
  745. return v;
  746. }
  747. template <typename C, size_t D, typename O>
  748. [[nodiscard]]
  749. constexpr
  750. vector<C,D,O> floor(vector<C,D,O> v)
  751. {
  752. v.floor();
  753. return v;
  754. }
  755. template <typename C, size_t D, typename O>
  756. [[nodiscard]]
  757. constexpr
  758. vector<C,D,O> ceil(vector<C,D,O> v)
  759. {
  760. v.ceil();
  761. return v;
  762. }
  763. template <typename C, size_t D, typename O>
  764. [[nodiscard]]
  765. constexpr
  766. vector<C,D,O> round(vector<C,D,O> v)
  767. {
  768. v.round();
  769. return v;
  770. }
  771. template <typename C, size_t D, typename O>
  772. [[nodiscard]]
  773. constexpr
  774. vector<C,D,O> trunc(vector<C,D,O> v)
  775. {
  776. v.trunc();
  777. return v;
  778. }
  779. template <typename C, size_t D, typename O>
  780. [[nodiscard]]
  781. constexpr
  782. auto abs(const vector<C,D,O>& v)
  783. {
  784. return v.transformed([](auto&& x){ using support::abs; return abs(x); });
  785. }
  786. template <typename C, size_t D, typename O>
  787. [[nodiscard]]
  788. constexpr
  789. C magnitude(const vector<C,D,O>& v)
  790. {
  791. return v.magnitude();
  792. }
  793. template <typename C, size_t D, typename O>
  794. [[nodiscard]]
  795. constexpr
  796. C quadrance(const vector<C,D,O>& v)
  797. {
  798. return v.quadrance();
  799. }
  800. template <typename C, size_t D, typename O>
  801. [[nodiscard]]
  802. constexpr
  803. C length(const vector<C,D,O>& v)
  804. {
  805. return v.length();
  806. }
  807. template <typename C, size_t D, typename O>
  808. [[nodiscard]]
  809. constexpr
  810. auto signum(vector<C,D,O> v)
  811. {
  812. v.signum();
  813. return v;
  814. }
  815. template <typename It, size_t Size, typename O,
  816. std::enable_if_t<support::is_iterable<It>{}>* = nullptr>
  817. auto operator*(vector<It, Size, O> v)
  818. {
  819. return support::transform([](auto&& x) -> decltype(auto) {return *x;}, v);
  820. }
  821. // for ADL to find these
  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. using ::operator>>=;
  843. template<typename Coordinate, size_t Dimensions, typename Order>
  844. std::ostream & operator<<(std::ostream & out, const vector<Coordinate, Dimensions, Order> & vector)
  845. {
  846. out << '(';
  847. constexpr size_t last = Dimensions - 1;
  848. for(size_t i = 0; i < last; ++i)
  849. out << vector[i] << ", ";
  850. out << vector[last] << ')';
  851. return out;
  852. }
  853. template<typename Coordinate, size_t N, size_t M, typename O1, typename O2>
  854. std::ostream & operator<<(std::ostream & out, const vector<vector<Coordinate, N, O1>, M, O2> & vector)
  855. {
  856. for(size_t i = 0; i < N; ++i)
  857. out << "^";
  858. out << "\n";
  859. for(size_t i = 0; i < M; ++i)
  860. out << vector[i] << "\n";
  861. for(size_t i = 0; i < N; ++i)
  862. out << "v";
  863. out << "\n";
  864. return out;
  865. }
  866. template <typename F, typename... R> vector(F firts, R... rest)
  867. -> vector<F, sizeof...(R) + 1>;
  868. // TODO: ugh, clang
  869. // https://bugs.llvm.org/show_bug.cgi?id=42757
  870. // very annoying in many different places :/
  871. template <typename C, size_t D, typename O, void* SFINAE> vector(vector<C,D,O,SFINAE>)
  872. -> vector<vector<C,D,O,SFINAE>,1>;
  873. template <typename>
  874. struct is_vector_instance : public std::false_type {};
  875. template <typename C, size_t D, typename O>
  876. struct is_vector_instance<vector<C,D,O>> : public std::true_type {};
  877. template <typename V>
  878. constexpr auto is_vector_instance_v = is_vector_instance<V>::value;
  879. template <size_t I, typename V,
  880. std::enable_if_t<is_vector_instance_v<std::decay_t<V>>>* = nullptr>
  881. constexpr decltype(auto) get(V&& v)
  882. { return std::forward<V>(v).template get<I>(); }
  883. // implementing this and similar things as part of vector class crashes clang
  884. // see meta class above
  885. template<typename Vector>
  886. struct vector_traits
  887. {
  888. using vector = Vector;
  889. using meta = typename vector::meta;
  890. template <typename Indices> struct size_of_depths {};
  891. template <size_t... I> struct size_of_depths<std::index_sequence<I...>>
  892. {
  893. using type = std::index_sequence<meta::template dimensions<>[I]...>;
  894. };
  895. using shape = typename size_of_depths<std::make_index_sequence<meta::depth()>>::type;
  896. };
  897. } // namespace simple::geom
  898. namespace simple
  899. {
  900. template<typename C, size_t D, typename O>
  901. struct support::define_array_operators<geom::vector<C,D,O>> :
  902. public support::trivial_array_accessor<geom::vector<C,D,O>, geom::vector<C,D,O>::dimensions>
  903. {
  904. template <typename V>
  905. constexpr static bool has_scalar_shape = std::is_same_v<
  906. typename geom::vector_traits<V>::shape,
  907. std::index_sequence<1>
  908. >;
  909. constexpr static auto enabled_operators = array_operator::all;
  910. constexpr static auto enabled_right_element_operators = array_operator::binary | array_operator::in_place;
  911. constexpr static auto enabled_left_element_operators = []()
  912. {
  913. // workaround for a bug in gcc
  914. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101004
  915. if constexpr (has_scalar_shape<geom::vector<C,D,O>>)
  916. return array_operator::binary | array_operator::in_place;
  917. else
  918. return array_operator::binary
  919. ^ array_operator::lshift
  920. ^ array_operator::rshift;
  921. }();
  922. // demote a 1D vector when mingling with scalars
  923. template <typename T, bool Element>
  924. using result_shape = std::conditional_t<
  925. Element && has_scalar_shape<geom::vector<T,D,O>>,
  926. T, geom::vector<T,D,O>
  927. >;
  928. template <typename Deduced, array_operator op, typename Other, bool Element>
  929. using result = result_shape
  930. <
  931. // prevent bool promotion for bitwise ops.
  932. // cause it dun make no sense, mr std! and we's actually's ave sum
  933. // use for ese in dis ere multidimensional world of ours...
  934. std::conditional_t
  935. <
  936. std::is_same_v<C,bool> &&
  937. std::is_same_v<Other,bool> &&
  938. (op && array_operator::bitwise),
  939. bool, Deduced
  940. >,
  941. Element
  942. >;
  943. // initially went with geom::vector_traits<geom::vector<C,D,O>>::shape
  944. // but then couldn't add a column vector Nx1 to a matrix NxM, so ended up with this,
  945. // it's a bit arbitrary though, doesn't have a name, feels fragile
  946. using compatibility_tag = std::tuple<O,
  947. std::index_sequence<D, geom::vector<C,D,O>::meta::depth()>
  948. >;
  949. };
  950. } // namespace simple
  951. template<typename T, size_t C, typename O>
  952. class std::numeric_limits<simple::geom::vector<T,C,O>>
  953. {
  954. using vec = simple::geom::vector<T,C,O>;
  955. using limits = std::numeric_limits<T>;
  956. public:
  957. constexpr static bool is_specialized = limits::is_specialized;
  958. [[nodiscard]]
  959. constexpr static vec min()
  960. {
  961. static_assert(limits::is_specialized);
  962. vec m{};
  963. for(auto&& c : m)
  964. c = limits::min();
  965. return m;
  966. }
  967. [[nodiscard]]
  968. constexpr static vec lowest()
  969. {
  970. static_assert(limits::is_specialized);
  971. vec m{};
  972. for(auto&& c : m)
  973. c = limits::lowest();
  974. return m;
  975. }
  976. [[nodiscard]]
  977. constexpr static vec max()
  978. {
  979. static_assert(limits::is_specialized);
  980. vec m{};
  981. for(auto&& c : m)
  982. c = limits::max();
  983. return m;
  984. }
  985. };
  986. template <typename C, size_t D, typename O>
  987. struct std::tuple_size<simple::geom::vector<C,D,O>> :
  988. std::integral_constant<size_t, D> {};
  989. template <size_t I, typename C, size_t D, typename O>
  990. struct std::tuple_element<I, simple::geom::vector<C,D,O>>
  991. {
  992. using type = C;
  993. };
  994. #endif /* end of include guard */