From e1800140dbfcdf44ef74e3bf1c5c78ff18c8f951 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Fri, 14 Jun 2019 08:41:52 +0200
Subject: [PATCH] add and use constexpr_switch

---
 .../src/common/AbstractionHelpers.hpp         | 23 +++++-------
 alib2std/src/extensions/utility.hpp           | 16 ++++++++
 alib2std/test-src/extensions/UtilityTest.cpp  | 37 +++++++++++++++++++
 3 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/alib2abstraction/src/common/AbstractionHelpers.hpp b/alib2abstraction/src/common/AbstractionHelpers.hpp
index 15a7660123..4a86d5dec0 100644
--- a/alib2abstraction/src/common/AbstractionHelpers.hpp
+++ b/alib2abstraction/src/common/AbstractionHelpers.hpp
@@ -35,22 +35,17 @@ constexpr decltype ( auto ) apply ( F && f, Tuple && t ) {
 }
 
 template < class ... Params >
-struct CheckInput;
+struct CheckInput {
+	static bool checkInput ( const std::shared_ptr < OperationAbstraction > & operation, unsigned index ) {
+		bool res = false;
 
-template < >
-struct CheckInput < > {
-	static bool checkInput ( const std::shared_ptr < OperationAbstraction > &, unsigned ) {
-		throw std::logic_error ( "Out of types to check" );
-	}
-};
+		auto lambda = [ & ] ( auto I ) {
+			 res = ( bool ) std::dynamic_pointer_cast < std::decay_t < std::tuple_element_t < decltype ( I )::value, std::tuple < Params ... > > > > ( operation->getProxyAbstraction ( ) );
+		};
 
-template < class Param, class ... Params >
-struct CheckInput < Param, Params ... > {
-	static bool checkInput ( const std::shared_ptr < OperationAbstraction > & operation, unsigned index ) {
-		if ( index == 0 )
-			return ( bool ) std::dynamic_pointer_cast < typename std::decay < Param >::type > ( operation->getProxyAbstraction ( ) );
-		else
-			return CheckInput < Params ... >::checkInput ( operation, index - 1 );
+		ext::constexpr_switch < sizeof ... ( Params ) > ( index, lambda );
+
+		return res;
 	}
 };
 
diff --git a/alib2std/src/extensions/utility.hpp b/alib2std/src/extensions/utility.hpp
index 8782eef5fe..689eb23a2b 100644
--- a/alib2std/src/extensions/utility.hpp
+++ b/alib2std/src/extensions/utility.hpp
@@ -51,6 +51,22 @@ inline auto move_copy ( const T & param ) {
 	}
 }
 
+namespace detail {
+
+template < class F, std::size_t ... Is >
+void constexpr_switch ( const std::size_t i, F && f, std::index_sequence < Is ... > ) {
+	[ ] ( ... ) { } (
+		( i == Is && ( ( void ) std::forward < F > ( f ) . operator ( ) ( std::integral_constant < size_t, Is > ( ) ), false ) ) ...
+	);
+}
+
+} // namespace detail
+
+template < std::size_t N, class F >
+void constexpr_switch ( const std::size_t i, F && f ) {
+	detail::constexpr_switch ( i, std::forward < F > ( f ), std::make_index_sequence < N > { } );
+}
+
 } /* namespace ext */
 
 #endif /* __UTILITY_HPP_ */
diff --git a/alib2std/test-src/extensions/UtilityTest.cpp b/alib2std/test-src/extensions/UtilityTest.cpp
index 866d111496..6a77be3d31 100644
--- a/alib2std/test-src/extensions/UtilityTest.cpp
+++ b/alib2std/test-src/extensions/UtilityTest.cpp
@@ -16,4 +16,41 @@ TEST_CASE ( "Utility", "[unit][std][bits]" ) {
 		ext::ptr_value < Foo > val ( Foo { } );
 		CHECK ( val->bar ( ) == 1 );
 	}
+
+	SECTION ( "Constexp switch" ) {
+		{
+			auto const t = std::make_tuple(42, 'z', 3.14, 13, 0, "Hello, World!");
+
+			auto lambda = [ & ] ( auto I ) {
+				if constexpr ( I == 0 )
+					CHECK ( std::get < decltype ( I )::value > ( t ) == 42 );
+				else if constexpr ( I == 1 )
+					CHECK ( std::get < decltype ( I )::value > ( t ) == 'z' );
+				else if constexpr ( I == 2 )
+					CHECK ( std::get < decltype ( I )::value > ( t ) == 3.14 );
+				else if constexpr ( I == 3 )
+					CHECK ( std::get < decltype ( I )::value > ( t ) == 13 );
+				else if constexpr ( I == 4 )
+					CHECK ( std::get < decltype ( I )::value > ( t ) == 0 );
+				else // constexpr ( I == 5 )
+					CHECK ( std::get < decltype ( I )::value > ( t ) == std::string ( "Hello, World!" ) );
+			};
+
+			for (std::size_t i = 0; i < std::tuple_size<decltype(t)>::value; ++i) {
+				ext::constexpr_switch < std::tuple_size<decltype(t)>::value > ( i, lambda );
+			}
+		}
+
+		{
+			auto const t = std::array<int, 4>{{0,1,2,3}};
+
+			auto lambda = [ & ] ( auto I ) {
+				CHECK ( std::get < decltype ( I )::value > ( t ) == I );
+			};
+
+			for (std::size_t i = 0; i < t.size(); ++i) {
+				ext::constexpr_switch < std::tuple_size<decltype(t)>::value > ( i, lambda );
+			}
+		}
+	}
 }
-- 
GitLab