fork download
  1. #include <cstdio>
  2. #include <typeinfo>
  3.  
  4. #include <utility>
  5. #include <type_traits>
  6.  
  7. namespace luple_ns {
  8.  
  9. //type list
  10. template<typename... TT> struct type_list { static const int size = sizeof...(TT); };
  11.  
  12. //get element type by index
  13. template<typename T, int N, int M = 0> struct tlist_get;
  14.  
  15. template<int N, int M, typename T, typename... TT> struct tlist_get< type_list<T, TT...>, N, M > {
  16. static_assert(N < (int) sizeof...(TT)+1 + M, "type index out of bounds");
  17. using type = std::conditional_t< N == M, T, typename tlist_get< type_list<TT...>, N, M + 1 >::type >;
  18. };
  19.  
  20. template<int N, int M> struct tlist_get< type_list<>, N, M > {
  21. using type = void;
  22. };
  23.  
  24. template<typename T, int N>
  25. using tlist_get_t = typename tlist_get<T, N>::type;
  26.  
  27. //get element index by type
  28. template<typename T, typename U, int N = 0> struct tlist_get_n;
  29.  
  30. template<typename U, int N, typename T, typename... TT> struct tlist_get_n< type_list<T, TT...>, U, N > {
  31. static const int value = std::is_same< T, U >::value ? N : tlist_get_n< type_list<TT...>, U, N + 1 >::value;
  32. };
  33. template<typename U, int N> struct tlist_get_n< type_list<>, U, N > {
  34. static const int value = -1;
  35. };
  36.  
  37. //a building block that is used in multiple inheritane
  38. template<typename T, int N> struct tuple_element {
  39. tlist_get_t<T, N> value;
  40. };
  41.  
  42. //base of luple and also parent of tuple_element's
  43. template<typename T, typename U> struct tuple_base;
  44.  
  45. template<typename... TT, int... NN>
  46. struct tuple_base< type_list<TT...>, std::integer_sequence<int, NN...> > : tuple_element< type_list<TT...>, NN >... {
  47.  
  48. using tlist = type_list<TT...>;
  49.  
  50. template<typename... UU, typename U = std::enable_if_t< sizeof...(UU) == sizeof...(NN) >>
  51. constexpr tuple_base ( UU&&... args ) : tuple_element< tlist, NN >{ std::forward<UU>(args) }... {}
  52. constexpr tuple_base ( TT const&... args ) : tuple_element< tlist, NN >{ args }... {}
  53. constexpr tuple_base ( TT&&... args ) : tuple_element< tlist, NN >{ std::move(args) }... {}
  54. constexpr tuple_base () {}
  55. };
  56.  
  57. //tuple=luple
  58. //T: type_list< ... user types ... >
  59. template<typename T> struct tuple : tuple_base< T, std::make_integer_sequence<int, T::size> > {
  60.  
  61. using type_list = T;
  62. using base = tuple_base< T, std::make_integer_sequence<int, T::size> >;
  63.  
  64. template<int N> constexpr auto& get() {
  65. static_assert(N < T::size, "tuple::get -> out of bounds access");
  66. return tuple_element< T, N >::value;
  67. }
  68.  
  69. template<typename U> constexpr auto& get() {
  70. static_assert(tlist_get_n<T, U>::value != -1, "no such type in type list");
  71. return tuple_element< T, tlist_get_n<T, U>::value >::value;
  72. }
  73.  
  74. template<int N> constexpr auto& get() const {
  75. static_assert(N < T::size, "tuple::get -> out of bounds access");
  76. return tuple_element< T, N >::value;
  77. }
  78.  
  79. template<typename U> constexpr auto& get() const {
  80. static_assert(tlist_get_n<T, U>::value != -1, "no such type in type list");
  81. return tuple_element< T, tlist_get_n<T, U>::value >::value;
  82. }
  83.  
  84. using base::base;
  85. };
  86.  
  87. template<int N, typename T> constexpr auto& get ( tuple<T>& t ) { return t.template get<N>(); }
  88. template<typename U, typename T> constexpr auto& get ( tuple<T>& t ) { return t.template get<U>(); }
  89.  
  90. template<int N, typename T> constexpr auto& get ( tuple<T> const& t ) { return t.template get<N>(); }
  91. template<typename U, typename T> constexpr auto& get ( tuple<T> const& t ) { return t.template get<U>(); }
  92.  
  93. template<typename T> constexpr auto size ( tuple<T> const& t ) { return T::size; }
  94. template<typename U, typename T> constexpr auto index ( tuple<T> const& t ) { return tlist_get_n< T, U >::value; }
  95.  
  96. //type for index
  97. template<typename T, int N>
  98. using element_t = tlist_get_t< typename T::type_list, N >;
  99.  
  100. //helper to make luple<A, B, C> and luple< type_list<A, B, C> > equivalent
  101. template<typename T> struct luple_impl {
  102. using type = tuple<T>;
  103. };
  104.  
  105. template<typename... TT> struct luple_impl< type_list< type_list<TT...> > > {
  106. using type = typename luple_impl< type_list<TT...> >::type;
  107. };
  108.  
  109. //template alias to wrap types into type_list
  110. template<typename... TT>
  111. using luple = typename luple_impl< type_list<TT...> >::type;
  112.  
  113. //helper to run code for every member of luple
  114. template<int... N, typename T0, typename T1>
  115. void luple_do_impl (std::integer_sequence<int, N...>, T0& t, T1 fn) {
  116. char dummy[]{ (fn( get<N>(t) ), char{})... };
  117. (void)dummy;
  118. }
  119.  
  120. //helper to run code for every member of tuple
  121. template<typename T0, typename T1>
  122. void luple_do (T0& t, T1 fn) {
  123. luple_do_impl( std::make_integer_sequence< int, T0::type_list::size >{}, t, fn );
  124. }
  125.  
  126. }
  127.  
  128. //import into global namespace
  129. using luple_ns::luple;
  130. using luple_ns::get;
  131. using luple_ns::index;
  132.  
  133.  
  134.  
  135. namespace struct_reader {
  136.  
  137. using namespace luple_ns;
  138.  
  139. //this is the main type list, add your own types here
  140. using type_list_t = type_list<
  141. void *, bool, char, unsigned char, signed char, short, int, long, long long,
  142. unsigned short, unsigned int, unsigned long, unsigned long long,
  143. float, double, long double,
  144. _IO_marker *,_IO_FILE *
  145. >;
  146.  
  147. //helper to get type using a templated conversion operator
  148. template<typename T>
  149. struct read_type {
  150. template<typename U>
  151. constexpr operator U() {
  152. using noptr = std::remove_pointer_t<U>;
  153. using nocon = std::remove_const_t<noptr>;
  154. static_assert( tlist_get_n<T, U>::value != -1 || tlist_get_n<T, nocon>::value != -1, "no such type in type list");
  155. constexpr int const tid = 0xFFFF, is_ptr = 1 << 16, is_con = 1 << 17;
  156. data = tlist_get_n<T, U>::value;
  157. if( data == -1 ) {
  158. data = tlist_get_n<T, nocon>::value & tid;
  159. data = data | (std::is_pointer<U>::value ? is_ptr : 0);
  160. data = data | (std::is_const<noptr>::value ? is_con : 0);
  161. }
  162. return {};
  163. }
  164. int data;
  165. };
  166.  
  167. using read_type_t = read_type< type_list_t >;
  168.  
  169. //here we're using overload resolution to get a data member type
  170. template<typename T, int... N>
  171. constexpr auto get_type_id(int n) {
  172. read_type_t tid[sizeof...(N)]{};
  173. T d = T{ tid[N]... }; (void)d;
  174. return tid[n].data;
  175. }
  176.  
  177. //helper to rebuild the type
  178. template<typename T, int tid, int is_pointer, int is_const>
  179. constexpr auto get_type() {
  180. using type = tlist_get_t<T, tid>;
  181. using ctype = std::conditional_t< (bool)is_const, std::add_const_t<type>, type >;
  182. using ptype = std::conditional_t< (bool)is_pointer, std::add_pointer_t<ctype>, ctype >;
  183. return ptype{};
  184. }
  185.  
  186. //read struct data member types and put it into a type list
  187. template<typename T, int... N>
  188. constexpr auto get_type_list(std::integer_sequence<int, N...>) {
  189. constexpr int t[] = { get_type_id<T, N...>(N)... };
  190. constexpr int const tid = 0xFFFF, is_ptr = 1 << 16, is_con = 1 << 17;
  191. return type_list< decltype(get_type<type_list_t, t[N]&tid, t[N]&is_ptr, t[N]&is_con>())...>{};
  192. }
  193.  
  194. //get fields number using expression SFINAE
  195. template<typename T, int... N>
  196. constexpr auto fields_number(...) { return sizeof...(N)-1; }
  197.  
  198. template<typename T, int... N>
  199. constexpr auto fields_number(int) -> decltype(T{ (N,read_type_t{})... }, sizeof(0)) { return fields_number<T, N..., 0>(0); }
  200.  
  201. //and here is our hot and fresh out of kitchen type list (alias template)
  202. template<typename T>
  203. using as_type_list = decltype(get_type_list< T >(std::make_integer_sequence< int, fields_number<T>(0) >{}));
  204.  
  205. }
  206.  
  207. int main() {
  208.  
  209. using FILE_tlist = struct_reader::as_type_list< FILE >;
  210.  
  211. //for being able to read out FILE I had to add _IO_marker* and _IO_FILE* to type_list_t
  212. //check notes in the file struct-reader.h at https://g...content-available-to-author-only...b.com/alexpolt/luple
  213.  
  214. using FILE_luple = luple< FILE_tlist >;
  215.  
  216. auto& t = reinterpret_cast<FILE_luple&>( *stdout );
  217.  
  218. printf("sizeof FILE = %zd, sizeof FILE_luple = %zd\n", sizeof(FILE), sizeof(t));
  219.  
  220. luple_do(t, [i=0](auto& value) mutable { printf("%d. %s: %#zX, \n", i++, typeid(value).name(), (size_t)value); });
  221.  
  222. }
