eswitch-v5
Advanced counterpart for switch statement in C++
eswitch_v5.hpp
Go to the documentation of this file.
1 
4 // Copyright (c) 2019-present Rustam Abdumalikov
5 //
6 // "eswitch_v5" library
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See
9 // accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11 
12 #pragma once
13 
14 #include <tuple>
15 #include <array>
16 #include <cassert>
17 #include <type_traits>
18 #include <optional>
19 #include <concepts>
20 #include <any>
21 #include <variant>
22 #include <regex>
23 #include <algorithm>
24 
25 // Add static assert if fallthrough and lambda with args were used
26 
27 namespace eswitch_v5
28 {
31 
32  template< typename T >
33  concept Index = requires( T ){ std::decay_t< T >::eswitch_index; };
34 
35  template< typename T >
36  concept NoneIndex = ( Index< T > == false );
37 
38  template< typename T >
39  concept Condition = requires( T t )
40  {
41  t( std::make_tuple() );
42  std::decay_t< T >::template is_out_of_range< std::size_t{} >();
43  };
45 
48 
49  enum class Logical_operators{ and_, or_ };
52 
53  template< Comparison_operators, Index, typename >
54  class condition;
55 
56  template< typename, std::size_t ... >
58 
59  template< typename T >
60  struct is;
61 
62  namespace extension
63  {
66 
67  enum class range{ open, close };
68 
69  template< range RangeType >
70  class Range
71  {
72  std::size_t start_;
73  std::size_t end_;
74 
75  public:
76  constexpr Range( const std::size_t start, const std::size_t end )
77  : start_( start ), end_( end )
78  {
79  }
80 
81  friend constexpr bool operator==( const std::size_t val, const Range rm )
82  {
83  if constexpr( RangeType == range::close )
84  return val >= rm.start_ && val <= rm.end_;
85  else
86  return val > rm.start_ && val < rm.end_;
87  }
88  };
89 
90  struct any
91  {
92  template< typename T >
93  friend constexpr bool operator==( const T&, const any& ) {
94  return true;
95  }
96 
97  template< typename T >
98  friend constexpr bool operator!=( const T&, const any& ) {
99  return false;
100  }
101  };
102 
103  template< typename T, std::size_t Sz >
105  {
107 
108  template< typename ... Args >
109  constexpr Any_from_impl( Args &&... args )
110  : anythings{ std::forward< Args >( args )... }
111  {
112  }
113 
114  template< typename T_ >
115  inline friend constexpr bool operator==( const T_ & value, const Any_from_impl& st )
116  {
117  #ifdef __cpp_lib_ranges
118  return std::ranges::find( st.anythings, value ) != std::end( st.anythings );
119  #else
120  return std::find( std::begin( st.anythings ), std::end( st.anythings ), value ) != std::end( st.anythings );
121  #endif
122  }
123  };
125 
128 
129  template< typename ... Args >
130  Any_from_impl( Args &&... ) -> Any_from_impl< std::common_type_t< std::decay_t< Args >... >, sizeof...( Args ) >;
132  }
133 
136 
140  template< std::size_t Idx >
141  struct Index_
142  {
145  static constexpr std::size_t eswitch_index = Idx;
146 
150  auto between( const std::size_t start, const std::size_t end ) const
151  {
152  using namespace extension;
153 
154  using Rng_t = Range< range::open >;
155  return condition< Comparison_operators::equal, Index_< Idx >, Rng_t >( Rng_t( start, end ) );
156  }
157 
161  auto within( const std::size_t start, const std::size_t end ) const
162  {
163  using namespace extension;
164 
165  using Rng_t = Range< range::close >;
166  return condition< Comparison_operators::equal, Index_< Idx >, Rng_t >( Rng_t( start, end ) );
167  }
168  };
170 
173 
174  constexpr Index_< 0 > _1; constexpr Index_< 10 > _11; constexpr Index_< 20 > _21;
175  constexpr Index_< 1 > _2; constexpr Index_< 11 > _12; constexpr Index_< 21 > _22;
176  constexpr Index_< 2 > _3; constexpr Index_< 12 > _13; constexpr Index_< 22 > _23;
177  constexpr Index_< 3 > _4; constexpr Index_< 13 > _14; constexpr Index_< 23 > _24;
178  constexpr Index_< 4 > _5; constexpr Index_< 14 > _15; constexpr Index_< 24 > _25;
179  constexpr Index_< 5 > _6; constexpr Index_< 15 > _16; constexpr Index_< 25 > _26;
180  constexpr Index_< 6 > _7; constexpr Index_< 16 > _17; constexpr Index_< 26 > _27;
181  constexpr Index_< 7 > _8; constexpr Index_< 17 > _18; constexpr Index_< 27 > _28;
182  constexpr Index_< 8 > _9; constexpr Index_< 18 > _19; constexpr Index_< 28 > _29;
183  constexpr Index_< 9 > _10; constexpr Index_< 19 > _20; constexpr Index_< 29 > _30;
185 
186  namespace details
187  {
190 
191  template< typename T >
193 
194  template< Comparison_operators Op, Index I >
195  struct is_default_case< condition< Op, I, extension::any > > : std::true_type {};
196 
197  template< typename T >
199 
200  template< typename T >
201  constexpr std::false_type is_std_variant( T && );
202 
203  template< typename ... Ts >
205 
206  template< typename T >
207  constexpr bool is_std_variant_v = decltype( is_std_variant( std::declval< std::decay_t< T > >() ) )();
208 
209  template< typename T >
211 
212  template< template< typename T1, typename T2 > class Pair, typename T1, typename T2 >
213  struct is_std_pair< Pair< T1, T2 > > :
214  std::conditional_t< std::is_same_v< Pair< T1, T2 >, std::pair< T1, T2 > >,
215  std::true_type, std::false_type >
216  {};
217 
218  template< typename T >
220 
221  template< typename T >
223 
224  template< template< typename ... Ts > class Tuple, typename ... Ts >
225  struct is_std_tuple< Tuple< Ts... > > :
226  std::conditional_t< std::is_same_v< Tuple< Ts... >, std::tuple< Ts... > >,
227  std::true_type, std::false_type >
228  {};
229 
230  template< typename T >
232 
233  template< typename T >
234  constexpr bool is_std_any_v = std::is_same_v< std::decay_t< T >, std::any >;
235 
236  template< typename T >
238 
239  template< typename R, typename C, typename ... Args >
240  struct is_callable_impl< R(C::*)(Args...) const > : std::true_type {};
241 
242  template< typename R, typename C, typename ... Args >
243  struct is_callable_impl< R(C::*)(Args...) > : std::true_type {};
244 
245  template< typename T >
246  constexpr bool is_callable_v = is_callable_impl< decltype( &T::operator() ) >::value;
247 
248  inline static constexpr bool unreachable()
249  {
250  if( !std::is_constant_evaluated() ) assert( false );
251 
252  return false;
253  }
254 
255  template< typename T >
257 
258  template< template< typename, std::size_t ... > class C, typename T, std::size_t ... Is >
259  struct is_predicate< C< T, Is... > >
261  std::is_same_v< C<T, Is... >, predicate_condition< T, Is... > >,
262  std::true_type, std::false_type >
263  {
264  };
265 
266  template< typename T >
268 
269  template< typename T >
271  {
272  };
273 
274  template< typename R, typename C, typename ... Args >
275  struct amount_args_function_has< R(C::*)(Args...) const >
276  {
277  static constexpr std::size_t value = sizeof...( Args );
278  using type = R;
279  };
280 
281  template< typename R, typename C, typename ... Args >
282  struct amount_args_function_has< R(C::*)(Args...) >
283  {
284  static constexpr std::size_t value = sizeof...( Args );
285  using type = R;
286  };
287 
288  template< typename T, typename = void >
289  struct amount_args{};
290 
291  template< typename T >
292  struct amount_args< T, std::void_t< decltype( &T::operator() ) > >
293  {
294  constexpr static auto value = amount_args_function_has< decltype( &T::operator() ) >::value;
295  };
296 
297  template< typename T >
299 
300  template< typename T, typename = void >
301  struct invoke_result {};
302 
303  template< typename T >
304  struct invoke_result< T, std::void_t< decltype( &T::operator() ) > >
305  {
306  using type = typename amount_args_function_has< decltype( &T::operator() ) >::type;
307  };
308 
309  template< typename T >
311 
312  template< typename ... Ts >
314  {
315  static constexpr bool value = false;
316  };
317 
318  template< typename ... TupleCnds, typename Cnd, typename ... Cnds >
319  constexpr auto move_default_case_to_the_end_impl( std::tuple< TupleCnds... > && tup, Cnd && cnd, Cnds &&...cnds )
320  {
321  if constexpr( is_default_case_v< decltype( std::declval< Cnd >().cnd ) > )
322  {
323  return std::tuple_cat( std::move( tup ),
325  std::forward< Cnds >( cnds )...,
326  std::forward< Cnd >( cnd ) ) );
327  }
328  else if constexpr( sizeof...( Cnds ) > 0 )
329  {
331  std::tuple_cat( std::move( tup ), std::make_tuple( std::forward< Cnd >( cnd ) ) ),
332  std::forward< Cnds >( cnds )... );
333  }
334  else
335  {
336  return std::tuple_cat( std::move( tup ), std::make_tuple( std::forward< Cnd >( cnd ) ) );
337  }
338  }
339 
340  template< typename ... Cnds >
341  constexpr auto move_default_case_to_the_end( Cnds &&... cnds )
342  {
344  std::forward< Cnds >( cnds )... );
345  }
346 
347  template< std::size_t ... Is, typename Tup >
348  inline static constexpr auto create_indexed_condition( Tup && values )
349  {
350  auto combine = []< typename T1, typename T2 >( T1 && t1, T2 && t2 )
351  {
352  if constexpr( Condition< T2 > && Index< T1 > )
353  {
354  static_assert( T1::eswitch_index == T2::idx::eswitch_index, "Wrong Index!" );
355  return std::forward< T2 >( t2 );
356  }
357  else
358  return std::forward< T1 >( t1 ) == std::forward< T2 >( t2 );
359  };
360 
361  return ( combine( Index_< Is >{}, std::get< Is >( std::move( values ) ) ) && ... );
362  }
364  } // namespace details
365 
368 
369  template< typename T >
370  concept has_type = requires{ typename T::type; };
371 
372  template< typename T >
373  concept has_value = requires{ T::value; };
374 
375  template< typename T >
377  !details::is_std_any_v< T > ||
378  !details::is_std_variant_v< T > ||
379  requires( T a, T b ) {
380  { a == b };
381  { a != b };
382  };
383 
384  template< typename T >
387  void
388  >;
389  template< typename T >
390  concept IsCndPredicate = details::is_predicate_v< std::decay_t< T > >;
391 
392  template< typename T >
393  concept IsNotCndPredicate = !IsCndPredicate< T >;
394 
395  template< typename T >
396  concept Callable = details::is_callable_v< T >;
397 
398  template< typename T >
399  concept StdTuple = details::is_std_tuple_v< T >;
400 
401  template< typename T >
402  concept StdPair = details::is_std_pair_v< T >;
404 
405 
408 
409  struct regexter { std::regex value; };
410 
413  inline static auto operator==( const std::string & tuple_entry, const regexter & value )
414  {
415  if( std::smatch match; std::regex_match( tuple_entry, match, value.value ) )
416  {
418  vs.reserve( match.size() );
419 
420  for( const auto & v : match )
421  vs.push_back( v );
422 
423  return std::make_optional( std::move( vs ) );
424  }
425 
427  }
428 
431  template< typename TupleEntry, typename UnderlyingType >
432  inline static constexpr auto operator==( TupleEntry && tuple_entry, const is< UnderlyingType > & ) noexcept
433  {
435 
437  const UnderlyingType, UnderlyingType >;
438 
439  if constexpr( std::is_pointer_v< _T > )
440  {
441  auto * d = dynamic_cast< type* >( tuple_entry );
442 
443  return d != nullptr ? std::make_optional( d ) : std::optional< type* >{};
444  }
445  else
446  {
447  try
448  {
449  auto & d = dynamic_cast< type& >( tuple_entry );
450  return std::make_optional( std::ref( d ) );
451  }
452  catch( const std::bad_cast & )
453  {
455  }
456  }
457  }
458 
461  template< typename TupleEntry, typename UnderlyingType >
462  inline static constexpr auto operator==( TupleEntry && tuple_entry, const is< UnderlyingType > & ) noexcept
463  requires details::is_std_any_v< TupleEntry >
464  {
465  if( auto * val = std::any_cast< UnderlyingType >( &tuple_entry ) )
466  {
467  return std::make_optional( std::cref( *val ) );
468  }
469 
471  }
472 
475  template< typename TupleEntry, typename UnderlyingType >
476  inline static constexpr auto operator==( TupleEntry && tuple_entry, const is< UnderlyingType > & ) noexcept
477  requires details::is_std_variant_v< TupleEntry >
478  {
479  if( auto * val = std::get_if< UnderlyingType >( &tuple_entry ) )
480  {
481  return std::make_optional( std::cref( *val ) );
482  }
483 
485  }
487 
490 
491  template< typename T, typename U >
492  concept EqualityComparable =
493  requires( T a, U b )
494  { a == b; };
496 
499 
501  template< Comparison_operators CmpOperator, Index TIndex, typename CaseEntry >
502  class condition
503  {
504  template< Comparison_operators, Index, typename >
505  friend class condition;
506 
507  CaseEntry value_;
508  public:
509 
510  using value_type = CaseEntry;
511  using idx = TIndex;
512 
513  template< typename Arg >
514  constexpr condition( Arg && value )
515  : value_( std::forward< Arg >( value ) )
516  {
517  }
518 
519  template< StdTuple TSrcTuple >
520  inline constexpr auto operator()( const TSrcTuple & src_tuple ) const
521  {
522  static_assert( !is_out_of_range< std::tuple_size_v< TSrcTuple > >(),
523  "Case Index is OUT OF RANGE" );
524 
525  return compare( std::get< TIndex::eswitch_index >( src_tuple ), value_ );
526  }
527 
528  template< StdTuple TSrcTuple >
529  inline constexpr bool operator()( const TSrcTuple & src_tuple ) const
530  requires ( std::tuple_size_v< std::decay_t< TSrcTuple > > == 0 )
531  {
532  return false;
533  }
534 
535  template< std::size_t MaxIndex >
536  static constexpr bool is_out_of_range()
537  {
538  return TIndex::eswitch_index >= MaxIndex;
539  }
540 
541  private:
542 
543  template< typename TupleEntry >
544  inline static constexpr auto compare( TupleEntry && t1, const CaseEntry & t2 )
545  requires EqualityComparable< decltype( t1 ), decltype( t2 ) >
546  {
547  switch( CmpOperator )
548  {
550  {
551  if constexpr( requires{ t1 == t2; } ) return t1 == t2;
552  }
554  {
555  if constexpr( requires{ t1 != t2; } ) return t1 != t2;
556  }
558  {
559  if constexpr( requires{ t1 > t2; } ) return t1 > t2;
560  }
562  {
563  if constexpr( requires{ t1 >= t2; } ) return t1 >= t2;
564  }
566  {
567  if constexpr( requires{ t1 < t2; } ) return t1 < t2;
568  }
570  {
571  if constexpr( requires{ t1 <= t2; } ) return t1 <= t2;
572  }
573  };
574  }
575 
576  template< typename T1, typename T2 >
577  inline static constexpr bool compare( T1 && t1, T2 && t2 )
578  {
579  static_assert( EqualityComparable< T1, T2 >, "Types are not COMPARABLE!" );
580 
581  return false;
582  }
583  };
584 
586  template< Logical_operators LogicalOperator, Condition ... Cnds >
588  {
589  template< Logical_operators, Condition ... >
590  friend class conditions;
591 
592  std::tuple< Cnds... > cnds_;
593  public:
594 
595  template< Condition ... OtherCnds, Condition Cnd >
596  constexpr conditions( conditions< LogicalOperator, OtherCnds... > && cnds, Cnd && cnd )
597  : cnds_( std::tuple_cat( std::move( cnds.cnds_ ), std::make_tuple( std::move( cnd ) ) ) )
598  {
599  }
600 
601  constexpr conditions( Cnds &&... cnds )
602  : cnds_( std::move( cnds )... )
603  {
604  }
605 
606  template< std::size_t MaxIndex >
607  static constexpr bool is_out_of_range()
608  {
609  return ( Cnds::template is_out_of_range< MaxIndex >() || ... );
610  }
611 
612  template< StdTuple TSrcTuple >
613  inline constexpr bool operator()( const TSrcTuple & src_tuple ) const
614  {
615  auto lmbd = [&]< typename T, T ... ints >( std::index_sequence< ints... > && )
616  {
617  return compare( static_cast< bool >( std::get< ints >( cnds_ )( src_tuple ) )... );
618  };
619 
620  return lmbd( std::make_index_sequence< sizeof...( Cnds ) >{} );
621  }
622 
623  private:
624 
625  inline static constexpr bool compare( const auto ... ts )
626  {
627  switch( LogicalOperator )
628  {
630  return ( ts && ... );
632  return ( ts || ... );
633  };
634  }
635  };
636 
637  template< Condition ... Cnds, Condition Cnd >
638  inline static constexpr auto operator&&( conditions< Logical_operators::and_, Cnds... > && cnds, Cnd && cnd )
639  {
640  return conditions< Logical_operators::and_, Cnds..., Cnd >(
641  std::move( cnds ), std::move( cnd ) );
642  }
643 
644  template< Condition Cnd1, Condition Cnd2 >
645  inline static constexpr auto operator&&( Cnd1 && cnd1, Cnd2 && cnd2 )
646  {
647  return conditions< Logical_operators::and_, Cnd1, Cnd2 >( std::move( cnd1 ), std::move( cnd2 ) );
648  }
649 
650  template< Condition ... Cnds, Condition Cnd >
651  inline static constexpr auto operator||( conditions< Logical_operators::or_, Cnds... > && cnds, Cnd && cnd )
652  {
653  return conditions< Logical_operators::or_, Cnds..., Cnd >(
654  std::move( cnds ), std::move( cnd ) );
655  }
656 
657  template< Condition Cnd1, Condition Cnd2 >
658  inline static constexpr auto operator||( Cnd1 && cnd1, Cnd2 && cnd2 )
659  {
660  return conditions< Logical_operators::or_, Cnd1, Cnd2 >( std::move( cnd1 ), std::move( cnd2 ) );
661  }
662 
663  template< Index Idx, typename T >
664  inline static constexpr auto operator==( Idx &&, T && rhv )
665  {
666  return condition< Comparison_operators::equal, std::decay_t< Idx >, T >( std::forward< T >( rhv ) );
667  }
668 
669  template< Index Idx, typename T >
670  constexpr auto operator!=( Idx &&, T && rhv )
671  {
672  return condition< Comparison_operators::not_equal, std::decay_t< Idx >, T >( std::forward< T >( rhv ) );
673  }
674 
675  template< Index Idx, typename T >
676  constexpr auto operator>( Idx &&, T && rhv )
677  {
678  return condition< Comparison_operators::greater, std::decay_t< Idx >, T >( std::forward< T >( rhv ) );
679  }
680 
681  template< Index Idx, typename T >
682  constexpr auto operator>=( Idx &&, T && rhv )
683  {
684  return condition< Comparison_operators::greater_or_equal, std::decay_t< Idx >, T >( std::forward< T >( rhv ) );
685  }
686 
687  template< Index Idx, typename T >
688  constexpr auto operator<( Idx &&, T && rhv )
689  {
690  return condition< Comparison_operators::less, std::decay_t< Idx >, T >( std::forward< T >( rhv ) );
691  }
692 
693  template< Index Idx, typename T >
694  constexpr auto operator<=( Idx &&, T && rhv )
695  {
696  return condition< Comparison_operators::less_or_equal, std::decay_t< Idx >, T >( std::forward< T >( rhv ) );
697  }
698 
703  template< typename ... Args >
705  {
706  static_assert( ( ComparableExceptAnyAndVariant<Args> && ... ), "Input Types should be COMPARABLE!" );
707 
708  std::tuple< const Args &... > tup_;
709  public:
710 
711  template< typename ... Ts >
712  constexpr eswitch_impl( Ts &&... ts ) : tup_( std::forward< Ts >( ts )... )
713  {
714  }
715 
716  template< typename T >
718 
719  template< typename T >
721 
722  template< typename T >
724 
725  template< typename ... Cnds >
726  inline constexpr auto operator()( Cnds && ... cnds )
727  {
728  if constexpr( ( !has_value< args_t< Cnds > > || ... ) )
729  {
730  static_assert( !( !has_value< args_t< Cnds > > || ... ),
731  "Predicate with 'auto' argument aren't ALLOWED!" );
732  }
733  else if constexpr( ( has_type< underlying< Cnds > > && ... ) )
734  {
735  static_assert( has_type< std::common_type< underlying_t< Cnds >... > >,
736  "Inconsistent 'Return type'!" );
737  }
738  }
739 
740  struct Padding {};
741 
742  template< typename ... Cnds >
743  inline constexpr auto operator()( Cnds && ... cnds ) requires has_type< std::common_type< underlying_t< Cnds >... > >
744  {
745  constexpr auto generic_lambda = []< typename T, T... ints >
746  ( std::index_sequence< ints... > && int_seq, auto && tup, auto && f )
747  {
748  ( f( std::get< ints >( tup ) ), ... );
749  };
750 
751  using return_t = std::common_type_t< underlying_t< Cnds >... >;
752 
753  constexpr auto has_return_value = !std::is_same_v< return_t, void >;
754 
756  > return_value;
757 
758  generic_lambda(
759  std::make_index_sequence< sizeof...( Cnds ) >{},
760  details::move_default_case_to_the_end( std::forward< Cnds >( cnds )... ),
761  [ this, &return_value, fallthrough = std::optional< bool >{} ]( const auto & cnd ) mutable
762  {
763  using namespace details;
764 
765  if( fallthrough && !( *fallthrough ) ) return;
766 
767  constexpr auto amount_args = amount_args_v< decltype( cnd.func ) >;
768 
769  if constexpr( amount_args == 0 )
770  {
771  if( fallthrough && *fallthrough )
772  {
773  cnd.func();
774 
775  fallthrough = cnd.fallthrough;
776 
777  return;
778  }
779  }
780 
781  auto res = cnd.cnd( tup_ );
782 
783  if( !res ) return;
784 
785  if constexpr( amount_args == 1 && !std::is_same_v< decltype( res ), bool > )
786  {
787  if constexpr( has_return_value )
788  {
789  return_value = static_cast< return_t >( cnd.func( std::move( *res ) ) );
790  }
791  else
792  {
793  cnd.func( std::move( *res ) );
794  }
795  }
796  else if constexpr( amount_args == 0 )
797  {
798  if constexpr( has_return_value )
799  {
800  return_value = static_cast< return_t >( cnd.func() );
801  }
802  else
803  {
804  cnd.func();
805  }
806  }
807  else
808  {
809  unreachable();
810  }
811 
812  fallthrough = cnd.fallthrough;
813  });
814 
815  if constexpr( has_return_value )
816  {
817  return return_value.value();
818  }
819  }
820  };
822 
825 
826  template< typename ... Ts >
827  eswitch_impl( Ts &&... ) -> eswitch_impl< Ts... >;
829 
832 
837  template< typename ... Ts >
838  inline static constexpr auto eswitch( Ts && ... ts )
839  {
840  return eswitch_impl( std::forward< Ts >( ts )... );
841  }
842 
847  template< StdPair T >
848  inline static constexpr auto eswitch( T && pair )
849  {
850  if constexpr( std::is_rvalue_reference_v< T&& > )
851  {
852  return eswitch_impl( std::move( pair.first ), std::move( pair.second ) );
853  }
854  else
855  {
856  return eswitch_impl( pair.first, pair.second );
857  }
858  }
859 
860  template< StdTuple T >
861  inline static constexpr auto eswitch( T && tup )
862  {
863  auto expand_tuple = [] < typename _T, _T ... ints >
864  ( std::index_sequence< ints... > &&, const auto & tup )
865  {
866  return eswitch_impl( std::get< ints >( tup )... );
867  };
868 
869  return expand_tuple( std::make_index_sequence< std::tuple_size_v< std::decay_t< T > > >{}, tup );
870  }
871 
872  template< Condition Cnd, Callable Func >
874  {
875  using F = Func;
876 
877  Cnd cnd;
878  Func func;
879  bool fallthrough = false;
880  };
882 
885 
886  template< typename T, typename F >
889 
892 
893  template< Condition T, Callable Func >
894  inline static constexpr auto operator%( T && cnd, Func && f )
895  {
896  return condition_with_predicate{ std::move( cnd ), std::move( f ) };
897  }
898 
899  struct Fallthrough {};
900 
901  template< typename Cnd, ReturnValueNoneVoid Func >
902  inline static constexpr auto operator^( condition_with_predicate< Cnd, Func >&& cp, const Fallthrough & )
903  {
904  cp.fallthrough = true;
905 
906  return std::move( cp );
907  }
908 
909  template< typename TPred, std::size_t ... Is >
910  class predicate_condition
911  {
912  public:
913 
914  TPred pred_;
915 
916  template< typename T >
917  constexpr predicate_condition( T && pred )
918  : pred_( std::forward< T >( pred ) )
919  {
920  }
921 
922  template< StdTuple TSrcTuple >
923  constexpr bool operator()( const TSrcTuple & src_tuple ) const
924  {
925  static_assert( !is_out_of_range< std::tuple_size_v< TSrcTuple > >(),
926  "Case Index is OUT OF RANGE" );
927 
928  return pred_( std::get< Is >( src_tuple )... );
929  }
930 
931  template< std::size_t MaxIndex >
932  static constexpr bool is_out_of_range()
933  {
934  constexpr std::array< bool, sizeof...( Is ) > list{ ( Is >= MaxIndex )... };
935 
936  return std::find( std::begin( list ), std::end( list ), true ) != std::end( list );
937  }
938  };
939 
940  template< typename R, typename... Args, Index Idx >
941  inline static constexpr auto operator,( R(*pred)(Args...), Idx )
942  {
943  return predicate_condition< R(*)(Args...), Idx::eswitch_index >( pred );
944  }
945 
946  template< IsNotCndPredicate Pred, Index Idx >
947  inline static constexpr auto operator,( Pred && pred, Idx )
948  {
949  return predicate_condition< std::remove_reference_t< Pred >, Idx::eswitch_index >(
950  std::forward< Pred >( pred ) );
951  }
952 
953  template < typename P, std::size_t ... I, Index Idx >
954  predicate_condition< P, I..., Idx::eswitch_index >
955  compose_new_predicate_condition_type( const predicate_condition< P, I... > &, Idx );
956 
957  template< IsCndPredicate Pred, Index Idx >
958  inline static constexpr auto operator,( Pred && pred, Idx idx )
959  {
960  return decltype( compose_new_predicate_condition_type( pred, idx ) )( std::move( pred.pred_ ) );
961  }
963 
966 
967  template< Condition Cnd >
968  inline static constexpr auto case_( Cnd && cnd )
969  {
970  return std::move( cnd );
971  }
972 
973  template< typename ... Ts >
974  inline static constexpr auto case_( Ts &&... values )
975  {
976  auto lmbd = []< typename T, T ... ints >( std::index_sequence< ints... >&&, auto &&... values )
977  {
978  // I intentionally avoided std::make_tuple, because the former change type of string literals
979  // from "const char[some_size]&" to "const char*" and this significantly impacts the performance.
980  return details::create_indexed_condition< ints... >(
981  std::tuple< Ts... >( std::forward< Ts >( values )... ) );
982  };
983 
984  return lmbd( std::make_index_sequence< sizeof...(Ts) >{},
985  std::forward< Ts >( values )... );
986  }
987 
990  template< typename ... Args >
991  inline static constexpr auto any_from( Args &&... args )
992  {
993  return extension::Any_from_impl( std::forward< Args >( args )... );
994  }
995 
998  template< typename T >
999  struct is
1000  {
1001  using type = T;
1002  };
1003 
1005  auto operator ""_r( const char * rgx, const std::size_t sz )
1006  {
1007  return regexter{ std::regex{ rgx } };
1008  }
1010 
1013 
1016  static constexpr Fallthrough fallthrough_;
1017 
1019  static constexpr extension::any _;
1021 
1024 
1026  #define Case( ... ) case_( __VA_ARGS__ ) % [&]
1027 
1029  #define Default ( _1 == extension::any{} ) % [&]
1030 
1032 
1033 } // namespace eswitch_v5
eswitch_v5::extension::any::operator!=
constexpr friend bool operator!=(const T &, const any &)
Definition: eswitch_v5.hpp:98
eswitch_v5::_9
constexpr Index_< 8 > _9
Definition: eswitch_v5.hpp:182
std::is_same_v
T is_same_v
std::make_tuple
T make_tuple(T... args)
std::false_type
eswitch_v5::IsNotCndPredicate
concept IsNotCndPredicate
Definition: eswitch_v5.hpp:393
eswitch_v5::condition::operator()
constexpr auto operator()(const TSrcTuple &src_tuple) const
Definition: eswitch_v5.hpp:520
regex
eswitch_v5::_1
constexpr Index_< 0 > _1
Definition: eswitch_v5.hpp:174
eswitch_v5::predicate_condition::is_out_of_range
static constexpr bool is_out_of_range()
Definition: eswitch_v5.hpp:932
eswitch_v5::Comparison_operators
Comparison_operators
Definition: eswitch_v5.hpp:50
std::string
STL class.
eswitch_v5::details::invoke_result_t
typename invoke_result< T >::type invoke_result_t
Definition: eswitch_v5.hpp:310
eswitch_v5::Callable
concept Callable
Definition: eswitch_v5.hpp:396
eswitch_v5::eswitch_impl::eswitch_impl
constexpr eswitch_impl(Ts &&... ts)
Definition: eswitch_v5.hpp:712
eswitch_v5::details::unreachable
static constexpr bool unreachable()
Definition: eswitch_v5.hpp:248
eswitch_v5::operator||
static constexpr auto operator||(conditions< Logical_operators::or_, Cnds... > &&cnds, Cnd &&cnd)
Definition: eswitch_v5.hpp:651
eswitch_v5::details::move_default_case_to_the_end_impl
constexpr auto move_default_case_to_the_end_impl(std::tuple< TupleCnds... > &&tup, Cnd &&cnd, Cnds &&...cnds)
Definition: eswitch_v5.hpp:319
eswitch_v5::_4
constexpr Index_< 3 > _4
Definition: eswitch_v5.hpp:177
eswitch_v5::operator%
static constexpr auto operator%(T &&cnd, Func &&f)
Definition: eswitch_v5.hpp:894
eswitch_v5::details::is_std_variant_v
constexpr bool is_std_variant_v
Definition: eswitch_v5.hpp:207
eswitch_v5::details::is_callable_impl
Definition: eswitch_v5.hpp:237
eswitch_v5::operator,
static constexpr auto operator,(R(*pred)(Args...), Idx)
Definition: eswitch_v5.hpp:941
eswitch_v5::has_type
concept has_type
Definition: eswitch_v5.hpp:370
std::vector::reserve
T reserve(T... args)
eswitch_v5::Index_
This structure is used as a reference to a specific parameter inside eswitch.
Definition: eswitch_v5.hpp:141
std::index_sequence
eswitch_v5::conditions::operator()
constexpr bool operator()(const TSrcTuple &src_tuple) const
Definition: eswitch_v5.hpp:613
eswitch_v5::condition::condition
constexpr condition(Arg &&value)
Definition: eswitch_v5.hpp:514
eswitch_v5::regexter::value
std::regex value
Definition: eswitch_v5.hpp:409
eswitch_v5::is::type
T type
Definition: eswitch_v5.hpp:1001
std::vector
STL class.
std::find
T find(T... args)
eswitch_v5::details::amount_args_v
constexpr std::size_t amount_args_v
Definition: eswitch_v5.hpp:298
eswitch_v5::details::invoke_result
Definition: eswitch_v5.hpp:301
std::make_optional
T make_optional(T... args)
eswitch_v5::Index_::eswitch_index
static constexpr std::size_t eswitch_index
Refer to some element in std::tuple( where eswitch keep all the parameters ).
Definition: eswitch_v5.hpp:145
eswitch_v5::fallthrough_
static constexpr Fallthrough fallthrough_
Indicates fall through from previous Case without testing condition of following Case.
Definition: eswitch_v5.hpp:1016
eswitch_v5::_13
constexpr Index_< 12 > _13
Definition: eswitch_v5.hpp:176
eswitch_v5::StdPair
concept StdPair
Definition: eswitch_v5.hpp:402
eswitch_v5::condition_with_predicate
Definition: eswitch_v5.hpp:873
eswitch_v5::extension::Any_from_impl::Any_from_impl
constexpr Any_from_impl(Args &&... args)
Definition: eswitch_v5.hpp:109
eswitch_v5::predicate_condition::operator()
constexpr bool operator()(const TSrcTuple &src_tuple) const
Definition: eswitch_v5.hpp:923
std::common_type
eswitch_v5::has_value
concept has_value
Definition: eswitch_v5.hpp:373
eswitch_v5::operator>=
constexpr auto operator>=(Idx &&, T &&rhv)
Definition: eswitch_v5.hpp:682
eswitch_v5::extension::Any_from_impl
Definition: eswitch_v5.hpp:104
eswitch_v5::_5
constexpr Index_< 4 > _5
Definition: eswitch_v5.hpp:178
std::regex_match
T regex_match(T... args)
tuple
eswitch_v5::details::move_default_case_to_the_end
constexpr auto move_default_case_to_the_end(Cnds &&... cnds)
Definition: eswitch_v5.hpp:341
eswitch_v5::_3
constexpr Index_< 2 > _3
Definition: eswitch_v5.hpp:176
eswitch_v5::ReturnValueNoneVoid
concept ReturnValueNoneVoid
Definition: eswitch_v5.hpp:385
eswitch_v5::extension::range::close
@ close
eswitch_v5::details::is_std_tuple_v
constexpr bool is_std_tuple_v
Definition: eswitch_v5.hpp:231
eswitch_v5::condition_with_predicate::func
Func func
Definition: eswitch_v5.hpp:878
eswitch_v5::_20
constexpr Index_< 19 > _20
Definition: eswitch_v5.hpp:183
eswitch_v5::details::is_predicate
Definition: eswitch_v5.hpp:256
any
eswitch_v5::operator<=
constexpr auto operator<=(Idx &&, T &&rhv)
Definition: eswitch_v5.hpp:694
eswitch_v5::condition
Compares value with corresponding entry in std::tuple.
Definition: eswitch_v5.hpp:54
eswitch_v5::Logical_operators::or_
@ or_
eswitch_v5::_6
constexpr Index_< 5 > _6
Definition: eswitch_v5.hpp:179
eswitch_v5::details::amount_args_function_has< R(C::*)(Args...) >::type
R type
Definition: eswitch_v5.hpp:285
eswitch_v5::_24
constexpr Index_< 23 > _24
Definition: eswitch_v5.hpp:177
eswitch_v5::extension::Any_from_impl::operator==
constexpr friend bool operator==(const T_ &value, const Any_from_impl &st)
Definition: eswitch_v5.hpp:115
algorithm
eswitch_v5::IsCndPredicate
concept IsCndPredicate
Definition: eswitch_v5.hpp:390
eswitch_v5::extension::Any_from_impl::anythings
std::array< T, Sz > anythings
Definition: eswitch_v5.hpp:106
eswitch_v5::details::invoke_result< T, std::void_t< decltype(&T::operator()) > >::type
typename amount_args_function_has< decltype(&T::operator()) >::type type
Definition: eswitch_v5.hpp:306
eswitch_v5::operator<
constexpr auto operator<(Idx &&, T &&rhv)
Definition: eswitch_v5.hpp:688
concepts
eswitch_v5::_14
constexpr Index_< 13 > _14
Definition: eswitch_v5.hpp:177
eswitch_v5::Comparison_operators::equal
@ equal
eswitch_v5::_25
constexpr Index_< 24 > _25
Definition: eswitch_v5.hpp:178
std::bad_cast
STL class.
eswitch_v5::_10
constexpr Index_< 9 > _10
Definition: eswitch_v5.hpp:183
std::vector::push_back
T push_back(T... args)
eswitch_v5::_29
constexpr Index_< 28 > _29
Definition: eswitch_v5.hpp:182
eswitch_v5::NoneIndex
concept NoneIndex
Definition: eswitch_v5.hpp:36
eswitch_v5::eswitch_impl
eswitch_impl(Ts &&...) -> eswitch_impl< Ts... >
eswitch_v5::Logical_operators
Logical_operators
Definition: eswitch_v5.hpp:49
eswitch_v5::StdTuple
concept StdTuple
Definition: eswitch_v5.hpp:399
eswitch_v5::case_
static constexpr auto case_(Cnd &&cnd)
Definition: eswitch_v5.hpp:968
eswitch_v5::Index_::within
auto within(const std::size_t start, const std::size_t end) const
Helper method which defines close set of integers. Then this set is used to determine whether certain...
Definition: eswitch_v5.hpp:161
eswitch_v5::is
Used to match for type of active entry in std::any, std::variant<...> and polymorphic types.
Definition: eswitch_v5.hpp:60
eswitch_v5::operator^
static constexpr auto operator^(condition_with_predicate< Cnd, Func > &&cp, const Fallthrough &)
Definition: eswitch_v5.hpp:902
eswitch_v5::predicate_condition::pred_
TPred pred_
Definition: eswitch_v5.hpp:914
eswitch_v5::predicate_condition::predicate_condition
constexpr predicate_condition(T &&pred)
Definition: eswitch_v5.hpp:917
eswitch_v5::any_from
static constexpr auto any_from(Args &&... args)
Helper function which allows to find if something is within the list( passed arguments ).
Definition: eswitch_v5.hpp:991
eswitch_v5::eswitch_impl::underlying_t
details::invoke_result_t< typename T::F > underlying_t
Definition: eswitch_v5.hpp:720
eswitch_v5::conditions::conditions
constexpr conditions(conditions< LogicalOperator, OtherCnds... > &&cnds, Cnd &&cnd)
Definition: eswitch_v5.hpp:596
eswitch_v5::extension::any::operator==
constexpr friend bool operator==(const T &, const any &)
Definition: eswitch_v5.hpp:93
eswitch_v5::_11
constexpr Index_< 10 > _11
Definition: eswitch_v5.hpp:174
eswitch_v5::condition_with_predicate::F
Func F
Definition: eswitch_v5.hpp:875
eswitch_v5::details::amount_args_function_has< R(C::*)(Args...) const >::type
R type
Definition: eswitch_v5.hpp:278
eswitch_v5::_16
constexpr Index_< 15 > _16
Definition: eswitch_v5.hpp:179
eswitch_v5::details::amount_args_function_has
Definition: eswitch_v5.hpp:270
eswitch_v5::Comparison_operators::not_equal
@ not_equal
eswitch_v5::_8
constexpr Index_< 7 > _8
Definition: eswitch_v5.hpp:181
eswitch_v5::eswitch_impl::Padding
Definition: eswitch_v5.hpp:740
eswitch_v5::Comparison_operators::greater
@ greater
eswitch_v5::_7
constexpr Index_< 6 > _7
Definition: eswitch_v5.hpp:180
array
eswitch_v5::details::is_std_variant
constexpr std::true_type is_std_variant(std::variant< Ts... > &&)
eswitch_v5::operator!=
constexpr auto operator!=(Idx &&, T &&rhv)
Definition: eswitch_v5.hpp:670
eswitch_v5::extension::Any_from_impl
Any_from_impl(Args &&...) -> Any_from_impl< std::common_type_t< std::decay_t< Args >... >, sizeof...(Args) >
eswitch_v5::details::is_std_tuple
Definition: eswitch_v5.hpp:222
eswitch_v5::Comparison_operators::greater_or_equal
@ greater_or_equal
eswitch_v5::details::is_std_pair
Definition: eswitch_v5.hpp:210
std::regex
eswitch_v5::_18
constexpr Index_< 17 > _18
Definition: eswitch_v5.hpp:181
eswitch_v5::extension::Range
Definition: eswitch_v5.hpp:70
eswitch_v5::extension::any
Definition: eswitch_v5.hpp:90
eswitch_v5::condition_with_predicate::cnd
Cnd cnd
Definition: eswitch_v5.hpp:877
std::decay_t
std::optional::value
T value(T... args)
eswitch_v5::condition::idx
TIndex idx
Definition: eswitch_v5.hpp:511
eswitch_v5::_27
constexpr Index_< 26 > _27
Definition: eswitch_v5.hpp:180
eswitch_v5::_30
constexpr Index_< 29 > _30
Definition: eswitch_v5.hpp:183
eswitch_v5::operator>
constexpr auto operator>(Idx &&, T &&rhv)
Definition: eswitch_v5.hpp:676
std::remove_reference_t
eswitch_v5::details::amount_args
Definition: eswitch_v5.hpp:289
eswitch_v5::details::is_default_case_v
constexpr bool is_default_case_v
Definition: eswitch_v5.hpp:198
eswitch_v5::Index
concept Index
Definition: eswitch_v5.hpp:33
eswitch_v5::condition::is_out_of_range
static constexpr bool is_out_of_range()
Definition: eswitch_v5.hpp:536
std::is_constant_evaluated
T is_constant_evaluated(T... args)
eswitch_v5::regexter
Definition: eswitch_v5.hpp:409
std::begin
T begin(T... args)
std
STL namespace.
cassert
eswitch_v5::extension::range::open
@ open
eswitch_v5::details::Always_false
Definition: eswitch_v5.hpp:313
eswitch_v5::details::is_std_pair_v
constexpr bool is_std_pair_v
Definition: eswitch_v5.hpp:219
eswitch_v5::conditions::conditions
constexpr conditions(Cnds &&... cnds)
Definition: eswitch_v5.hpp:601
std::invoke_result_t
eswitch_v5::eswitch_impl::operator()
constexpr auto operator()(Cnds &&... cnds)
Definition: eswitch_v5.hpp:726
eswitch_v5::eswitch_impl
Accept arbitrary number of Case's and test each of them sequentially. If match was found then execute...
Definition: eswitch_v5.hpp:704
eswitch_v5::details::is_callable_v
constexpr bool is_callable_v
Definition: eswitch_v5.hpp:246
eswitch_v5::condition::value_type
CaseEntry value_type
Definition: eswitch_v5.hpp:510
eswitch_v5::Comparison_operators::less
@ less
eswitch_v5::Condition
concept Condition
Definition: eswitch_v5.hpp:39
eswitch_v5::_22
constexpr Index_< 21 > _22
Definition: eswitch_v5.hpp:175
eswitch_v5::operator&&
static constexpr auto operator&&(conditions< Logical_operators::and_, Cnds... > &&cnds, Cnd &&cnd)
Definition: eswitch_v5.hpp:638
eswitch_v5::eswitch
static constexpr auto eswitch(Ts &&... ts)
This function is responsible for passing arguments for class eswitch_impl with overloaded operator(),...
Definition: eswitch_v5.hpp:838
optional
std::tuple_cat
T tuple_cat(T... args)
std::size_t
eswitch_v5::_
static constexpr extension::any _
Used in Case to match for any input.
Definition: eswitch_v5.hpp:1019
std::smatch
eswitch_v5::predicate_condition
Definition: eswitch_v5.hpp:57
std::end
T end(T... args)
eswitch_v5::Index_::between
auto between(const std::size_t start, const std::size_t end) const
Helper method which defines open set of integers. Then this set is used to determine whether certain ...
Definition: eswitch_v5.hpp:150
eswitch_v5::extension::range
range
Definition: eswitch_v5.hpp:67
eswitch_v5::operator==
static auto operator==(const std::string &tuple_entry, const regexter &value)
CaseModule to support for matching and withdrawing of values for and from regular expression.
Definition: eswitch_v5.hpp:413
eswitch_v5::_28
constexpr Index_< 27 > _28
Definition: eswitch_v5.hpp:181
std::conditional_t
eswitch_v5::conditions
Container which holds arbitrary number of condition.
Definition: eswitch_v5.hpp:587
eswitch_v5::ComparableExceptAnyAndVariant
concept ComparableExceptAnyAndVariant
Definition: eswitch_v5.hpp:376
eswitch_v5::details::is_predicate_v
constexpr bool is_predicate_v
Definition: eswitch_v5.hpp:267
eswitch_v5::details::is_std_any_v
constexpr bool is_std_any_v
Definition: eswitch_v5.hpp:234
eswitch_v5::condition::operator()
constexpr bool operator()(const TSrcTuple &src_tuple) const requires(std
Definition: eswitch_v5.hpp:529
eswitch_v5::details::is_default_case
Definition: eswitch_v5.hpp:192
eswitch_v5::_19
constexpr Index_< 18 > _19
Definition: eswitch_v5.hpp:182
eswitch_v5::compose_new_predicate_condition_type
predicate_condition< P, I..., Idx::eswitch_index > compose_new_predicate_condition_type(const predicate_condition< P, I... > &, Idx)
eswitch_v5::details::create_indexed_condition
static constexpr auto create_indexed_condition(Tup &&values)
Definition: eswitch_v5.hpp:348
eswitch_v5::_23
constexpr Index_< 22 > _23
Definition: eswitch_v5.hpp:176
eswitch_v5::_12
constexpr Index_< 11 > _12
Definition: eswitch_v5.hpp:175
eswitch_v5
Definition: eswitch_v5.hpp:27
eswitch_v5::Comparison_operators::less_or_equal
@ less_or_equal
eswitch_v5::_26
constexpr Index_< 25 > _26
Definition: eswitch_v5.hpp:179
eswitch_v5::condition_with_predicate
condition_with_predicate(T, F) -> condition_with_predicate< T, F >
eswitch_v5::_21
constexpr Index_< 20 > _21
Definition: eswitch_v5.hpp:174
eswitch_v5::_15
constexpr Index_< 14 > _15
Definition: eswitch_v5.hpp:178
eswitch_v5::_17
constexpr Index_< 16 > _17
Definition: eswitch_v5.hpp:180
type_traits
eswitch_v5::Fallthrough
Definition: eswitch_v5.hpp:899
eswitch_v5::conditions::is_out_of_range
static constexpr bool is_out_of_range()
Definition: eswitch_v5.hpp:607
std::declval
T declval(T... args)
std::ref
T ref(T... args)
std::tuple_size_v
T tuple_size_v
eswitch_v5::extension::Range::Range
constexpr Range(const std::size_t start, const std::size_t end)
Definition: eswitch_v5.hpp:76
eswitch_v5::_2
constexpr Index_< 1 > _2
Definition: eswitch_v5.hpp:175
eswitch_v5::Logical_operators::and_
@ and_
variant
eswitch_v5::extension::Range::operator==
constexpr friend bool operator==(const std::size_t val, const Range rm)
Definition: eswitch_v5.hpp:81