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