From f42416fff2b1e5ead34e8713c7a0d14419eb39bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Tr=C3=A1vn=C3=AD=C4=8Dek?= <jan.travnicek@fit.cvut.cz>
Date: Thu, 20 Jan 2022 05:42:01 +0100
Subject: [PATCH] abstraction: use deep type retrieval if available

---
 alib2abstraction/src/core/type_details.hpp |  8 ++++++--
 alib2data/src/common/symbol_or_epsilon.hpp | 21 +++++++++++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/alib2abstraction/src/core/type_details.hpp b/alib2abstraction/src/core/type_details.hpp
index ec0952bbb1..cdfc9036d4 100644
--- a/alib2abstraction/src/core/type_details.hpp
+++ b/alib2abstraction/src/core/type_details.hpp
@@ -27,8 +27,12 @@ public:
 	}
 
 	template < class T >
-	static type_details get ( const T & ) {
-		return core::type_details::get < T > ( );
+	static type_details get ( const T & arg ) {
+		if constexpr ( core::is_specialized < core::type_util < T > > ) {
+			return core::type_util < T >::type ( arg );
+		} else {
+			return core::type_details::get < T > ( );
+		}
 	}
 
 	static type_details universal_type ( );
diff --git a/alib2data/src/common/symbol_or_epsilon.hpp b/alib2data/src/common/symbol_or_epsilon.hpp
index 087e6b9e61..db52ac5dbf 100644
--- a/alib2data/src/common/symbol_or_epsilon.hpp
+++ b/alib2data/src/common/symbol_or_epsilon.hpp
@@ -2,6 +2,7 @@
 
 #include <optional>
 
+#include <core/type_util.hpp>
 #include <core/type_details_base.hpp>
 
 #include <alib/tuple>
@@ -94,6 +95,26 @@ ext::ostream & operator << ( ext::ostream & out, const common::symbol_or_epsilon
 
 namespace core {
 
+template < class SymbolType >
+struct type_util < common::symbol_or_epsilon < SymbolType > > {
+	static std::unique_ptr < type_details_base > type ( const common::symbol_or_epsilon < SymbolType > & arg ) {
+		core::unique_ptr_set < type_details_base > subTypes;
+
+		if ( ! arg.is_epsilon ( ) )
+			subTypes.insert ( type_util < SymbolType >::type ( arg.getSymbol ( ) ) );
+
+		std::vector < std::unique_ptr < type_details_base > > sub_types_vec;
+		if ( subTypes.empty ( ) )
+			sub_types_vec.push_back ( std::make_unique < type_details_universal_type > ( ) );
+		else if ( subTypes.size ( ) == 1 )
+			sub_types_vec.push_back ( std::move ( subTypes.extract ( subTypes.begin ( ) ).value ( ) ) );
+		else
+			sub_types_vec.push_back ( std::make_unique < type_details_variant_type > ( std::move ( subTypes ) ) );
+
+		return std::make_unique < type_details_template > ( "common::symbol_or_epsilon", std::move ( sub_types_vec ) );
+	}
+};
+
 template < class SymbolType >
 struct type_details_retriever < common::symbol_or_epsilon < SymbolType > > {
 	static std::unique_ptr < type_details_base > get ( ) {
-- 
GitLab