From 02f195b8d4014bb44f7da725eae9f2dc36ce1791 Mon Sep 17 00:00:00 2001
From: namark <namark@disroot.org>
Date: Wed, 29 Jan 2020 02:55:41 +0400
Subject: [PATCH] first<N>, last<N> and better mutant_clone,

also deprecated mutantClone... anyone use it? probably not, but still...
deprecated!
---
 source/simple/geom/vector.hpp | 38 ++++++++++++++++++++++++++++++++---
 unit_tests/point.cpp          |  7 ++++---
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/source/simple/geom/vector.hpp b/source/simple/geom/vector.hpp
index 50306c5..1049d2b 100644
--- a/source/simple/geom/vector.hpp
+++ b/source/simple/geom/vector.hpp
@@ -174,6 +174,7 @@ namespace simple::geom
 			: raw {std::forward<Coordinates>(coordinates)...}
 		{}
 
+		// TODO: constexpr and forwarding
 		template <typename Another, is_convertible_to_me<Another>* = nullptr,
 		std::enable_if_t<std::is_same_v<typename Another::order, Order>> *...>
 		explicit vector(const Another& another)
@@ -181,6 +182,7 @@ namespace simple::geom
 			std::copy(another.begin(), another.end(), begin());
 		}
 
+		// TODO: forwarding
 		template <typename Another, is_convertible_to_me<Another>* = nullptr,
 		std::enable_if_t<!std::is_same_v<typename Another::order, Order>> *...>
 		constexpr explicit vector(const Another& another) : raw{}
@@ -210,7 +212,7 @@ namespace simple::geom
 		}
 
 		template <typename Another>
-		[[nodiscard]]
+		[[nodiscard]] [[deprecated("use mutant_clone instead")]]
 		constexpr Another mutantClone(typename Another::coordinate_type(*method)(const vector::coordinate_type&)) const&
 		{
 			static_assert(Another::dimensions == Dimensions, " Dimension mismatch. ");
@@ -221,13 +223,21 @@ namespace simple::geom
 
 		template <typename Function, typename AnotherCoord = std::invoke_result_t<Function, Coordinate>>
 		[[nodiscard]]
-		constexpr vector<AnotherCoord, Dimensions> mutant_clone(const Function& transform) const&
+		constexpr vector<AnotherCoord, Dimensions, Order> mutant_clone(Function&& transform) const&
 		{
 			vector<AnotherCoord, Dimensions> another{};
-			std::transform(begin(), end(), another.begin(), transform);
+			for(size_t i = 0; i < Dimensions; ++i)
+			{
+				// std::invoke is not constexpr -_-
+				another[i] = std::apply(
+					std::forward<Function>(transform),
+					std::forward_as_tuple((*this)[i])
+				);
+			}
 			return another;
 		}
 
+		// TODO: mix should preserve order if mixed size >= original size
 		template<size_t... CoordinateIndices, typename Mixed = vector<Coordinate, sizeof...(CoordinateIndices)> >
 		[[nodiscard]]
 		constexpr Mixed mix() const
@@ -276,6 +286,28 @@ namespace simple::geom
 			return result;
 		}
 
+		template <size_t N,
+			 std::enable_if_t<N <= Dimensions>* = nullptr>
+		[[nodiscard]]
+		constexpr vector<Coordinate,N> last() const
+		{
+			vector<Coordinate,N> result{};
+			for(size_t i = 0; i < N; ++i)
+				result[i] = (*this)[Dimensions-N+i];
+			return result;
+		}
+
+		template <size_t N,
+			 std::enable_if_t<N <= Dimensions>* = nullptr>
+		[[nodiscard]]
+		constexpr vector<Coordinate,N> first() const
+		{
+			vector<Coordinate,N> result{};
+			for(size_t i = 0; i < N; ++i)
+				result[i] = (*this)[i];
+			return result;
+		}
+
 		template <typename C = Coordinate, size_t D = Dimensions,
 			 std::enable_if_t<std::is_same_v<C,bool> && (D != 1)>* = nullptr>
 		[[nodiscard]]
diff --git a/unit_tests/point.cpp b/unit_tests/point.cpp
index 130f9c5..7f07e72 100644
--- a/unit_tests/point.cpp
+++ b/unit_tests/point.cpp
@@ -87,10 +87,8 @@ void Mutation()
 	float4 p {1.3f, 1.5f, 2.1f, 4.6f};
 	int4 p2 {1, 2, 2, 5};
 	int4 p3 {1, 1, 2, 4};
-	assert( p2 == p.mutantClone<int4>( [](auto x) -> int { return std::round(x); } ));
-	assert( p3 == p.mutantClone<int4>( [](auto x) -> int { return x; } ));
 	assert( p2 == p.mutant_clone( [](auto x) -> int { return std::round(x); } ));
-	assert( p3 == p.mutant_clone( [](auto x) -> int { return x; } ));
+	assert( p3 == p.mutant_clone( [](auto x) { return int(x); } ));
 }
 
 void Mixing()
@@ -104,6 +102,9 @@ void Mixing()
 	assert( (geom::vector<int, 6>{3,3,3,2,2,1} == p.mix<6>({2,2,2,1,1,0})) );
 	assert( (geom::vector<int, 3>{1,2,0} == p.mix<0,1,4>(0)) );
 	assert( (geom::vector<int, 3>{1,2,0} == p.mix<3>({0,1,4}, 0)) );
+
+	assert( (vector(1,2) == p.first<2>()) );
+	assert( (vector(2,3,4) == p.last<3>()) );
 }
 
 void MultidimensionalElementAccess()
-- 
GitLab