Simple-Vector v1.3.0
Vector.hpp
Go to the documentation of this file.
1// Copyright Dominic Koepke 2021 - 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef SIMPLE_VECTOR_VECTOR_HPP
7#define SIMPLE_VECTOR_VECTOR_HPP
8
9#pragma once
10
11#include "Algorithm.hpp"
12#include "Concepts.hpp"
13#include "Functional.hpp"
14
15#include <algorithm>
16#include <array>
17#include <cassert>
18#include <cmath>
19#include <concepts>
20#include <execution>
21#include <ranges>
22
23namespace sl::vec
24{
34 template <value_type T, std::size_t VDimensions>
35 requires (0 < VDimensions)
36 class Vector
37 {
38 public:
42 constexpr static std::size_t dimensions{ VDimensions };
46 using value_type = std::remove_cvref_t<T>;
50 using storage_type = std::array<value_type, dimensions>;
51
56 constexpr Vector() noexcept = default;
60 constexpr ~Vector() noexcept = default;
64 constexpr Vector(const Vector&) noexcept = default;
68 constexpr Vector(Vector&&) noexcept = default;
69
77 template <class... TArgs>
78 requires (sizeof...(TArgs) == dimensions && (std::convertible_to<TArgs, T> && ...))
79 explicit (VDimensions <= 1)
80 constexpr Vector(TArgs&&...args) noexcept
81 : m_Values{ static_cast<T>(args)... }
82 {
83 }
84
95 template <std::convertible_to<value_type> T2, auto VOtherDimensions>
96 requires (!std::same_as<T2, value_type> || dimensions != VOtherDimensions)
97 constexpr explicit Vector(const Vector<T2, VOtherDimensions>& other)
98 {
100 (
101 std::ranges::take_view{ other, std::min(dimensions, VOtherDimensions) },
102 std::ranges::begin(m_Values),
103 fn::cast_invoke_result<value_type>(std::identity{})
104 );
105 }
106
118 template <std::invocable TGenerator>
119 requires std::convertible_to<std::invoke_result_t<TGenerator&>, value_type>
120 constexpr explicit Vector(TGenerator generator)
121 {
122 std::ranges::generate(m_Values, std::ref(generator));
123 }
124
129 constexpr Vector& operator =(const Vector&) noexcept = default;
134 constexpr Vector& operator =(Vector&&) noexcept = default;
135
142 [[nodiscard]]
143 constexpr bool operator ==(const Vector&) const noexcept = default;
144
152 [[nodiscard]]
153 constexpr const value_type& operator [](std::integral auto index) const noexcept
154 {
155 assert(std::in_range<std::size_t>(index) && "index must be in range of type std::size_t");
156 return m_Values[static_cast<std::size_t>(index)];
157 }
158
166 template <std::integral TIndex>
167 [[nodiscard]]
168 constexpr value_type& operator [](std::integral auto index) noexcept
169 {
170 assert(std::in_range<std::size_t>(index) && "index must be in range of type std::size_t");
171 return m_Values[static_cast<std::size_t>(index)];
172 }
173
178 [[nodiscard]]
179 constexpr const value_type& x() const noexcept
180 {
181 return m_Values[0];
182 }
183
188 [[nodiscard]]
189 constexpr value_type& x() noexcept
190 {
191 return m_Values[0];
192 }
193
200 [[nodiscard]]
201 constexpr const value_type& y() const noexcept
202 requires (1 < VDimensions)
203 {
204 return m_Values[1];
205 }
206
213 [[nodiscard]]
214 constexpr value_type& y() noexcept
215 requires (1 < VDimensions)
216 {
217 return m_Values[1];
218 }
219
226 [[nodiscard]]
227 constexpr const value_type& z() const noexcept
228 requires (2 < VDimensions)
229 {
230 return m_Values[2];
231 }
232
239 [[nodiscard]]
240 constexpr value_type& z() noexcept
241 requires (2 < VDimensions)
242 {
243 return m_Values[2];
244 }
245
252 template <std::convertible_to<value_type> T2>
253 constexpr Vector& operator +=(const Vector<T2, dimensions>& other)
254 {
256 (
257 m_Values,
258 other,
259 std::ranges::begin(m_Values),
260 fn::cast_invoke_result<value_type>(std::plus{})
261 );
262 return *this;
263 }
264
271 template <std::convertible_to<value_type> T2>
272 constexpr Vector& operator -=(const Vector<T2, dimensions>& other)
273 {
275 (
276 m_Values,
277 other,
278 std::ranges::begin(m_Values),
279 fn::cast_invoke_result<value_type>(std::minus{})
280 );
281 return *this;
282 }
283
290 template <std::convertible_to<value_type> T2>
291 constexpr Vector& operator +=(const T2& value)
292 {
294 (
295 m_Values,
296 std::ranges::begin(m_Values),
297 fn::cast_invoke_result<value_type>([&value](const auto& lhs) { return lhs + value; })
298 );
299 return *this;
300 }
301
308 template <std::convertible_to<value_type> T2>
309 constexpr Vector& operator -=(const T2& value)
310 {
312 (
313 m_Values,
314 std::ranges::begin(m_Values),
315 fn::cast_invoke_result<value_type>([&value](const auto& lhs) { return lhs - value; })
316 );
317 return *this;
318 }
319
326 template <std::convertible_to<value_type> T2>
327 constexpr Vector& operator *=(const T2& value)
328 {
330 (
331 m_Values,
332 std::ranges::begin(m_Values),
333 fn::cast_invoke_result<value_type>([&value](const auto& lhs) { return lhs * value; })
334 );
335 return *this;
336 }
337
346 template <std::convertible_to<value_type> T2>
347 constexpr Vector& operator /=(const T2& value)
348 {
349 assert(value != 0 && "division by 0 is undefined.");
350
352 (
353 m_Values,
354 std::ranges::begin(m_Values),
355 fn::cast_invoke_result<value_type>([&value](const auto& lhs) { return lhs / value; })
356 );
357 return *this;
358 }
359
368 template <std::convertible_to<value_type> T2>
369 requires modable<T>
370 constexpr Vector& operator %=(const T2& rawValue)
371 {
372 const auto value = static_cast<value_type>(rawValue);
373 assert(value != 0 && "division by 0 is undefined.");
374
376 (
377 m_Values,
378 std::ranges::begin(m_Values),
379 [value](const auto& lhs) { return lhs % value; }
380 );
381 return *this;
382 }
383
388 [[nodiscard]]
389 constexpr auto begin() noexcept { return std::ranges::begin(m_Values); }
390
395 [[nodiscard]]
396 constexpr auto begin() const noexcept { return std::ranges::begin(m_Values); }
397
402 [[nodiscard]]
403 constexpr auto cbegin() const noexcept { return std::ranges::cbegin(m_Values); }
404
409 [[nodiscard]]
410 constexpr auto end() noexcept { return std::ranges::end(m_Values); }
411
416 [[nodiscard]]
417 constexpr auto end() const noexcept { return std::ranges::end(m_Values); }
418
423 [[nodiscard]]
424 constexpr auto cend() const noexcept { return std::ranges::cend(m_Values); }
425
430 [[nodiscard]]
431 constexpr auto rbegin() noexcept { return std::ranges::rbegin(m_Values); }
432
437 [[nodiscard]]
438 constexpr auto rbegin() const noexcept { return std::ranges::rbegin(m_Values); }
439
444 [[nodiscard]]
445 constexpr auto crbegin() const noexcept { return std::ranges::crbegin(m_Values); }
446
451 [[nodiscard]]
452 constexpr auto rend() noexcept { return std::ranges::rend(m_Values); }
453
458 [[nodiscard]]
459 constexpr auto rend() const noexcept { return std::ranges::rend(m_Values); }
460
465 [[nodiscard]]
466 constexpr auto crend() const noexcept { return std::ranges::crend(m_Values); }
467
468 private:
469 storage_type m_Values{};
470 };
471
476 template <class... T>
477 Vector(T&&...) -> Vector<std::common_type_t<T...>, sizeof...(T)>;
478
490 template <value_type T, std::size_t VDimensions>
491 struct vector_traits<Vector<T, VDimensions>>
492 {
494
495 static constexpr std::size_t dimensions = Vector<T, VDimensions>::dimensions;
496 };
497
503 template <value_type T, auto VDimensions>
504 struct is_vectorial<Vector<T, VDimensions>> : std::true_type
505 {
506 };
507
522 template <vectorial TVector, add_assignable<TVector> T2>
523 [[nodiscard]]
524 constexpr TVector operator +(TVector lhs, T2&& rhs)
525 {
526 lhs += std::forward<T2>(rhs);
527 return lhs;
528 }
529
538 template <vectorial TVector, sub_assignable<TVector> T2>
539 [[nodiscard]]
540 constexpr TVector operator -(TVector lhs, T2&& rhs)
541 {
542 lhs -= std::forward<T2>(rhs);
543 return lhs;
544 }
545
554 template <vectorial TVector, mul_assignable<TVector> T2>
555 [[nodiscard]]
556 constexpr TVector operator *(TVector lhs, T2&& rhs)
557 {
558 lhs *= std::forward<T2>(rhs);
559 return lhs;
560 }
561
570 template <vectorial TVector, mul_assignable<TVector> T2>
571 [[nodiscard]]
572 constexpr TVector operator *(T2&& lhs, TVector rhs)
573 {
574 rhs *= std::forward<T2>(lhs);
575 return rhs;
576 }
577
586 template <vectorial TVector, div_assignable<TVector> T2>
587 [[nodiscard]]
588 constexpr TVector operator /(TVector lhs, T2&& rhs)
589 {
590 lhs /= std::forward<T2>(rhs);
591 return lhs;
592 }
593
602 template <vectorial TVector, mod_assignable<TVector> T2>
603 [[nodiscard]]
604 constexpr TVector operator %(TVector lhs, T2&& rhs)
605 {
606 lhs %= std::forward<T2>(rhs);
607 return lhs;
608 }
609
618 template <vectorial TVector1, vectorial TVector2>
619 requires mulable<vector_value_t<TVector2>, vector_value_t<TVector1>>
620 [[nodiscard]]
621 constexpr vector_value_t<TVector1> dot_product(const TVector1& lhs, const TVector2& rhs)
622 {
623 using T = vector_value_t<TVector1>;
625 (
626 lhs,
627 rhs,
628 T{},
629 std::plus{},
630 fn::cast_invoke_result<T>(std::multiplies{})
631 );
632 }
633
640 template <vectorial TVector>
641 [[nodiscard]]
642 constexpr vector_value_t<TVector> length_squared(const TVector& vector)
643 {
644 return dot_product(vector, vector);
645 }
646
655 template <vectorial TVector>
656 [[nodiscard]]
657 constexpr auto length(const TVector& vector) { return std::sqrt(length_squared(vector)); }
658
665 template <vectorial TVector>
666 requires std::floating_point<vector_value_t<TVector>>
667 [[nodiscard]]
668 constexpr TVector normalized(TVector vec)
669 {
670 assert(vec != TVector{});
671
672 return vec /= length(vec);
673 }
674
682 template <vectorial TVector>
683 [[nodiscard]]
684 constexpr TVector projected(const TVector& vector, TVector target)
685 {
686 assert(vector != TVector{} && "vector must not be the null vector.");
687 assert(target != TVector{} && "target must not be the null vector.");
688
689 const auto dot = dot_product(vector, target);
690 const auto targetLengthSq = length_squared(target);
691 target *= (dot / targetLengthSq);
692 return target;
693 }
694
706 template <vectorial TVector, class T>
707 requires std::is_arithmetic_v<T>
708 [[nodiscard]]
709 constexpr TVector lerp(TVector vector1, const TVector& vector2, T t)
710 {
712 (
713 vector1,
714 vector2,
715 std::ranges::begin(vector1),
716 fn::cast_invoke_result<vector_value_t<TVector>>([t](auto a, auto b) { return std::lerp(a, b, t); })
717 );
718 return vector1;
719 }
720
727 template <vectorial TVector>
728 requires std::floating_point<vector_value_t<TVector>>
729 [[nodiscard]]
730 constexpr TVector inversed(TVector vector)
731 {
733 (
734 vector,
735 std::ranges::begin(vector),
736 [](auto value) { return 1. / value; }
737 );
738 return vector;
739 }
740
742}
743
744#endif
A mathematically vector implementation.
Definition: Vector.hpp:37
constexpr value_type & z() noexcept
Accesses the third element.
Definition: Vector.hpp:240
constexpr value_type & x() noexcept
Accesses the first element.
Definition: Vector.hpp:189
constexpr auto begin() const noexcept
Returns an const iterator to the first element.
Definition: Vector.hpp:396
constexpr auto rend() const noexcept
Returns an const iterator to the reverse-end of the given range (i.e. the element before the first el...
Definition: Vector.hpp:459
constexpr auto begin() noexcept
Returns an iterator to the first element.
Definition: Vector.hpp:389
constexpr auto rbegin() noexcept
Returns an iterator to the reverse-beginning.
Definition: Vector.hpp:431
std::array< value_type, dimensions > storage_type
Used storage type.
Definition: Vector.hpp:50
constexpr const value_type & z() const noexcept
Accesses the third element.
Definition: Vector.hpp:227
std::remove_cvref_t< T > value_type
Alias for T, but without modifiers.
Definition: Vector.hpp:46
constexpr Vector() noexcept=default
Default constructor.
constexpr const value_type & y() const noexcept
Accesses the second element.
Definition: Vector.hpp:201
constexpr auto rbegin() const noexcept
Returns an const iterator to the reverse-beginning.
Definition: Vector.hpp:438
constexpr const value_type & x() const noexcept
Accesses the first element.
Definition: Vector.hpp:179
VDimensions<=1) constexpr Vector(TArgs &&...args) noexcept :m_Values{ static_cast< T >(args)... } { } template< std::convertible_to< value_type > T2, auto VOtherDimensions > requires(!std::same_as< T2, value_type >||dimensions !=VOtherDimensions) constexpr explicit Vector(const Vector< T2, VOtherDimensions > &other) { transform_unseq(std::ranges::take_view{ other, std::min(dimensions, VOtherDimensions) }, std::ranges::begin(m_Values), fn::cast_invoke_result< value_type >(std::identity{}));} template< std::invocable TGenerator > constexpr Vector(TGenerator generator)
Aggregate initialization like constructor.
Definition: Vector.hpp:120
constexpr auto cbegin() const noexcept
Returns an const iterator to the first element.
Definition: Vector.hpp:403
constexpr auto end() noexcept
Returns an iterator to the end (i.e. the element after the last element).
Definition: Vector.hpp:410
constexpr auto rend() noexcept
Returns an iterator to the reverse-end of the given range (i.e. the element before the first element)...
Definition: Vector.hpp:452
constexpr auto cend() const noexcept
Returns an const iterator to the end (i.e. the element after the last element).
Definition: Vector.hpp:424
constexpr auto crend() const noexcept
Returns an const iterator to the reverse-end of the given range (i.e. the element before the first el...
Definition: Vector.hpp:466
constexpr auto end() const noexcept
Returns an const iterator to the end (i.e. the element after the last element).
Definition: Vector.hpp:417
constexpr auto crbegin() const noexcept
Returns an const iterator to the reverse-beginning.
Definition: Vector.hpp:445
constexpr value_type & y() noexcept
Accesses the second element.
Definition: Vector.hpp:214
Checks if the given type can be used in immutable module operations.
Definition: Concepts.hpp:135
Checks if the given type is regular and can be used in common arithmetically operations.
Definition: Concepts.hpp:162
constexpr void transform_unseq(TRange &&range, TOut result, TUnaryOp unaryOp)
Applies the given unary operation to each element and writes into result.
Definition: Algorithm.hpp:52
constexpr T transform_reduce_unseq(TRange &&range, T init, TBinaryOp binaryOp, TUnaryOp unaryOp)
Applies the unaryOp to each elements from the range and reduces the results (possibly permuted and ag...
Definition: Algorithm.hpp:169
constexpr auto cast_invoke_result(TFunc func) noexcept
Factory function creating a wrapper function object, which invokes the provided function object and c...
Definition: Functional.hpp:47
typename vector_traits< std::remove_cvref_t< T > >::value_type vector_value_t
Convenience alias type to the value_type of Vectors.
Definition: Concepts.hpp:188
constexpr vector_value_t< TVector > length_squared(const TVector &vector)
Calculates the squared length of a Vector.
Definition: Vector.hpp:642
constexpr TVector operator-(TVector lhs, T2 &&rhs)
Minus operator.
Definition: Vector.hpp:540
constexpr TVector normalized(TVector vec)
Calculates the normalization of a Vector.
Definition: Vector.hpp:668
constexpr TVector lerp(TVector vector1, const TVector &vector2, T t)
Computes the linear interpolation between both vectors for the parameter t (or extrapolation,...
Definition: Vector.hpp:709
constexpr auto length(const TVector &vector)
Calculates the length of a Vector.
Definition: Vector.hpp:657
constexpr TVector operator%(TVector lhs, T2 &&rhs)
Modulo operator.
Definition: Vector.hpp:604
constexpr vector_value_t< TVector1 > dot_product(const TVector1 &lhs, const TVector2 &rhs)
Calculates the dot product of to Vectors.
Definition: Vector.hpp:621
Vector(T &&...) -> Vector< std::common_type_t< T... >, sizeof...(T)>
Vector deduction guide to make aggregate-like construction easier.
constexpr TVector operator/(TVector lhs, T2 &&rhs)
Division operator.
Definition: Vector.hpp:588
constexpr TVector projected(const TVector &vector, TVector target)
Projects vector onto the target Vector.
Definition: Vector.hpp:684
constexpr TVector operator*(TVector lhs, T2 &&rhs)
Multiplication operator.
Definition: Vector.hpp:556
constexpr TVector inversed(TVector vector)
Computes the inverse of the vector (1./v[0], 1./v[1], ...).
Definition: Vector.hpp:730
constexpr TVector operator+(TVector lhs, T2 &&rhs)
Sum operator.
Definition: Vector.hpp:524
Definition: Algorithm.hpp:19
Checks whether T is a vector type.
Definition: Concepts.hpp:203
Uniform interface to Vector types.
Definition: Concepts.hpp:180