From cfbbf7899ed998bc5571fecd59df3c865e0d04bb Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Mon, 3 Sep 2018 09:31:56 +0200
Subject: [PATCH] implementation and use of callback output iterator

---
 .../src/core/components/setComponents.hpp     | 10 +--
 alib2common/test-src/core/ComponentsTest.cpp  | 11 +++
 alib2std/src/extensions/iterator.hpp          | 75 +++++++++++++++++++
 alib2std/test-src/extensions/IteratorTest.cpp |  8 ++
 alib2std/test-src/extensions/IteratorTest.h   |  2 +
 5 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/alib2common/src/core/components/setComponents.hpp b/alib2common/src/core/components/setComponents.hpp
index 8a0d5b0f64..a0e81b6875 100644
--- a/alib2common/src/core/components/setComponents.hpp
+++ b/alib2common/src/core/components/setComponents.hpp
@@ -149,14 +149,8 @@ public:
 	 *        CommonException if one of the added elements is not available in context of datatype where the set is used
 	 */
 	void set ( SetComponentType data ) {
-		SetComponentType removed;
-		std::set_difference ( m_data.begin ( ), m_data.end ( ), data.begin ( ), data.end ( ), std::inserter ( removed, removed.end ( ) ) );
-
-		for ( const ComponentType & element : removed )
-			checkRemove ( element );
-
-		for ( const ComponentType & element : data )
-			checkAdd ( element );
+		std::set_difference ( m_data.begin ( ), m_data.end ( ), data.begin ( ), data.end ( ), ext::make_callback_iterator < const ComponentType & > ( std::bind ( & SetComponent::checkRemove, this, std::placeholders::_1 ) ) );
+		std::set_difference ( data.begin ( ), data.end ( ), m_data.begin ( ), m_data.end ( ), ext::make_callback_iterator < const ComponentType & > ( std::bind ( & SetComponent::checkAdd, this, std::placeholders::_1 ) ) );
 
 		m_data = std::move ( data );
 	}
diff --git a/alib2common/test-src/core/ComponentsTest.cpp b/alib2common/test-src/core/ComponentsTest.cpp
index 661918b1a9..cadcbe0ac7 100644
--- a/alib2common/test-src/core/ComponentsTest.cpp
+++ b/alib2common/test-src/core/ComponentsTest.cpp
@@ -130,6 +130,17 @@ void ComponentsTest::testRemove ( ) {
 	tmp.accessComponent < GeneralAlphabet > ( ).add ( "1" );
 	tmp.accessComponent < NonlinearAlphabet > ( ).add ( "1" );
 	CPPUNIT_ASSERT_THROW ( tmp.accessComponent < GeneralAlphabet > ( ).remove ( "1" ), exception::CommonException );
+	CPPUNIT_ASSERT_THROW ( tmp.accessComponent < GeneralAlphabet > ( ).remove ( ext::linear_set < std::string > { "1" } ), exception::CommonException );
+	CPPUNIT_ASSERT_NO_THROW ( tmp.accessComponent < GeneralAlphabet > ( ).set ( ext::linear_set < std::string > { "1", "2", "aaa", "3" } ) );
+	CPPUNIT_ASSERT_THROW ( tmp.accessComponent < GeneralAlphabet > ( ).set ( ext::linear_set < std::string > { } ), exception::CommonException );
+
+	CPPUNIT_ASSERT ( tmp.accessComponent < GeneralAlphabet > ( ).get ( ).size ( ) == 4 );
+
+	CPPUNIT_ASSERT_NO_THROW ( tmp.accessComponent < NonlinearAlphabet > ( ).set ( ext::linear_set < std::string > { "1", "3" } ) );
+	CPPUNIT_ASSERT_THROW ( tmp.accessComponent < NonlinearAlphabet > ( ).set ( ext::linear_set < std::string > { "1", "4" } ), exception::CommonException );
+
 	tmp.accessComponent < NonlinearAlphabet > ( ).remove ( "1" );
 	tmp.accessComponent < GeneralAlphabet > ( ).remove ( "1" );
+
+
 }