Success #stdin #stdout 0s 15232KB
stdin
Standard input is empty
stdout
sizeof FILE = 216, sizeof FILE_luple = 216
0. i: 0XFFFFFFFFFBAD2884, 
1. Pc: 0X1CF7C20, 
2. Pc: 0X1CF7C20, 
3. Pc: 0X1CF7C20, 
4. Pc: 0X1CF7C20, 
5. Pc: 0X1CF7CB2, 
6. Pc: 0X1CF8C20, 
7. Pc: 0X1CF7C20, 
8. Pc: 0X1CF8C20, 
9. Pc: 0, 
10. Pc: 0, 
11. Pc: 0, 
12. P10_IO_marker: 0, 
13. P8_IO_FILE: 0X2AC38A32B8C0, 
14. i: 0X1, 
15. i: 0, 
16. l: 0XFFFFFFFFFFFFFFFF, 
17. t: 0, 
18. a: 0, 
19. c: 0, 
20. Pv: 0X2AC38A32D760, 
21. l: 0XFFFFFFFFFFFFFFFF, 
22. Pv: 0, 
23. Pv: 0X2AC38A32B780, 
24. Pv: 0, 
25. Pv: 0, 
26. m: 0, 
27. i: 0XFFFFFFFFFFFFFFFF, 
28. c: 0, 
29. c: 0, 
30. c: 0, 
31. c: 0, 
32. c: 0, 
33. c: 0, 
34. c: 0, 
35. c: 0, 
36. c: 0, 
37. c: 0, 
38. c: 0, 
39. c: 0, 
40. c: 0, 
41. c: 0, 
42. c: 0, 
43. c: 0, 
44. c: 0, 
45. c: 0, 
46. c: 0, 
47. c: 0,