From 4a8be9d3ad3c3c3405e88c5be608aa5a4c602dae Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Mon, 20 Nov 2017 06:39:04 +0100
Subject: [PATCH] allow registration of member methods

---
 alib2cli/test-src/cli/CliTest.cpp             | 24 +++++++++++
 alib2cli/test-src/cli/CliTest.h               |  2 +
 .../src/abstraction/AlgorithmRegistry.hpp     | 33 +++++++++++++++
 .../src/abstraction/MemberAbstraction.hpp     | 40 +++++++++++++++++++
 .../abstraction/ValueOperationAbstraction.hpp | 10 +++++
 5 files changed, 109 insertions(+)
 create mode 100644 alib2common/src/abstraction/MemberAbstraction.hpp

diff --git a/alib2cli/test-src/cli/CliTest.cpp b/alib2cli/test-src/cli/CliTest.cpp
index caee106204..c848b39da5 100644
--- a/alib2cli/test-src/cli/CliTest.cpp
+++ b/alib2cli/test-src/cli/CliTest.cpp
@@ -267,3 +267,27 @@ void CliTest::testSetConstruction ( ) {
 	parser = cli::Parser ( cli::Lexer ( "execute $set2 | Print -" ) );
 	parser.parse ( )->run ( environment );
 }
+
+class Foo {
+	int m_base;
+public:
+	Foo ( int base ) : m_base ( base ) {
+	}
+
+	int bar ( int value ) {
+		return m_base + value;
+	}
+
+	static Foo make_foo ( int base ) {
+		return Foo ( base );
+	}
+};
+
+void CliTest::testMember ( ) {
+	abstraction::AlgorithmRegistry::registerAlgorithm < Foo > ( Foo::make_foo, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, std::array < std::string, 1 > ( ) );
+	abstraction::AlgorithmRegistry::registerMethod < Foo > ( & Foo::bar, "bar", std::array < std::string, 1 > ( ) );
+
+	cli::Environment environment;
+	cli::Parser parser ( cli::Lexer ( "execute Foo 3 | Foo::bar - 2" ) );
+	parser.parse ( )->run ( environment );
+}
diff --git a/alib2cli/test-src/cli/CliTest.h b/alib2cli/test-src/cli/CliTest.h
index d9f5c7af68..21a3fdd0f5 100644
--- a/alib2cli/test-src/cli/CliTest.h
+++ b/alib2cli/test-src/cli/CliTest.h
@@ -12,6 +12,7 @@ class CliTest : public CppUnit::TestFixture {
 	CPPUNIT_TEST ( testReferencePassing );
 	CPPUNIT_TEST ( testConstRvalueReferencePassing );
 	CPPUNIT_TEST ( testSetConstruction );
+	CPPUNIT_TEST ( testMember );
 	CPPUNIT_TEST_SUITE_END ( );
 
 public:
@@ -25,6 +26,7 @@ public:
 	void testReferencePassing ( );
 	void testConstRvalueReferencePassing ( );
 	void testSetConstruction ( );
+	void testMember ( );
 };
 
 #endif // CLI_TEST_H_
diff --git a/alib2common/src/abstraction/AlgorithmRegistry.hpp b/alib2common/src/abstraction/AlgorithmRegistry.hpp
index 2e400ab150..8a499839a2 100644
--- a/alib2common/src/abstraction/AlgorithmRegistry.hpp
+++ b/alib2common/src/abstraction/AlgorithmRegistry.hpp
@@ -31,6 +31,17 @@ class AlgorithmRegistry {
 		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const = 0;
 	};
 