diff --git a/alib2std/src/extensions/iterator.hpp b/alib2std/src/extensions/iterator.hpp
index 9c4cf7c8da..cee8d5a4fd 100644
--- a/alib2std/src/extensions/iterator.hpp
+++ b/alib2std/src/extensions/iterator.hpp
@@ -25,6 +25,7 @@
 #define __ITERATOR_HPP_
 
 #include <iterator>
+#include <functional>
 
 namespace ext {
 
@@ -1025,6 +1026,80 @@ constexpr T * end ( T ( & arr ) [ N ] ) noexcept {
 	return arr + N;
 }
 
+/**
+ * \brief
+ * Output iterator calling a callback function on assignment
+ *
+ * \tparam the type of value accepted by the callback. The type must include the reference and cv-qualification if needed.
+ */
+template < class T >
+class callback_iterator : public std::iterator < std::output_iterator_tag, void, void, void, void > {
+	/**
+	 * The callback.
+	 */
+	std::function < void ( T ) > m_callback;
+
+public:
+	/**
+	 * Constructor of the callback iterator based on callback
+	 *
+	 * \param callback the function to call on asignment
+	 */
+	explicit callback_iterator ( std::function < void ( T ) > callback ) : m_callback ( callback ) {
+	}
+
+	/**
+	 * Asignment operator calling the calback with the accepted parameter.
+	 *
+	 * \param value the value to pass to the callback
+	 *
+	 * \return reference to this iterator
+	 */
+	callback_iterator & operator = ( T value ) {
+		m_callback ( std::forward < T > ( value ) );
+		return * this;
+	}
+
+	/**
+	 * Typical implementation of output iterator dereference operator producing itself.
+	 *
+	 * \return reference to this output iterator
+	 */
+	callback_iterator &operator * ( ) {
+		return * this;
+	}
+
+	/**
+	 * Increment operator implementation as no operation.
+	 *
+	 * \return reference to this output iterator
+	 */
+	callback_iterator &operator ++ ( ) {
+		return * this;
+	}
+
+	/**
+	 * Increment operator implementation as no operation.
+	 *
+	 * \return reference to this output iterator
+	 */
+	callback_iterator operator ++ ( int ) {
+		return * this;
+	}
+};
+
+/**
+ * Function to create callback iterator from the callback.
+ *
+ * \param T the type of value accepted by the callback.
+ *
+ * \return the callback iterator
+ */
+template < class T >
+callback_iterator < T > make_callback_iterator ( const std::function < void ( T ) > & callback ) {
+	return callback_iterator < T > ( callback );
+}
+
 } /* namespace ext */
 
 #endif /* __ITERATOR_HPP_ */
diff --git a/alib2std/test-src/extensions/IteratorTest.cpp b/alib2std/test-src/extensions/IteratorTest.cpp
index ac11e103d2..12b0636704 100644
--- a/alib2std/test-src/extensions/IteratorTest.cpp
+++ b/alib2std/test-src/extensions/IteratorTest.cpp
@@ -69,3 +69,11 @@ void IteratorTest::testReverser() {
 
 	CPPUNIT_ASSERT ( data2 == trans );
 }
+
+void IteratorTest::testCallbackIterator ( ) {
+	int expected;
+	ext::callback_iterator < int > out = ext::make_callback_iterator < int > ( [ & ] ( int value ) -> void { CPPUNIT_ASSERT ( value == expected ); } );
+
+	expected = 10;
+	* out = 10;
+}
diff --git a/alib2std/test-src/extensions/IteratorTest.h b/alib2std/test-src/extensions/IteratorTest.h
index 1cff4cd97e..93d4bc4947 100644
--- a/alib2std/test-src/extensions/IteratorTest.h
+++ b/alib2std/test-src/extensions/IteratorTest.h
@@ -8,6 +8,7 @@ class IteratorTest : public CppUnit::TestFixture
   CPPUNIT_TEST_SUITE( IteratorTest );
   CPPUNIT_TEST( testIterator );
   CPPUNIT_TEST( testReverser );
+  CPPUNIT_TEST( testCallbackIterator );
   CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -16,6 +17,7 @@ public:
 
   void testIterator();
   void testReverser();
+  void testCallbackIterator();
 };
 
 #endif  // ITERATOR_TEST_H_
-- 
GitLab