Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpolt committed Oct 13, 2017
1 parent 0130cb5 commit 6ccdc01
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 81 deletions.
45 changes: 31 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ This repository is home to separate but related projects:
C++ Type Loophole, luple, nuple, C++ String Interning, Struct Reader.


## The C++ Type Loophole (C++14)

Header file: [type-loophole.h][]

Struct Reader is very limited in what it can do. You can't use std::string or a virtual type
with it, you need to add types to a list before using them. While researching the thing I
uncovered a **C++ Type Loophole**. Read more in the [blog post][e] with online examples.


## luple: A Lightweight (in terms of source code) Tuple (C++14)

Expand All @@ -25,7 +17,10 @@ C++ Type Loophole, luple, nuple, C++ String Interning, Struct Reader.
reinterpret\_cast it). Luple can be used in constexpr functions if its data members are of
literal type. Check the header for API description.

See it in action [online at tio.run][c] (or at [Ideone][d]).
See it in action [online at tio.run][l-tio] (also [Coliru][l-col] or [Wandbox][l-wan]).

Read the header for API documentation.


## nuple: a Named Tuple (C++14)

Expand All @@ -34,7 +29,10 @@ C++ Type Loophole, luple, nuple, C++ String Interning, Struct Reader.
nuple extends luple and allows giving names to data members. It works by using C++ string
interning (intern.h) which allows for a neat syntax. Check this [blog post][n].

Online example is [here at tio.run][n-tio] (or at [Ideone][n-ide]).
See it in action [online at tio.run][n-tio] (also [Coliru][n-col] or [Wandbox][n-wan]).

Read the header for API documentation.


## C++ String Interning (C++14)

Expand All @@ -50,6 +48,8 @@ C++ Type Loophole, luple, nuple, C++ String Interning, Struct Reader.

Also you can check an online example [here at tio.run][i-tio] (or at [Ideone][i-ide]).

Read the header for API documentation.


## Struct Reader (C++14)

Expand All @@ -63,6 +63,19 @@ C++ Type Loophole, luple, nuple, C++ String Interning, Struct Reader.

After discovery of the Great Type Loophole there is not much value to Struct Reader, I guess.

Read the header for API documentation.


## The C++ Type Loophole (C++14)

Header file: [type-loophole.h][]

Struct Reader is very limited in what it can do. You can't use std::string or a virtual type
with it, you need to add types to a list before using them. While researching the thing I
uncovered a **C++ Type Loophole**. Read more in the [blog post][e] with online examples.

Read the header for API documentation.

---

## License
Expand All @@ -78,10 +91,14 @@ C++ Type Loophole, luple, nuple, C++ String Interning, Struct Reader.
[n]: http://alexpolt.github.io/named-tuple.html "nuple: a Named Tuple"
[i]: http://alexpolt.github.io/intern.html "Useful Properties of String Interning in C++"

[c]: https://goo.gl/ojAhbb "luple Online Example"
[d]: https://ideone.com/nK9ttI "luple Online Example"
[n-tio]: https://goo.gl/EMWgBG "nuple Online Example"
[n-ide]: https://ideone.com/uvZ3uZ "nuple Online Example"
[l-tio]: https://goo.gl/isZtwj "luple Online Example at tio.run"
[l-col]: http://coliru.stacked-crooked.com/a/15a37a8385bcb3dc "luple Online Example at Coliru"
[l-wan]: https://wandbox.org/permlink/nm2pzbt1WqkfZ6k1 "luple Online Example at Wandbox"

[n-tio]: https://goo.gl/ocpLpG "luple Online Example at tio.run"
[n-col]: http://coliru.stacked-crooked.com/a/6c31a74287925b52 "luple Online Example at Coliru"
[n-wan]: https://wandbox.org/permlink/FA7LV8zjuyy9UIFH "luple Online Example at Wandbox"

[i-tio]: https://goo.gl/LfDTZ3 "C++ String Interning Online Example"
[i-ide]: https://ideone.com/Dh6az7 "C++ String Interning Online Example"

