emlabcpp
modern opinionated embedded C++ library
decompose.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "../concepts.h"
27 
28 #include <tuple>
29 
30 namespace emlabcpp
31 {
32 
33 // thanks to the great presentation: https://www.youtube.com/watch?v=abdeAew3gmQ (Antony Polukhin)
34 namespace detail
35 {
36 
37  static constexpr std::size_t max_decompose_count = 16;
38 
39  template < std::size_t >
41  {
42  template < typename T >
43  operator T() const;
44  };
45 
46  template < class T, std::size_t I0, std::size_t... I >
47  constexpr auto decompose_count_impl( int& out, std::index_sequence< I0, I... > )
48  -> std::add_pointer_t<
49  decltype( T{ decompose_anything< I0 >{}, decompose_anything< I >{}... } ) >
50  {
51  out = sizeof...( I ) + 1;
52  return nullptr;
53  }
54 
55  template < class T, std::size_t... I >
56  constexpr void* decompose_count_impl( int& out, std::index_sequence< I... > )
57  {
58  if constexpr ( sizeof...( I ) > 0 ) {
59  decompose_count_impl< T >(
60  out, std::make_index_sequence< sizeof...( I ) - 1 >{} );
61  } else if constexpr ( std::is_default_constructible_v< T > ) {
62  out = 0;
63  } else {
64  out = -1;
65  }
66  return nullptr;
67  }
68 
69  template < typename T >
70  constexpr int decompose_count()
71  {
72  int c = -2;
73  decompose_count_impl< std::decay_t< T > >(
74  c, std::make_index_sequence< max_decompose_count >{} );
75  return c;
76  }
77 
78 } // namespace detail
79 
80 template < typename T >
81 concept decomposable = std::is_class_v< std::decay_t< T > > && !gettable_container< T > &&
82  ( detail::decompose_count< T >() >= 0 );
83 
84 #define EMLABCPP_GENERATE_DECOMPOSE( ID, ... ) \
85  template < typename T > \
86  concept decomposable_##ID = decomposable< T > && detail::decompose_count< T >() == ( ID ); \
87  \
88  template < decomposable_##ID T > \
89  constexpr auto decompose( T&& item ) \
90  { \
91  if constexpr ( !std::is_lvalue_reference_v< T > ) { \
92  auto&& [__VA_ARGS__] = std::forward< T >( item ); \
93  return std::make_tuple( __VA_ARGS__ ); \
94  } else { \
95  auto& [__VA_ARGS__] = item; \
96  return std::tie( __VA_ARGS__ ); \
97  } \
98  }
99 
100 template < typename T >
101 concept decomposable_0 = decomposable< T > && ( detail::decompose_count< T >() == 0 );
102 
103 template < decomposable_0 T >
104 constexpr std::tuple<> decompose( T&& )
105 {
106  return {};
107 }
108 
109 template < typename T, typename Tuple >
110 constexpr T compose( Tuple tpl )
111 {
112  return std::apply(
113  []< typename... Args >( Args&&... args ) {
114  return T{ std::forward< Args >( args )... };
115  },
116  std::move( tpl ) );
117 }
118 
120 EMLABCPP_GENERATE_DECOMPOSE( 2, a0, a1 )
121 EMLABCPP_GENERATE_DECOMPOSE( 3, a0, a1, a2 )
122 EMLABCPP_GENERATE_DECOMPOSE( 4, a0, a1, a2, a3 )
123 EMLABCPP_GENERATE_DECOMPOSE( 5, a0, a1, a2, a3, a4 )
124 EMLABCPP_GENERATE_DECOMPOSE( 6, a0, a1, a2, a3, a4, a5 )
125 EMLABCPP_GENERATE_DECOMPOSE( 7, a0, a1, a2, a3, a4, a5, a6 )
126 EMLABCPP_GENERATE_DECOMPOSE( 8, a0, a1, a2, a3, a4, a5, a6, a7 )
127 EMLABCPP_GENERATE_DECOMPOSE( 9, a0, a1, a2, a3, a4, a5, a6, a7, a8 )
128 EMLABCPP_GENERATE_DECOMPOSE( 10, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 )
129 EMLABCPP_GENERATE_DECOMPOSE( 11, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 )
130 EMLABCPP_GENERATE_DECOMPOSE( 12, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 )
131 EMLABCPP_GENERATE_DECOMPOSE( 13, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 )
132 EMLABCPP_GENERATE_DECOMPOSE( 14, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13 )
133 EMLABCPP_GENERATE_DECOMPOSE( 15, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 )
135  16,
136  a0,
137  a1,
138  a2,
139  a3,
140  a4,
141  a5,
142  a6,
143  a7,
144  a8,
145  a9,
146  a10,
147  a11,
148  a12,
149  a13,
150  a14,
151  a15 )
152 
153 template < typename T >
154 using decomposed_type = decltype( decompose( std::declval< T >() ) );
155 
156 } // namespace emlabcpp
constexpr int decompose_count()
Definition: decompose.h:70
constexpr auto decompose_count_impl(int &out, std::index_sequence< I0, I... >) -> std::add_pointer_t< decltype(T{ decompose_anything< I0 >{}, decompose_anything< I >{}... }) >
Definition: decompose.h:47
static constexpr std::size_t max_decompose_count
Definition: decompose.h:37
MIT License.
Definition: impl.h:31
Args const & args
Definition: min_max.h:83
constexpr T compose(Tuple tpl)
Definition: decompose.h:110
concept decomposable
Definition: decompose.h:81
EMLABCPP_GENERATE_DECOMPOSE(16, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) template< typename T > using decomposed_type
concept decomposable_0
Definition: decompose.h:101
constexpr std::tuple decompose(T &&)
Definition: decompose.h:104
Definition: decompose.h:41