fork download
  1. #include <iostream>
  2. #include <tuple>
  3. #include <utility>
  4. #include <type_traits>
  5. #include <functional>
  6. #include <vector>
  7.  
  8. /*template <typename T>
  9. struct xrange {
  10.  
  11.  
  12. };*/
  13.  
  14. struct to_t { };
  15. const auto to = to_t();
  16.  
  17. struct until_t { };
  18. const auto until = until_t();
  19.  
  20. template <typename T>
  21. struct set_build {
  22. std::vector<T> items;
  23.  
  24. set_build () {
  25.  
  26. }
  27.  
  28. set_build ( std::vector<T> build ) : items(std::move(build)) {
  29.  
  30. }
  31.  
  32. typename std::vector<T>::iterator begin () {
  33. return std::begin( items );
  34. }
  35.  
  36. typename std::vector<T>::iterator end () {
  37. return std::end( items );
  38. }
  39.  
  40. typename std::vector<T>::const_iterator begin () const {
  41. return std::begin( items );
  42. }
  43.  
  44. typename std::vector<T>::const_iterator end () const {
  45. return std::end( items );
  46. }
  47.  
  48. template <typename TFx>
  49. set_build<T> operator& ( TFx&& fx ) {
  50. std::vector<T> filtered;
  51. filtered.reserve( items.size() );
  52. for ( auto&& item : items ) {
  53. if ( fx( item ) )
  54. filtered.emplace_back( item );
  55. }
  56. items = std::move( filtered );
  57. return *this;
  58. }
  59.  
  60. };
  61.  
  62. template <typename TFx, typename T>
  63. set_build<T> operator| ( TFx&& fx, const set_build<T>& set ) {
  64. std::vector<T> comprehension;
  65. comprehension.reserve( set.items.size() );
  66. for ( auto& item : set ) {
  67. comprehension.emplace_back( fx( item ) );
  68. }
  69. return set_build<T>( std::move( comprehension ) );
  70. }
  71.  
  72. template <typename T, typename T0, typename T1 = T0, typename TDiff = decltype( std::declval<T1>() - std::declval<T0>() )>
  73. set_build<T> make_specific ( T0&& n0, const to_t&, T1&& n1, TDiff&& ndiff = static_cast<TDiff>(1) ) {
  74. std::vector<T> items;
  75. if ( n0 == n1 || ndiff == static_cast<TDiff>( 0 ) )
  76. return set_build<T>( std::move( items ) );
  77.  
  78. T c0 = n0;
  79.  
  80. if ( n0 < n1 ) {
  81. if ( ndiff < static_cast<TDiff>( 0 ) )
  82. return set_build<T>( std::move( items ) );
  83.  
  84. while ( c0 <= n1 ) {
  85. items.emplace_back( c0 );
  86. c0 += ndiff;
  87. }
  88. }
  89. else {
  90. if ( ndiff > static_cast<TDiff>( 0 ) )
  91. return set_build<T>( std::move( items ) );
  92.  
  93. while ( c0 >= n1 ) {
  94. items.emplace_back( c0 );
  95. c0 += ndiff;
  96. }
  97. }
  98.  
  99. return set_build<T>( std::move( items ) );
  100. }
  101.  
  102. template <typename T0, typename T1 = T0>
  103. set_build<T0> make ( T0&& n0, T1&& n1 ) {
  104. return make_specific<T0, T0, T1>( std::forward<T0>( n0 ), to, std::forward<T1>( n1 ) );
  105. }
  106.  
  107. template <typename T0, typename T1 = T0, typename TDiff = decltype( std::declval<T1>() - std::declval<T0>() )>
  108. set_build<T0> make ( T0&& n0, const to_t&, T1&& n1, TDiff&& ndiff = static_cast<TDiff>(1) ) {
  109. return make_specific<T0, T0, T1, TDiff>( std::forward<T0>( n0 ), to, std::forward<T1>( n1 ), std::forward<TDiff>( ndiff ) );
  110. }
  111.  
  112. template <typename T, typename T0, typename T1 = T0, typename TLim = T0>
  113. set_build<T> make_specific ( T0&& n0, T1&& n1, const until_t&, TLim&& nlim ) {
  114. typedef decltype( std::declval<T1>() - std::declval<T0>() ) TDiff;
  115. TDiff ndiff = n1 - n0;
  116. return make_specific<T, T0, TLim, TDiff>( std::forward<T0>( n0 ), to, std::forward<TLim>( nlim ), std::forward<TDiff>( ndiff ) );
  117. }
  118.  
  119. template <typename T0, typename T1 = T0, typename TLim = T0>
  120. set_build<T0> make ( T0&& n0, T1&& n1, const until_t&, TLim&& nlim ) {
  121. return make_specific<T0, T0, T1, TLim>( std::forward<T0>( n0 ), std::forward<T1>( n1 ), until, std::forward<TLim>( nlim ) );
  122. }
  123.  
  124. template <typename T0, typename T1 = T0, typename TLim = T0>
  125. set_build<T0> make ( T0&& n0, T1&& n1, TLim&& nlim ) {
  126. return make_specific<T0, T0, T1, TLim>( std::forward<T0>( n0 ), std::forward<T1>( n1 ), until, std::forward<TLim>( nlim ) );
  127. }
  128.  
  129. template <typename TRange>
  130. void Print ( TRange&& range ) {
  131. std::cout << "[ ";
  132. for ( auto& r : range ) {
  133. std::cout << r << ' ';
  134. }
  135. std::cout << "]" << std::endl;
  136. }
  137.  
  138. int main ( int argc, char** argv ) {
  139. // While the next line would be the ideal math-like syntax
  140. // we can't have it because `operator|` is left-associative
  141. // we, instead of the below...
  142. //auto results = [ ( x * x ) | (1, 20) | (x * x > 144) ] ;
  143.  
  144. // we start with a range instead, so we can build it up from there
  145. // also, in C++ we use lambdas
  146. //auto results = [ build(1, to, 20) | ( x * x ) | (x * x > 144) ] ;
  147. auto results1 = []( int x ) { return x * x; } | make( 1, to, 20 ) & []( int x ){ return x * x > 144; };
  148. std::cout << "make(1, to, 20):" << std::endl;
  149. Print( results1 );
  150.  
  151. auto results2 = []( int x ) { return x * x; } | make( 1, 2, 20 ) & []( int x ){ return x * x > 144; };
  152. std::cout << "make(1, 2, 20):" << std::endl;
  153. Print( results2 );
  154.  
  155. auto results3 = []( int x ) { return x * x; } | make( 1, 4, 20 ) & []( int x ){ return x * x > 144; };
  156. std::cout << "make(1, 4, 20):" << std::endl;
  157. Print( results3 );
  158.  
  159. }
Success #stdin #stdout 0s 2988KB
stdin
Standard input is empty
stdout
make(1, to, 20):
[ 169 196 225 256 289 324 361 400 ]
make(1, 2, 20):
[ 169 196 225 256 289 324 361 400 ]
make(1, 4, 20):
[ 169 256 361 ]