Expand Down
155 changes: 124 additions & 31 deletions luple.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,30 @@ License: Public-domain software
Construction:
luple< int, char ... > l0;
luple< std::string > l0{ "test" };
luple< std::string > l0{ std::string{"test"} };
luple< std::string > l1{ l0 };
luple< std::string > l1{ std::move( l0 ) };
//luple<...>
using person_t = luple< char const*, int id >;
person_t p[] = { { "alex", 0 }, { "ivan", 1 } };
luple< std::string, int > l0{ "test", 10 };
luple< std::string, int > l0{ std::string{"test"}, 20 };
luple< std::string, int > l1{ l0 };
luple< std::string, int > l1{ std::move( l0 ) };
//luple_t< type_list<...> >
//it's sometimes more useful to deal with a single T parameter
//rather dealing with a parameter pack TT...
using tlist = luple_ns::type_list< int, int, int >;
luple_t< tlist > obj{ 1, 2, 3 };
template<typename T>
void print( luple_t< T > const& ) { ... }
Assigment:
Expand All @@ -43,24 +62,36 @@ License: Public-domain software
Accesing data:
using my_luple_t = luple< int, std::string >;
using foo_t = luple< int, float, std::string >;
my_luple_t l2{ 10, "test" };
foo_t f0{ 10, 10.f, "hello world" };
auto& n = get<0>( l2 );
auto& str = get<std::string>( l2 );
auto& n = get< 0 >( f0 );
auto& str = get< std::string >( f0 );
get< float >( f0 ) = 20.f;
auto sz = size( l2 );
auto sz = size( f0 );
const int int_index = index<std::string>( l2 );
int int_index = index< std::string >( f0 );
static_assert( int_index != -1 , "not found" );
using element1_t = luple_ns::element_t< my_luple_t, 1 >;
using element1_t = luple_ns::element_t< foo_t, 2 >;
element1_t str{ "hello" };
luple_do( f0, []( auto& value ) { std::cout << value << ", "; } );
Comparison:
using person_t = luple< char const*, int id >;
element1_t str2{ "hello" };
person_t p[] = { { "alex", 0 }, { "ivan", 1 } };
luple_do( l2, []( auto& value ) { std::cout << value << ", "; } );
bool less = p[0] < p[1];
bool equal = p[0] == p[1];
//etc.
*/

