From b801f71b2b129b4f59fbcd427313bbfd2b4666e6 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 24 Apr 2018 16:12:09 +0200
Subject: [PATCH] introduce ptr_tuple

---
 alib2std/src/alib/ptr_tuple                   |   1 +
 alib2std/src/extensions/ptr_tuple.hpp         | 275 ++++++++++++++++++
 alib2std/test-src/extensions/PtrTupleTest.cpp |  24 ++
 alib2std/test-src/extensions/PtrTupleTest.h   |  19 ++
 4 files changed, 319 insertions(+)
 create mode 100644 alib2std/src/alib/ptr_tuple
 create mode 100644 alib2std/src/extensions/ptr_tuple.hpp
 create mode 100644 alib2std/test-src/extensions/PtrTupleTest.cpp
 create mode 100644 alib2std/test-src/extensions/PtrTupleTest.h

diff --git a/alib2std/src/alib/ptr_tuple b/alib2std/src/alib/ptr_tuple
new file mode 100644
index 0000000000..241c8a79ad
--- /dev/null
+++ b/alib2std/src/alib/ptr_tuple
@@ -0,0 +1 @@
+#include <extensions/ptr_tuple.hpp>
diff --git a/alib2std/src/extensions/ptr_tuple.hpp b/alib2std/src/extensions/ptr_tuple.hpp
new file mode 100644
index 0000000000..005406475b
--- /dev/null
+++ b/alib2std/src/extensions/ptr_tuple.hpp
@@ -0,0 +1,275 @@
+/*
+ * ptr_tuple.hpp
+ *
+ * Created on: Feb 28, 2014
+ * Author: Jan Travnicek
+ */
+
+#ifndef __PTR_TUPLE_HPP_
+#define __PTR_TUPLE_HPP_
+
+#include <ostream>
+#include <sstream>
+#include <string>
+
+#include "tuple.hpp"
+#include "compare.hpp"
+#include "iterator.hpp"
+#include "clone.hpp"
+
+namespace ext {
+
+template < class ... Types >
+class ptr_tuple {
+	std::tuple < Types * ... > m_data;
+
+	template < std::size_t ... Indices >
+	void copyCons ( std::index_sequence < Indices ... >, const ptr_tuple & tpl ) {
+		( void ) std::initializer_list < int > { ( std::get < Indices > ( m_data ) = ext::clone ( std::get < Indices > ( * tpl.m_data ) ), 0 ) ... };
+	}
+
+	template < std::size_t ... Indices >
+	void moveCons ( std::index_sequence < Indices ... >, ptr_tuple && tpl ) {
+		( void ) std::initializer_list < int > { ( std::swap ( std::get < Indices > ( m_data ), std::get < Indices > ( tpl.m_data ) ), 0 ) ... };
+	}
+
+	template < std::size_t ... Indices >
+	void cons ( std::index_sequence < Indices ... >, const Types & ... elems ) {
+		( void ) std::initializer_list < int > { ( std::get < Indices > ( m_data ) = ext::clone ( elems ), 0 ) ... };
+	}
+
+	template < std::size_t ... Indices, class ... UTypes >
+	void cons ( std::index_sequence < Indices ... >, UTypes && ... elems ) {
+		( void ) std::initializer_list < int > { ( std::get < Indices > ( m_data ) = ext::clone ( std::forward < UTypes > ( elems ) ), 0 ) ... };
+	}
+
+	template < std::size_t ... Indices >
+	void des ( std::index_sequence < Indices ... > ) {
+		( void ) std::initializer_list < int > { ( delete std::get < Indices > ( m_data ), 0 ) ... };
+	}
+
+public:
+	ptr_tuple ( const ptr_tuple & tpl ) {
+		copyCons ( std::make_index_sequence < sizeof ... ( Types ) > ( ), tpl );
+	}
+
+	ptr_tuple ( ptr_tuple && tpl ) {
+		moveCons ( std::make_index_sequence < sizeof ... ( Types ) > ( ), std::move ( tpl ) );
+	}
+
+/*	template < class ... UTypes>
+	ptr_tuple ( const ptr_tuple < UTypes ... > & tpl ) {
+	}
+
+	template < class ... UTypes >
+	ptr_tuple ( ptr_tuple < UTypes ... > && tpl ) {
+
+	}*/
+
+	explicit ptr_tuple ( const Types & ... elems ) {
+		cons ( std::make_index_sequence < sizeof ... ( Types ) > ( ), elems ... );
+	}
+
+	template < class ... UTypes >
+	explicit ptr_tuple ( UTypes && ... elems ) {
+		cons ( std::make_index_sequence < sizeof ... ( Types ) > ( ), std::forward < UTypes > ( elems ) ... );
+	}
+
+	~ptr_tuple ( ) {
+		des ( std::make_index_sequence < sizeof ... ( Types ) > ( ) );
+	}
+
+	ptr_tuple < Types ... > & operator = ( const ptr_tuple < Types ... > & other ) {
+		if ( this == & other )
+			return * this;
+
+		des ( std::make_index_sequence < sizeof ... ( Types ) > ( ) );
+		copyCons ( std::make_index_sequence < sizeof ... ( Types ) > ( ), other );
+
+		return *this;
+	}
+
+	ptr_tuple < Types ... > & operator = ( ptr_tuple < Types ... > && other ) {
+		std::swap ( m_data, other.m_data );
+
+		return *this;
+	}
+
+	void swap ( ptr_tuple & other ) {
+		swap ( this->m_data, other.m_data );
+	}
+
+	template < std::size_t I >
+	auto & get ( ) & {
+		return * std::get < I > ( m_data );
+	}
+
+	template < std::size_t I >
+	const auto & get ( ) const & {
+		return * std::get < I > ( m_data );
+	}
+
+	template < std::size_t I >
+	auto && get ( ) && {
+		return std::move ( * std::get < I > ( m_data ) );
+	}
+};
+
+template< class... Ts>
+std::ostream& operator<<(std::ostream& out, const ext::ptr_tuple<Ts...>& tuple) {
+	out << "(";
+
+	bool first = true;
+	auto outCallback = [ & ] ( const auto & arg0 ) {
+		if ( ! first ) {
+			out << ", ";
+		} else {
+			first = false;
+		}
+		out << arg0;
+	};
+
+	ext::foreach ( tuple, outCallback  );
+	out << ")";
+	return out;
+}
+
+template < typename ... Ts >
+struct compare < ext::ptr_tuple < Ts ... > > {
+	int operator ()( const ext::ptr_tuple < Ts ... > & first, const ext::ptr_tuple < Ts ... > & second ) const {
+		return compareTupleHelper < ext::tuple_size < ext::tuple < Ts ... > >::value - 1, ext::ptr_tuple < Ts ... > >::compHelp ( first, second );
+	}
+
+};
+
+template < class ... Ts >
+std::string to_string ( const ext::ptr_tuple < Ts ... > & value ) {
+	std::stringstream ss;
+	ss << value;
+	return ss.str();
+}
+
+template < class T >
+bool operator == ( const ptr_tuple < T > & first, const ptr_tuple < T > & second ) {
+	static compare < ptr_tuple < T > > comp;
+	return comp ( first, second ) == 0;
+}
+
+template < class T >
+bool operator != ( const ptr_tuple < T > & first, const ptr_tuple < T > & second ) {
+	return ! ( first == second );
+}
+
+template < class T >
+bool operator < ( const ptr_tuple < T > & first, const ptr_tuple < T > & second ) {
+	static compare < ptr_tuple < T > > comp;
+	return comp ( first, second ) < 0;
+}
+
+template < class T >
+bool operator > ( const ptr_tuple < T > & first, const ptr_tuple < T > & second ) {
+	return second < first;
+}
+
+template < class T >
+bool operator <= ( const ptr_tuple < T > & first, const ptr_tuple < T > & second ) {
+	return ! ( first > second );
+}
+
+template < class T >
+bool operator >= ( const ptr_tuple < T > & first, const ptr_tuple < T > & second ) {
+	return ! ( first < second );
+}
+
+} /* namespace ext */
+
+namespace std {
+
+template < class ... Ts >
+void swap ( ext::ptr_tuple < Ts ... > & first, ext::ptr_tuple < Ts ... > & second ) {
+	first.swap ( second );
+}
+
+template < std::size_t I, class ... Types >
+auto & get ( ext::ptr_tuple < Types ... > & tpl ) {
+	return tpl.template get < I > ( );
+}
+
+template < std::size_t I, class ... Types >
+const auto & get ( const ext::ptr_tuple < Types ... > & tpl ) {
+	return tpl.template get < I > ( );
+}
+
+template < std::size_t I, class ... Types >
+auto && get ( ext::ptr_tuple < Types ... > && tpl ) {
+	return tpl.template get < I > ( );
+}
+
+} /* namespace std */
+
+namespace ext {
+
+template<typename... _Elements>
+constexpr ptr_tuple < typename std::__decay_and_strip < _Elements >::__type... > make_ptr_tuple ( _Elements && ... __args ) {
+	typedef ptr_tuple < typename std::__decay_and_strip < _Elements >::__type... > __result_type;
+	return __result_type ( std::forward < _Elements > ( __args ) ... );
+}
+
+template < class ... Types >
+class tuple_size < ext::ptr_tuple < Types ... > > : public std::integral_constant < std::size_t, sizeof...( Types ) > { };
+
+template < std::size_t I, class... Types >
+struct tuple_element < I, ext::ptr_tuple < Types... > > {
+	typedef typename std::tuple_element < I, std::tuple < Types ... > >::type type;
+};
+
+template < class Result, unsigned I, class Callable, class ... Types >
+struct call_on_nth_helper < Result, I, ext::ptr_tuple < Types ... >, Callable > {
+	template < class Tuple >
+	static Result call_on_nth_fn ( Tuple && t, unsigned index, Callable callback ) {
+		if ( index == 0 )
+			return callback ( std::get < ext::tuple_size < Tuple >::value - I > ( std::forward < ext::ptr_tuple < Types ... > > ( t ) ) );
+		else
+			return call_on_nth_helper < Result, I - 1, ext::ptr_tuple < Types ... >, Callable >::call_on_nth_fn ( std::forward < Tuple && > ( t ), index - 1, callback );
+	}
+};
+
+template < class Result, class Callable, class ... Types >
+struct call_on_nth_helper < Result, 0, ext::ptr_tuple < Types ... >, Callable > {
+	template < class Tuple >
+	static Result call_on_nth_fn ( Tuple &&, unsigned, Callable ) {
+		throw std::out_of_range ( "Not enough elements in tuple." );
+	}
+};
+
+template < unsigned I, class Callable, class ... Types >
+struct foreach_helper < I, ext::ptr_tuple < Types ... >, Callable > {
+	template < class Tuple >
+	static void foreach_fn ( Tuple && t, Callable callback ) {
+		foreach_helper < I - 1, ext::ptr_tuple < Types ... >, Callable >::foreach_fn ( std::forward < Tuple && > ( t ), callback );
+		callback ( std::get < I - 1 > ( t ) );
+	}
+};
+
+template < class Callable, class ... Types >
+struct foreach_helper < 0, ext::ptr_tuple < Types ... >, Callable > {
+	template < class Tuple >
+	static void foreach_fn ( Tuple &&, Callable ) {
+	}
+};
+
+template < class Type, int size, class ... Types >
+struct PtrTupleBuilder;
+
+template < class Type, class ... Types >
+struct PtrTupleBuilder < Type, 0, Types ... > {
+	typedef ext::ptr_tuple < Types ... > type;
+};
+
+template < class Type, int n, class ... Types >
+struct PtrTupleBuilder : public PtrTupleBuilder < Type, n - 1, Type, Types ... > {
+};
+
+} /* namespace ext */
+
+#endif /* __PTR_TUPLE_HPP_ */
diff --git a/alib2std/test-src/extensions/PtrTupleTest.cpp b/alib2std/test-src/extensions/PtrTupleTest.cpp
new file mode 100644
index 0000000000..593c13861f
--- /dev/null
+++ b/alib2std/test-src/extensions/PtrTupleTest.cpp
@@ -0,0 +1,24 @@
+#include "PtrTupleTest.h"
+#include <alib/ptr_tuple>
+#include <sstream>
+
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( PtrTupleTest, "bits" );
+CPPUNIT_TEST_SUITE_REGISTRATION( PtrTupleTest );
+
+void PtrTupleTest::setUp() {
+}
+
+void PtrTupleTest::tearDown() {
+}
+
+void PtrTupleTest::testCallOnNth() {
+	ext::ptr_tuple < int, int, int, int, int > t = ext::make_ptr_tuple ( 1, 2, 3, 4, 5 );
+
+	CPPUNIT_ASSERT ( ext::call_on_nth < int > ( t, 1, [] ( int i ) { return i; } ) == 2 );
+
+	std::stringstream ss;
+	ss << t;
+	std::cout << ss.str ( ) << std::endl;
+	CPPUNIT_ASSERT ( ss.str ( ) == "(1, 2, 3, 4, 5)" );
+}
+
diff --git a/alib2std/test-src/extensions/PtrTupleTest.h b/alib2std/test-src/extensions/PtrTupleTest.h
new file mode 100644
index 0000000000..9092c32436
--- /dev/null
+++ b/alib2std/test-src/extensions/PtrTupleTest.h
@@ -0,0 +1,19 @@
+#ifndef PTR_TUPLE_TEST_H_
+#define PTR_TUPLE_TEST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class PtrTupleTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( PtrTupleTest );
+  CPPUNIT_TEST( testCallOnNth );
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void setUp();
+  void tearDown();
+
+  void testCallOnNth();
+};
+
+#endif  // PTR_TUPLE_TEST_H_
-- 
GitLab