+	template < class ObjectType, class Return, class ... Params >
+	class MemberImpl : public Entry {
+		std::function < Return ( ObjectType *, Params ... ) > m_callback;
+
+	public:
+		MemberImpl ( std::function < Return ( ObjectType *, Params ... ) > callback ) : m_callback ( callback ) {
+		}
+
+		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override;
+	};
+
 	template < class Return, class ... Params >
 	class EntryImpl : public Entry {
 		std::function < Return ( Params ... ) > m_callback;
@@ -94,6 +105,22 @@ class AlgorithmRegistry {
 	static void registerInternal ( std::string algorithm, AlgorithmCategories::AlgorithmCategory category, ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result, ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params, std::shared_ptr < Entry > value );
 
 public:
+	template < class Algo, class ObjectType, class ReturnType, class ... ParamTypes >
+	static void registerMethod ( ReturnType ( ObjectType:: * callback ) ( ParamTypes ... ), std::string methodName, std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
+		AlgorithmCategories::AlgorithmCategory category = AlgorithmCategories::AlgorithmCategory::DEFAULT;
+		std::string algorithm = ext::to_string < Algo > ( ) + "::" + methodName;
+
+		ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params = convertParamTypes < ParamTypes ... > ( paramNames );
+		params.insert ( params.begin ( ), convertParamType < ObjectType > ( "object" ) );
+
+		ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result = convertReturnType < ReturnType > ( );
+
+		if ( isRegistered ( algorithm, category, params ) )
+			throw exception::CommonException ( "Callback for " + algorithm + " already registered." );
+
+		registerInternal ( std::move ( algorithm ), category, std::move ( result ), std::move ( params ), std::make_shared < MemberImpl < ObjectType, ReturnType, ParamTypes ... > > ( callback ) );
+	}
+
 	template < class Algo, class ReturnType, class ... ParamTypes >
 	static void registerAlgorithm ( ReturnType ( * callback ) ( ParamTypes ... ), AlgorithmCategories::AlgorithmCategory category, std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
 		std::string algorithm = ext::to_string < Algo > ( );
@@ -130,11 +157,17 @@ public:
 
 } /* namespace abstraction */
 
+#include <abstraction/MemberAbstraction.hpp>
 #include <abstraction/AlgorithmAbstraction.hpp>
 #include <abstraction/WrapperAbstraction.hpp>
 
 namespace abstraction {
 
+template < class Object, class Return, class ... Params >
+std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::MemberImpl < Object, Return, Params ... >::getAbstraction ( ) const {
+	return std::make_shared < abstraction::MemberAbstraction < Object, Return, Params ... > > ( m_callback );
+}
+
 template < class Return, class ... Params >
 std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::EntryImpl < Return, Params ... >::getAbstraction ( ) const {
 	return std::make_shared < abstraction::AlgorithmAbstraction < Return, Params ... > > ( m_callback );
diff --git a/alib2common/src/abstraction/MemberAbstraction.hpp b/alib2common/src/abstraction/MemberAbstraction.hpp
new file mode 100644
index 0000000000..86e17756cb
--- /dev/null
+++ b/alib2common/src/abstraction/MemberAbstraction.hpp
@@ -0,0 +1,40 @@
+/*
+ * MemberAbstraction.hpp
+ *
+ *  Created on: 11. 7. 2017
+ *	  Author: Jan Travnicek
+ */
+
+#ifndef _MEMBER_ABSTRACTION_HPP_
+#define _MEMBER_ABSTRACTION_HPP_
+
+#include <abstraction/NaryOperationAbstraction.hpp>
+#include <memory>
+#include <abstraction/Registry.h>
+
+namespace abstraction {
+
+template < class ObjectType, class ReturnType, class ... ParamTypes >
+class MemberAbstraction : public NaryOperationAbstraction < ReturnType, ObjectType &, ParamTypes ... > {
+	std::function < ReturnType ( ObjectType *, ParamTypes ... ) > m_callback;
+
+public:
+	MemberAbstraction ( std::function < ReturnType ( ObjectType *, ParamTypes ... ) > callback ) : m_callback ( callback ) {
+	}
+
+	virtual bool run ( ) override {
+		if ( ! this->inputsReady ( ) )
+			return false;
+
+		if ( this->cached ( ) )
+			return true;
+
+		this->member_run_helper ( m_callback, this->m_params, this->m_moves, std::make_index_sequence < sizeof ... ( ParamTypes ) > { } );
+		return true;
+	}
+
+};
+
+} /* namespace abstraction */
+
+#endif /* _MEMBER_ABSTRACTION_HPP_ */
diff --git a/alib2common/src/abstraction/ValueOperationAbstraction.hpp b/alib2common/src/abstraction/ValueOperationAbstraction.hpp
index a08d007f27..19dde2e605 100644
--- a/alib2common/src/abstraction/ValueOperationAbstraction.hpp
+++ b/alib2common/src/abstraction/ValueOperationAbstraction.hpp
@@ -31,6 +31,16 @@ protected:
 	mutable ext::variant < void, ReturnType > m_data;
 
 public:
+	template < typename Callable, typename Object, typename ... Ts, size_t ... Indexes >
+	inline void member_run_helper ( Callable callback, const ext::tuple < Object, Ts ... > & inputs, const std::array < bool, 1 + sizeof ... ( Indexes ) > moves, std::index_sequence < Indexes ... > ) {
+		/* make unused parameter warning go away in case of sizeof ... ( Ts ) == 0 */
+		( void ) inputs;
+		( void ) moves;
+
+		if ( ! isReady ( ) )
+			m_data = callback ( & std::get < 0 > ( inputs )->getValue ( false ), std::get < Indexes + 1 > ( inputs )->getValue ( std::get < Indexes + 1 > ( moves ) ) ... );
+	}
+
 	template < typename Callable, typename ... Ts, size_t ... Indexes >
 	inline void run_helper ( Callable callback, const ext::tuple < Ts ... > & inputs, const std::array < bool, sizeof ... ( Indexes ) > moves, std::index_sequence < Indexes ... > ) {
 		/* make unused parameter warning go away in case of sizeof ... ( Ts ) == 0 */
-- 
GitLab