Expand Down Expand Up @@ -134,6 +165,8 @@ namespace luple_ns {
using type_list = T;
using base = tuple_base< T, std::make_integer_sequence<int, T::size> >;

static const int size = T::size;

template<int N> constexpr auto& get() {
static_assert(N < T::size, "tuple::get -> out of bounds access");
return tuple_element< T, N >::value;
Expand All @@ -157,50 +190,110 @@ namespace luple_ns {
using base::base;
};

//template alias to wrap types into type_list
template<typename... TT>
using luple = tuple< type_list< TT... > >;

//template alias that takes type_list directly
template<typename T>
using luple_t = tuple< T >;

//get function helpers
template<int N, typename T> constexpr auto& get ( tuple<T>& t ) { return t.template get<N>(); }
template<typename U, typename T> constexpr auto& get ( tuple<T>& t ) { return t.template get<U>(); }

template<int N, typename T> constexpr auto& get ( tuple<T> const& t ) { return t.template get<N>(); }
template<typename U, typename T> constexpr auto& get ( tuple<T> const& t ) { return t.template get<U>(); }

template<typename T> constexpr auto size ( tuple<T> const& t ) { return T::size; }
template<typename U, typename T> constexpr auto index ( tuple<T> const& t ) { return tlist_get_n< T, U >::value; }
//tuple size
template<typename T> constexpr auto size ( tuple<T> const& ) { return T::size; }

//member index from type
template<typename U, typename T> constexpr auto index ( tuple<T> const& ) { return tlist_get_n< T, U >::value; }

//type for index
template<typename T, int N>
using element_t = tlist_get_t< typename T::type_list, N >;

//helper to make luple<A, B, C> and luple< type_list<A, B, C> > equivalent
template<typename T> struct luple_impl {
using type = tuple<T>;
};
//helper to run code for every member of luple
template<int... N, typename T0, typename T1>
void luple_do_impl ( std::integer_sequence<int, N...>, T0& t, T1 fn ) {

template<typename... TT> struct luple_impl< type_list< type_list<TT...> > > {
using type = typename luple_impl< type_list<TT...> >::type;
};
//in C++17 we got folding expressions

//template alias to wrap types into type_list
template<typename... TT>
using luple = typename luple_impl< type_list<TT...> >::type;
char dummy[] = { ( fn( get<N>(t) ), char{} )... };

//helper to run code for every member of luple
template<int... N, typename T0, typename T1>
void luple_do_impl (std::integer_sequence<int, N...>, T0& t, T1 fn) {
char dummy[]{ (fn( get<N>(t) ), char{})... };
(void)dummy;
}

//helper to run code for every member of tuple
template<typename T0, typename T1>
void luple_do (T0& t, T1 fn) {
void luple_do ( T0& t, T1 fn ) {

luple_do_impl( std::make_integer_sequence< int, T0::type_list::size >{}, t, fn );
}

}

//import into global namespace
using luple_ns::luple;
using luple_ns::luple_t;
using luple_ns::get;
using luple_ns::index;


//relational operators helpers

template<int N, typename T, typename U, typename = std::enable_if_t< N == T::size >>
bool luple_cmp_less ( T&, U& ) { return false; }

template<int N, typename T, typename U, typename = std::enable_if_t< (N < T::size) >>
bool luple_cmp_less ( luple_t< T > const& a, luple_t< U > const& b ) {

bool less = get< N >( a ) < get< N >( b );
bool equal = get< N >( a ) == get< N >( b );

return less ? true : ( equal ? luple_cmp_less< N+1 >( a, b ) : false );
}

template<int N, typename T, typename U, typename = std::enable_if_t< N == T::size >>
bool luple_cmp_equal ( T&, U& ) { return true; }

template<int N, typename T, typename U, typename = std::enable_if_t< (N < T::size) >>
bool luple_cmp_equal ( luple_t< T > const& a, luple_t< U > const& b ) {

bool equal = get< N >( a ) == get< N >( b );

return equal ? luple_cmp_equal< N+1 >( a, b ) : false;
}

//relational operators

template<typename T, typename U, typename = std::enable_if_t< (T::size > 0) && T::size == U::size >>
bool operator< ( luple_t< T > const& a, luple_t< U > const& b) {

return luple_cmp_less< 0 >( a, b );
}

template<typename T, typename U, typename = std::enable_if_t< (T::size > 0) && T::size == U::size >>
bool operator== ( luple_t< T > const& a, luple_t< U > const& b) {

return luple_cmp_equal< 0 >( a, b );
}

//the rest are easy

template<typename T, typename U>
bool operator!= ( luple_t< T > const& a, luple_t< U > const& b) { return !( a == b ); }

template<typename T, typename U>
bool operator> ( luple_t< T > const& a, luple_t< U > const& b) { return b < a; }

template<typename T, typename U>
bool operator<= ( luple_t< T > const& a, luple_t< U > const& b) { return !( a > b ); }

template<typename T, typename U>
bool operator>= ( luple_t< T > const& a, luple_t< U > const& b) { return !( a < b ); }



33 changes: 22 additions & 11 deletions nuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,30 @@ License: Public-domain software
#include "nuple.h"
using nameid_t = nuple<$("name"), char const*, $("id"), int>; //$(...) - check intern.h
using nameid_t = nuple< $("name"), char const*, $("id"), int >; //$(...) - see intern.h header
nameid_t n[] = { {"alex", 1}, {"ivan", 2} };
for( auto const& v : n )
printf( "name: %s, id: %d\n", get<$("name")>(v), get<$("id")>(v) );
auto get_person(int i) { return nameid_t{"john", i}; }
auto get_person ( int i ) { return nameid_t{ "john", i }; }
auto p = get_person(3);
auto p = get_person( 3 );
printf( "name: %s, id: %d\n", get<$("name")>( p ), get<$("id")>( p ) );
printf( "name: %s, id: %d\n", get<$("name")>(p), get<$("id")>(p) );
//nuple extends luple, so luple methods work as usual (as in tuple)
printf( "luple size: %d\n", size(p) );
printf( "luple size: %d\n", size( p ) );
get<0>(p) = "irene"; //or get<$("name")>(p) = "irene";
get<0>( p ) = "irene"; //or get<$("name")>( p ) = "irene";
get<int>( p ) = 4; //or get<$("id")>( p ) = 4;
get<int>(p) = 4; //or get<$("id")>(p) = 4;
bool is_equal = p == p;
//see luple.h for more examples
Expand Down Expand Up @@ -85,29 +88,37 @@ namespace nuple_ns {
//nuple is just a thin layer on top of luple

template<typename... TT>
struct nuple : luple< typename filter<TT...>::tlist > {
struct nuple : luple_t< typename filter<TT...>::tlist > {

using name_list = typename filter<TT...>::nlist;
using base = luple< typename filter<TT...>::tlist >;
using base = luple_t< typename filter<TT...>::tlist >;

static_assert( name_list::size == base::type_list::size, "name and type list sizes don't match" );

using base::base;
};

//turn a nuple member name into an index and call get< index >( ... )

template<typename T, typename = std::enable_if_t< intern::is_string<T>::value >, typename... TT>
constexpr auto& get ( nuple<TT...>& t ) {
static_assert( luple_ns::tlist_get_n< typename nuple<TT...>::name_list, T>::value != -1, "no such field" );

static_assert( luple_ns::tlist_get_n< typename nuple<TT...>::name_list, T>::value != -1, "no such nuple name" );

return get< luple_ns::tlist_get_n< typename nuple<TT...>::name_list, T >::value >( t );
}

template<typename T, typename = std::enable_if_t< intern::is_string<T>::value >, typename... TT>
constexpr auto& get ( nuple<TT...> const& t ) {
static_assert( luple_ns::tlist_get_n< typename nuple<TT...>::name_list, T>::value != -1, "no such field" );

static_assert( luple_ns::tlist_get_n< typename nuple<TT...>::name_list, T>::value != -1, "no such nuple name" );

return get< luple_ns::tlist_get_n< typename nuple<TT...>::name_list, T >::value >( t );
}

}


using nuple_ns::nuple;


Loading

0 comments on commit 6ccdc01

Please sign in to comment.