rangeless::fn
fn.hpp
Go to the documentation of this file.
1 /*
2 ================================================================================
3 
4  PUBLIC DOMAIN NOTICE
5  National Center for Biotechnology Information
6 
7  This software is a "United States Government Work" under the terms of the
8  United States Copyright Act. It was written as part of the author's official
9  duties as a United States Government employees and thus cannot be copyrighted.
10  This software is freely available to the public for use. The National Library
11  of Medicine and the U.S. Government have not placed any restriction on its use
12  or reproduction.
13 
14  Although all reasonable efforts have been taken to ensure the accuracy and
15  reliability of this software, the NLM and the U.S. Government do not and
16  cannot warrant the performance or results that may be obtained by using this
17  software. The NLM and the U.S. Government disclaim all warranties, expressed
18  or implied, including warranties of performance, merchantability or fitness
19  for any particular purpose.
20 
21  Please cite NCBI in any work or product based on this material.
22 
23 ================================================================================
24 
25  Author: Alex Astashyn
26 
27 */
28 #ifndef RANGELESS_FN_HPP_
29 #define RANGELESS_FN_HPP_
30 
31 #include <stdexcept> // to include std::logic_error for MSVC
32 #include <algorithm>
33 #include <functional>
34 #include <vector>
35 #include <map>
36 #include <deque> // can we get rid of this and implement in terms of ring-buffer?
37 #include <string> // for to_string
38 #include <iterator> // for std::inserter, MSVC
39 #include <cassert>
40 
41 #if defined(DOXYGEN) || (defined(RANGELESS_FN_ENABLE_RUN_TESTS) && RANGELESS_FN_ENABLE_RUN_TESTS)
42 # define RANGELESS_FN_ENABLE_PARALLEL 1
43 # define RANGELESS_ENABLE_TSV 1
44 #endif
45 
46 #if defined(_MSC_VER)
47 # pragma warning(push)
48 # pragma warning(disable: 4068) // unknown pragmas (for GCC diagnostic push)
49 #endif
50 
51 
52 #define RANGELESS_FN_THROW(msg) throw std::logic_error( std::string{} + __FILE__ + ":" + std::to_string(__LINE__) + ": "#msg );
53 
54 namespace rangeless
55 {
56 
57 /// @brief LINQ -like library of higher-order functions for data manipulation.
58 namespace fn
59 {
60 
61 namespace impl
62 {
63  // A trick to make compiler produce a compilation error printing the expanded type.
64  // Usage: TheTypeInQuestionIs<T>{}; or TheTypeInQuestionIs<decltype(expr)>{};
65  // The compiler output will have ... TheTypeInQuestionIs<int> ...
66  // ^^^ computed type
67  template<typename...> struct TheTypeInQuestionIs;
68 
69  template<typename IteratorTag, typename Iterable>
70  static inline void require_iterator_category_at_least(const Iterable&)
71  {
72  static_assert(std::is_base_of<IteratorTag, typename std::iterator_traits<typename Iterable::iterator>::iterator_category>::value, "Iterator category does not meet minimum requirements.");
73  }
74 
75  /////////////////////////////////////////////////////////////////////////
76  /// Very bare-bones version of std::optional-like with rebinding assignment semantics.
77  template<class T>
78  class maybe
79  {
80  struct sentinel{};
81  union
82  {
83  sentinel m_sentinel;
85  };
86 
87  bool m_empty = true;
88 
89  public:
90  using value_type = T;
91 
92  static_assert(!std::is_same<value_type, void>::value, "Can't have void as value_type - did you perhaps forget a return-statement in your transform-function?");
93 
94  maybe() : m_sentinel{}
95  {}
96 
97  // to avoid double-destruction
98  maybe(const maybe&) = delete;
99  maybe& operator=(const maybe&) = delete;
100 
101  maybe(T&& val)
102  {
103  reset(std::move(val));
104  }
105 
106  maybe(maybe&& other) noexcept
107  { //^^ by value instead?
108  if(!other.m_empty) {
109  reset(std::move(*other));
110  other.reset();
111  }
112  }
113 
114  // need this for monadic binding?
115  // maybe(maybe<maybe<T>> other) noexcept { ... }
116 
117  // NB: the assignment semantics differ from that of std::optional!
118  // See discussion in reset() below
119  maybe& operator=(maybe&& other) noexcept
120  {
121  if(this == &other) {
122  ;
123  } else if(!other.m_empty) {
124  reset(std::move(*other));
125  other.reset();
126  } else {
127  reset();
128  }
129  return *this;
130  }
131 
132  void reset(T&& val)
133  {
134  // NB: even if we are holding a value, we don't move-assign to it
135  // and instead reset and place-new, because the type may be
136  // move-constructible but not move-assigneable, e.g. containing a closure.
137  // https://stackoverflow.com/questi ons/38541354/move-assignable-lambdas-in-clang-and-gcc/
138  //
139  // Another reason we can't simply move-assign to
140  // is that T may be a tuple containing
141  // references, and we want to assign maybe<T> of such tuple
142  // without assigning referenced objects as a side-effect,
143  // unlike std::optional: (See NB[2])
144  // int x = 42;
145  // int y = 99;
146  // std::optional<std::tuple<int&>> opt_x = std::tie(x);
147  // std::optional<std::tuple<int&>> opt_y = std::tie(y);
148  // opt_x = opt_y; // x is now 99. For our purposes this is NOT what we want.
149  //
150  // For our purposes maybe<T> MUST behave similarly to a unique_ptr,
151  // except with stack-storage, where move-assignment simply transfers ownership.
152  //
153  // We are not sacrificing any correctness or performance because no copies are ever made anywhere -
154  // all assignments and argument-passing are by-move; T does not even need to be copy-constructible/assignable.
155  //
156  // We absolutely cannot rely on T::operator=(...),
157  // but the user code, however, can always invoke it directly as appropriate, e.g.
158  // *nonempty_maybe_vec = other_vec; // uses vector's operator= (will reuse existing internal storage without reallocation when possible).
159  //
160  // Note: We used to take T by value `reset(T val)`, since we're passing and taking by move, while also
161  // allowing the user-code to pass by implicit copy if they need to, but changed it to taking by rvalue-reference
162  // `reset(T&& val)` only, to disallow the user-code to accidentally write inefficient code like
163  // nonemmpty_maybe_vec.reset(other_vec), which destroys the currently-held vector, and makes a copy of
164  // other vec while passing it by value. Instead, the user-code would be forced to write
165  // *nonempty_maybe_vec = other_vec.
166  //
167  // (this was never a use-case in this library, but disallowing it anyway based on feedback).
168  //
169  // Related:
170  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3527.html#optional_ref.rationale.assign
171  // https://www.fluentcpp.com/2018/10/05/pros-cons-optional-references/
172 
173  reset();
174 
175  new (&m_value) T(std::move(val));
176 
177  m_empty = false;
178  }
179 
180  void reset()
181  {
182  if(!m_empty) {
183  this->operator*().~T();
184  m_empty = true;
185  }
186  }
187 
188  explicit operator bool() const noexcept
189  {
190  return !m_empty;
191  }
192 
193  T& operator*() noexcept
194  {
195  assert(!m_empty);
196 
197 #if __cplusplus >= 201703L
198  return *std::launder(&m_value);
199 #else
200  return m_value;
201 #endif
202  }
203 
204  // I believe technically we need std::launder here, yet I couldn't
205  // find a single implementation of `optional` that launders
206  // memory after placement-new, or side-steps the issue.
207  //
208  // https://en.cppreference.com/w/cpp/types/aligned_storage (static_vector example)
209  // https://github.com/ericniebler/range-v3
210  // https://github.com/mpark/base
211  // https://github.com/akrzemi1/Optional
212  // https://github.com/TartanLlama/optional
213  // https://github.com/ned14/outcome (MVP for discussing the issue in the documentation)
214  //
215  // We'll formally test for expected behavior in a unit-test.
216 
217  const T& operator*() const noexcept
218  {
219  assert(!m_empty);
220 
221 #if __cplusplus >= 201703L
222  return *std::launder(&m_value);
223 #else
224  return m_value;
225 #endif
226  }
227 
228 #if 0
229  // this causes internal compiler error in MSVC
230  template<typename F>
231  auto transform(F fn) && -> maybe<decltype(fn(std::move(**this)))>
232  {
233  if(m_empty) {
234  return { };
235  }
236 
237  return { fn(std::move(**this)) };
238  }
239 #endif
240 
242  {
243  reset();
244  }
245  };
246 
247  /////////////////////////////////////////////////////////////////////////////
248  // Will be used to control SFINAE priority of ambiguous overload resolutions.
249  // https://stackoverflow.com/questions/34419045
250 
251  struct pr_lowest {};
252  struct pr_low : pr_lowest {};
253  struct pr_high : pr_low {};
254  struct pr_highest : pr_high {};
255 
257 
258 
259 } // namespace impl
260 
261 
262  /// @defgroup io Inputs and Outputs
263  ///
264  /*!
265  @code
266  fn::seq([]{ ... }) % ... // as input-range from a nullary invokable
267  std::move(vec) % ... // pass by-move
268  vec % ... // pass by-copy
269  fn::from(vec) % ... // as view yielding elements by-move (or copy-view, if vec is const)
270  fn::cfrom(vec) % ... // as const view yielding elements by-copy (regardless of whether vec is const)
271  fn::refs(vec) % ... // as seq yielding reference-wrappers
272  @endcode
273  */
274  /// @{
275 
276  /////////////////////////////////////////////////////////////////////////
277  /// @brief Return fn::end_seq() from input-range generator function to signal end-of-inputs.
278  ///
279  /// This throws fn::end_seq::exception on construction, and is interpreted internally as end-of-inputs.
280  /// This exception does not propagate outside of the API's boundaries.
281  struct end_seq
282  {
283  // First I called it just "end", but want to avoid name confusion, because
284  // end() usually returns end-iterator in c++.
285 
286  /* I chose to allow exception-based approach to singal end-of-inputs.
287  *
288  * This is a pythonic approach to signal end-of-inputs from a generator function.
289  * This is cleanest from the API perspective, allowing for very trivial
290  * custom logic with fn::adapt, and also most straightforward under the hood
291  * implementation-wise. Using exceptions for flow control is generally
292  * considered a bad idea, but since the API is exeception-neutral, the
293  * only downside from the external perspective is the overhead
294  * associated with exceptional code path).
295  *
296  * Update: Switched the internals to monadic end-of-seq signaling by passing values
297  * via maybe-wrapper everywhere. To allow easy usage to user-code if they
298  * can tolerate exception-handling overhead, the user-code gen-function is wrapped
299  * in catch_end callable that will catch the end_seq::exception and will return
300  * empty-maybe, adapting the gen-function from exception-based to empty-maybe representation.
301  */
302 
303  struct exception
304  {};
305 
306  // TODO: can we preallocate exception with std::make_exception_ptr
307  // and then reuse it with std::rethrow_exception, which would avoid
308  // allocation? This doesn't seem to make any difference on throughput, however.
309  //
310  // Related article on performance of exceptions:
311  // http://nibblestew.blogspot.com/2017/01/measuring-execution-performance-of-c.html
312 
313 
314  // throw on construction or in conversion?
315  // There are pros and cons, i.e.
316  // a user may simply do `fn::end_seq();`
317  // and expect it to take effect.
318  //
319  // Also,
320  // return cond ? ret : fn::end_seq();
321  // will prevent copy-elision, one has to remember to std::move(ret).
323  {
324  throw exception{};
325  }
326 
327 #if 0 // MSVC 19.15 does not support noreturn
328  template<typename T>
329  [[ noreturn ]] operator T() const
330  {
331  throw exception{};
332  }
333 #else
334  template<typename T>
335  operator T() const
336  {
337  throw exception{};
338  return std::move(*impl::maybe<T>{});
339  }
340 #endif
341 
342  };
343 
344 
345 
346 namespace impl
347 {
348  // will isolate exception-based end-of-seq signaling and will
349  // not throw end_seq::exception ourselves (except in adapt,
350  // if user-code calls gen() past-the-end) to allow nonthrowing functionality.
351  template<typename Gen>
352  struct catch_end
353  {
354  Gen gen;
355  bool ended; // after first end_seq::exception
356  // will return empty-maybe without invoking gen, to avoid
357  // repeating the exception-handling overhead.
358 
359  using value_type = decltype(gen());
360 
362  {
363  if(ended) {
364  return { };
365  }
366 
367  try {
368  return { gen() };
369  } catch( const end_seq::exception& ) {
370  ended = true;
371  return { };
372  }
373  }
374  };
375 
376  // A type-erasing wrapper for a gen, wrapping it in a std::function,
377  // and providing value_type (so that InGen::value_type all over the place works).
378  // An alternative would be to use a metafunction that computes value_type everywhere instead.
379  template<typename T>
380  struct any_gen
381  {
382  using value_type = T;
383  std::function<impl::maybe<value_type>()> gen;
384 
386  {
387  return gen();
388  }
389  };
390 
391  /////////////////////////////////////////////////////////////////////
392  // invoke gen.recycle(value) if gen defines this method
393  template<typename G, typename T>
394  auto recycle(G& gen, T& value, pr_high) -> decltype(gen.recycle(value), void())
395  {
396  gen.recycle(value);
397  }
398 
399  // Low-priority fallback when gen.recycle(...) is not viable.
400  template<typename G, typename T>
401  void recycle(G&, T&, pr_low)
402  {
403  // no-op
404  }
405 
406  /////////////////////////////////////////////////////////////////////////
407  /// Single-pass InputRange-adapter for nullary generators.
408  ///
409  template<typename Gen>
410  class seq
411  {
412  // NB: This yields rvalue-references (`reference = value_type&&`)
413  // Pros:
414  // 1) If the downstream function takes arg by value (e.g. to transform, for_each, foldl, etc),
415  // it will be passed without making a copy.
416  //
417  // 2) We want to prevent user-code from making lvalue-references
418  // to the iterator's value, that will be invalidated when the iterator is incremented.
419  //
420  // Cons: move-iterators are not widely used, and an expression like `auto x = *it;`
421  // leaves *it in moved-from state, and it may not be clear from the context that a move just happened.
422  // That said, the entire point of this library is so that the user-code does not
423  // need to deal with iterators directly.
424 
425  public:
426  using value_type = typename Gen::value_type;
427  static_assert(!std::is_reference<value_type>::value, "The type returned by the generator-function must be a value-type. Use std::ref if necessary.");
428 
429  seq(Gen gen)
430  : m_gen( std::move(gen) ) // NB: must use parentheses here!
431  {}
432 
433  // To support conversion to any_seq_t.
434  // (i.e. Gen is a std::function, and OtherGen is some-lambda-type)
435  //
436  // Used to implement as rvalue-specific implicit conversion,
437  // using any_seq_t = seq<std::function<impl::maybe<value_type>()>>;
438  // operator any_seq_t() && { ... }
439  //
440  // but can't do this because of MSVC bug
441  // causing ambiguous overload resolution vs.
442  // operator std::vector<value_type>() &&
443  template<typename OtherGen>
445  : m_current{ std::move(other.m_current) }
446  , m_gen{ std::move(other.m_gen) }
447  , m_started{ other.m_started }
448  , m_ended{ other.m_ended }
449  , m_resumable{ other.m_resumable }
450 
451  {
452  other.m_started = true;
453  other.m_ended = true;
454  }
455 
456  seq(const seq&) = delete;
457  seq& operator=(const seq&) = delete;
458 
459  seq(seq&&) = default; // TODO: need to customize to set other.m_ended = other.m_started = true?
460  seq& operator=(seq&&) = default;
461 
462  /////////////////////////////////////////////////////////////////////
463  class iterator
464  {
465  public:
466  using iterator_category = std::input_iterator_tag;
467  using difference_type = void;
469  using pointer = value_type*;
470  using reference = value_type&&; // NB: rvalue-reference
471 
472  iterator(seq* p = nullptr) : m_parent{ p }
473  {}
474 
476  {
477  if(!m_parent || m_parent->m_ended) {
478  m_parent = nullptr;
479  return *this;
480  }
481 
482  auto& p = *m_parent;
483 
484  if(p.m_current) {
485  impl::recycle(p.m_gen, *p.m_current, resolve_overload{});
486  }
487 
488  p.m_current = p.m_gen();
489 
490  if(!p.m_current) {
491  p.m_ended = true;
492  m_parent = nullptr; // reached end
493  }
494  return *this;
495  }
496 
497 #pragma GCC diagnostic push
498 #pragma GCC diagnostic ignored "-Weffc++" // insists operator++(int) should be returning iterator
499  maybe<value_type> operator++(int) // to support *it++ usage
500  {
501  auto ret = std::move(m_parent->m_current);
502  this->operator++();
503  return ret;
504  }
505 #pragma GCC diagnostic pop
506 
507 
508  reference operator*() const { return static_cast<reference>(*m_parent->m_current); }
509  // Why do we need static_cast<reference> instead of simply std::move ?
510  // See https://en.cppreference.com/w/cpp/iterator/move_iterator/operator*
511 
512  pointer operator->() const { return &*m_parent->m_current; }
513 
514  bool operator==(const iterator& other) const
515  {
516  return m_parent == other.m_parent;
517  }
518 
519  bool operator!=(const iterator& other) const
520  {
521  return m_parent != other.m_parent;
522  }
523 
524  private:
525 
526  friend seq;
527 
528  seq* m_parent;
529  };
530 
531  iterator begin() // NB: non-const, advances to the first element, (calls m_gen)
532  {
533  // An input-range is single-pass. Not expecting multiple calls to begin()
534  if(m_started && !m_resumable) {
535  RANGELESS_FN_THROW("seq::begin() can only be called once per instance. Set resumable(true) to override.");
536  }
537 
538  auto it = iterator{ m_ended ? nullptr : this };
539 
540  if(!m_started && !m_ended) {
541  m_started = true; // advance to the first element (or end)
542  ++it;
543  }
544  return it;
545  }
546 
547  static iterator end()
548  {
549  return {};
550  }
551 
552 #if 0
553  // not providing this because begin() may be once-callable
554 
555  bool empty() // nb: non-const because begin() is non-const.
556  { // should this be made const (make fields mutable) ?
557  //return m_ended; // can't do that - may be empty, but m_Advanced==fase
558  return begin() == end();
559  }
560 #endif
561 
562  /// By default, calling begin() a second time will throw, because
563  /// the default expectation is that begin() will restart from the beginning,
564  /// which does not hold with seq, or any input-range for that matter.
565  /// This may be suppressed with .resumable(true),
566  /// making it explicit that the user-code is aware that begin() will resume
567  /// from the current state.
568  seq& set_resumable(bool res = true)
569  {
570  m_resumable = res;
571  }
572 
573  Gen& get_gen()
574  {
575  return m_gen;
576  }
577 
578  const Gen& get_gen() const
579  {
580  return m_gen;
581  }
582 
583  operator std::vector<value_type>() && // rvalue-specific because after conversion
584  { // the seq will be consumed (m_ended)
585  assert(!m_ended);
586  //assert(!m_started); allow or prohibit?
587 
588  std::vector<value_type> ret{};
589 
590  if(m_current) {
591  ret.push_back(std::move(*m_current));
592  m_current.reset();
593  }
594 
595  for(auto x = m_gen(); x; x = m_gen()) {
596  ret.push_back(std::move(*x));
597  }
598 
599  m_started = true;
600  m_ended = true;
601 
602  return ret;
603  }
604 
605 
606  private:
607  friend class iterator;
608 
609  // so that we can access private fields in constructor taking seq<OtherGen>
610  template<typename U>
611  friend class seq;
612 
613  impl::maybe<value_type> m_current = {};
614  // Last value returned by m_gen.
615  // Can't be simply T because T
616  // might not be default-constructible.
617 
618  Gen m_gen; // nullary generator
619  bool m_started = false; // false iff did not advance to begin()
620  bool m_ended = false;
621  bool m_resumable = false; // if true, do not throw if called begin() more than once.
622  };
623 
624  /////////////////////////////////////////////////////////////////////
625  template<typename Iterable>
626  struct refs_gen
627  {
628  Iterable& cont; // maybe const
629 
630  using value_type = decltype(std::ref(*cont.begin()));
631  // std::reference_wrapper< maybe-const Iterable::value_type>
632 
633  decltype(cont.begin()) it; // may be iterator or const_iterator
634 
636  {
637  if(it == cont.end()) {
638  return { };
639  } else {
640  return { *it++ };
641  }
642  }
643  };
644 
645 } // namespace impl
646 
647  /////////////////////////////////////////////////////////////////////////
648  /// @brief Adapt a generator function as `InputRange`.
649  /*!
650  @code
651  int i = 0;
652  int sum =
653  fn::seq([&i]
654  {
655  return i < 5 ? x++ : fn::end_seq();
656  })
657 
658  % fn::where([](int x)
659  {
660  return x > 2;
661  }) // 3, 4
662 
663  % fn::transform([](int x)
664  {
665  return x + 1;
666  }) // 4, 5
667 
668  % fn::foldl_d([](int out, int in)
669  {
670  return out * 10 + in;
671  });
672 
673  VERIFY(sum == 45);
674  @endcode
675  */
676  template<typename NullaryInvokable>
678  {
679  static_assert(!std::is_reference<decltype(gen_fn())>::value, "The type returned by gen_fn must be a value-type.");
680  static_assert(!std::is_same<decltype(gen_fn()), void>::value, "You forgot a return-statement in your gen-function.");
681  return { { std::move(gen_fn), false } };
682  }
683 
684  /////////////////////////////////////////////////////////////////////////
685  /// @brief Adapt a reference to `Iterable` as `seq` yielding reference-wrappers.
686  template<typename Iterable>
688  {
689  // Prevent usage with input-ranges, since reference-wrappers will become dangling
690  impl::require_iterator_category_at_least<std::forward_iterator_tag>(src);
691 
692  return { { src, src.begin() } };
693  }
694 
695  /// @}
696 
697 
698 namespace impl
699 {
700  /////////////////////////////////////////////////////////////////////
701  // User-provided key_fn may be returning a std::reference_wrapper<...>.
702  // So we'll be comparing keys using lt or eq, equipped to deal with that.
703  // See also https://stackoverflow.com/questions/9139748/using-stdreference-wrapper-as-the-key-in-a-stdmap
704 
705  struct lt
706  {
707 
708  template<typename T>
709  bool operator()(const T& a, const T& b) const
710  {
711  return std::less<T>{}(a, b);
712  }
713 
714  template<typename T>
715  bool operator()(const std::reference_wrapper<T>& a,
716  const std::reference_wrapper<T>& b) const
717  {
718  return std::less<T>{}(a.get(), b.get());
719  }
720  };
721 
722  struct eq
723  {
724  template<typename T>
725  bool operator()(const T& a, const T& b) const
726  {
727  return a == b;
728  }
729 
730  template<typename T>
731  bool operator()(const std::reference_wrapper<T>& a,
732  const std::reference_wrapper<T>& b) const
733  {
734  return a.get() == b.get();
735  }
736  };
737 
738  template<typename T>
739  int compare(const T& a, const T&b)
740  {
741  return ( lt{}(a, b) ? -1
742  : lt{}(b, a) ? 1
743  : 0);
744  }
745 
746 
747  /////////////////////////////////////////////////////////////////////
748  // @brief Value-wrapper with reversed operator<, used with by::decreasing
749  template<typename T>
750  struct gt
751  {
752  T val; // this has to be non-const, otherwise does not compile with T=bool (or int, etc)
753  // when used as part of a tuple (e.g. in the big example
754  // make_tuple(fn::by::decreasing(is_nc), ...); // compilation error if const T val; here
755  // make_tuple(!is_nc, ...); // ok
756  //
757  // Having a const field also prevents the use of move-constructor
758  // when passing by move.
759 
760  bool operator<(const gt& other) const
761  {
762  return std::less<T>{}(other.val, this->val);
763  }
764 
765  // operator== in case it will be used with group_adjacent_by or unique_adjacent_by
766  bool operator==(const gt& other) const
767  {
768  return other.val == this->val;
769  }
770 
771  // if val is a unary key-function
772  template<typename Arg>
773  auto operator()(const Arg& arg) const -> gt<decltype(val(arg))>
774  {
775  return { val(arg) };
776  }
777  };
778 
779  // binary comparator composed over key_fn
780  template<typename F>
781  struct comp
782  {
783  const F key_fn;
784 
785  // NB: may be type-assymetric
786  template<typename A, typename B>
787  bool operator()(const A& a, const B& b) const
788  {
789  return lt{}(key_fn(a), key_fn(b));
790  }
791  };
792 
793 } // namespace impl
794 
795 
796 /// @brief Common key-functions to use with sort_by/unque_by/group_all_by
797 /// @code
798 /// ptrs = %= fn::sort_by(fn::by::dereferenced{});
799 /// std::move(pairs) % fn::group_all_by(fn::by::second{});
800 /// @endcode
801 namespace by
802 {
803  // sort() / unique() are simply sort_by<identity> and unique_adjacent_by<identity>
804  struct identity
805  {
806  template<typename T>
807  auto operator()(const T& x) const -> const T&
808  {
809  return x;
810  }
811  };
812 
814  {
815  template<typename P> // any dereferenceable type
816  auto operator()(const P& ptr) const -> decltype(*ptr)
817  {
818  return *ptr;
819  }
820  };
821 
822  struct first
823  {
824  template<typename T>
825  auto operator()(const T& x) const -> decltype(*&x.first) // *& so that decltype computes a reference
826  {
827  return x.first;
828  }
829  };
830 
831  struct second
832  {
833  template<typename T>
834  auto operator()(const T& x) const -> decltype(*&x.second)
835  {
836  return x.second;
837  }
838  };
839 
840  /// e.g. for tuples or pairs, `fn::group_adjacent_by(fn::by::get<string>{})`
841  template<typename U>
842  struct get
843  {
844  template<typename T>
845  auto operator()(const T& x) const -> const U&
846  {
847  return std::get<U>(x);
848  }
849  };
850 
851  /// @brief Wraps the passed value and exposes inverted operator<.
852  /*!
853  @code
854  {{
855  // sort by longest-first, then lexicographically
856 
857  const auto inp = std::vector<std::string>{ "2", "333", "1", "222", "3" };
858  const auto expected = std::vector<std::string>{ "222", "333", "1", "2", "3" };
859 
860 
861  auto ret1 = inp % fn::sort_by([](const string& s)
862  {
863  return std::make_tuple(fn::by::decreasing(s.size()), std::ref(s));
864  });
865  VERIFY(ret1 == expected);
866 
867 
868  auto ret2 = inp % fn::sort_by([](const string& s)
869  {
870  return std::make_tuple(s.size(), fn::by::decreasing(std::ref(s)));
871  }) % fn::reverse();
872  VERIFY(ret2 == expected);
873 
874 
875  // we can also compose by::decreasing with a key-function
876  auto ret3 = inp % fn::sort_by(fn::by::decreasing([](const std::string& s)
877  {
878  return std::make_tuple(s.size(), fn::by::decreasing(std::ref(s)));
879  }));
880  VERIFY(ret3 == expected);
881 
882 
883  // we can also create a comparator from a key-function.
884  auto ret4 = inp;
885  gfx::timsort(ret4.begin(), ret4.end(), fn::by::make_comp([](const std::string& s)
886  {
887  return std::make_tuple(fn::by::decreasing(s.size()), std::ref(s));
888  }));
889  VERIFY(ret4 == expected);
890 
891 
892  // NB: we can't use std::tie because fn::by::decreasing returns an rvalue,
893  // so we use std::make_tuple and capture s by std::ref.
894  }}
895  @endcode
896  */
897  template<typename T>
899  {
900  // Note: we could perfect-forward T instead of taking it by value,
901  // such that return type is gt<const reference>,
902  // but this would allow misuse such as
903  // fn::sorty_by([](const auto& x)
904  // {
905  // const auto key = x.get_key();
906  // return fn::by::decreasing(key);
907  // // if key is captured by reference,
908  // // it becomes dangling after return.
909  // });
910  // Instead, will allow the user to explicitly
911  // capture by-reference via reference-wrapper below.
912 
913  return { std::move(x) };
914  }
915 
916  template<typename T>
917  impl::gt<const T&> decreasing(std::reference_wrapper<T> x)
918  {
919  // unwrapping reference_wrapper and capturing by const-reference,
920  // because otherwise unwrapped reference_wrapper won't bind to
921  // operator< in gt::operator<.
922  return { x.get() };
923  }
924 
925  /// @brief Make binary comparison predicate from a key-function
926  template<typename F>
928  {
929  return { std::move(key_fn) };
930  }
931 } // namespace by
932 
933 /// Common transform-functions that can be used as param to fn::transform
934 namespace get
935 {
937  {
938  template<typename P> // any dereferenceable type
939  auto operator()(P ptr) const -> typename std::remove_reference<decltype(std::move(*ptr))>::type
940  {
941  return std::move(*ptr);
942  }
943  };
944 
945  struct first
946  {
947  template<typename T>
948  auto operator()(T x) const -> typename T::first_type
949  {
950  return std::move(x.first);
951  }
952  };
953 
954  struct second
955  {
956  template<typename T>
957  auto operator()(T x) const -> typename T::second_type
958  {
959  return std::move(x.second);
960  }
961  };
962 
963  struct enumerated
964  {
965  size_t i = 0UL;
966 
967  template<typename T>
968  auto operator()(T x) -> std::pair<size_t, T>
969  {
970  return { i++, std::move(x) };
971  }
972  };
973 }
974 
975  /// @defgroup view Views
976  /// @{
977 
978  /////////////////////////////////////////////////////////////////////////
979  /// @brief A view is just a pair of interators with begin() and end() interface.
980  template<typename Iterator>
981  class view
982  {
983  private:
984  Iterator it_beg;
985  Iterator it_end;
986 
987  public:
988  view(Iterator b, Iterator e)
989  : it_beg( std::move(b) )
990  , it_end( std::move(e) )
991  {}
992 
993  view() = default;
994 
995  using iterator = Iterator;
996  using value_type = typename iterator::value_type;
997 
998  Iterator begin() const { return it_beg; }
999  Iterator end() const { return it_end; }
1000 
1001  /// Truncate the view.
1002  ///
1003  /// Precondition: `b == begin() || e = end()`; throws `std::logic_error` otherwise.
1004  /// This does not affect the underlying range.
1005  void erase(Iterator b, Iterator e)
1006  {
1007  // We support the erase method to obviate view-specific overloads
1008  // for some hofs, e.g. take_while, take_first, drop_whille, drop_last, etc -
1009  // the container-specific overloads will work for views as well.
1010 
1011  if(b == it_beg) {
1012  // erase at front
1013  it_beg = e;
1014  } else if(e == it_end) {
1015 
1016  // erase at end
1017  impl::require_iterator_category_at_least<std::forward_iterator_tag>(*this);
1018 
1019  it_end = b;
1020  } else {
1021  RANGELESS_FN_THROW("Can only erase at the head or at the tail of the view");
1022  }
1023  }
1024 
1025  void clear()
1026  {
1027  it_beg = it_end;
1028  }
1029 
1030  bool empty() const
1031  {
1032  return it_beg == it_end;
1033  }
1034  };
1035 
1036  // Note: we named the methods from, such that usage like
1037  // auto sorted_vec = fn::from(it_beg, it_end) % fn::sort();
1038  // communicates that the range will be moved-from.
1039 
1040  /// @brief Create a range-view from a pair of iterators.
1041  template<typename Iterator>
1042  constexpr view<Iterator> from(Iterator it_beg, Iterator it_end) noexcept
1043  {
1044  return { std::move(it_beg), std::move(it_end) };
1045  }
1046 
1047  /// To enable composability of APIs returning a pair of iterators, e.g. std::equal_range
1048  template<typename Iterator>
1049  constexpr view<Iterator> from(std::pair<Iterator, Iterator> p) noexcept
1050  {
1051  return { std::move(p.first), std::move(p.second) };
1052  }
1053 
1054  /// Create a range-view for a container, or an iterable that has `begin` and `end` as free functions rather than methods.
1055  template<typename Iterable,
1056  typename Iterator = typename Iterable::iterator>
1057  constexpr view<Iterator> from(Iterable& src) noexcept
1058  {
1059  using std::begin;
1060  using std::end;
1061  return { begin(src), end(src) };
1062  }
1063 
1064  template<typename Iterable,
1065  typename Iterator = typename Iterable::const_iterator>
1066  constexpr view<Iterator> from(const Iterable& src) noexcept
1067  {
1068  // need a separate overload for const, because without it
1069  // begin(src) yields const_iterator that is not convertible
1070  // to normal iterator that's in the signature.
1071 
1072  using std::begin; // cbegin/cend here instead?
1073  using std::end;
1074  return { begin(src), end(src) };
1075  }
1076 
1077 
1078  template<typename Iterable,
1079  typename Iterator = typename Iterable::const_iterator>
1080  constexpr view<Iterator> cfrom(const Iterable& src) noexcept
1081  {
1082  using std::begin;
1083  using std::end;
1084  return { begin(src), end(src) };
1085  }
1086 
1087  /// @}
1088 
1089 
1090 
1091 /////////////////////////////////////////////////////////////////////////
1092 /// @brief Implementations for corresponding static functions in fn::
1093 namespace impl
1094 {
1095  // Wrap an Iterable as gen-callable, yielding elements by move.
1096  struct to_seq
1097  {
1098  /////////////////////////////////////////////////////////////////////////
1099  // We compose seqs by yanking m_gen from the input seq,
1100  // wrapping it into a nullary callable (see gen) that will do the
1101  // additional work (e.g. filter, transform, etc) and wrapping back as seq.
1102  // I.e. we're doing the monadic "burrito" technique.
1103  // See RANGELESS_FN_OVERLOAD_FOR_SEQ
1104  //
1105  // The alternative is to wrap any range with adapting seq, but
1106  // this results in a to_seq at every layer instead of the outermost one.
1107  //
1108  // So if we want to work with a user-provided input-range or a container lazily,
1109  // we first need to wrap it as seq that will yield elements by-move.
1110  template<typename Iterable>
1111  struct gen
1112  {
1113  using value_type = typename Iterable::value_type;
1114  using iterator = typename Iterable::iterator;
1115 
1116  Iterable src_range;
1118  bool started;
1119 
1121  {
1122  if(!started) {
1123  started = true;
1124  it = src_range.begin();
1125  // r might not be a container (i.e. some input-range
1126  // and begin() may be non-const, so deferring until
1127  // the first call to operator() rather than
1128  // initializing it{ r.begin() } in constructor.
1129  } else if(it == src_range.end()) {
1130  ; // may be equal to end in case of repeated calls to operator() after ended
1131  } else {
1132  ++it;
1133  }
1134 
1135  if(it == src_range.end()) {
1136  return { };
1137  } else {
1138  return { std::move(*it) };
1139  }
1140  }
1141  };
1142 
1143  // pass-through if already a seq
1144  template<typename Gen>
1146  {
1147  return seq;
1148  }
1149 
1150  /// @brief Wrap a range (e.g. a container or a view) as seq.
1151  template<typename Iterable>
1152  seq<gen<Iterable>> operator()(Iterable src) const
1153  {
1154  return { { std::move(src) , {}, false } };
1155  }
1156  };
1157 
1158 
1159  /////////////////////////////////////////////////////////////////////
1160  struct to_vector
1161  {
1162  // passthrough overload
1163  template<typename T>
1164  std::vector<T> operator()(std::vector<T> vec) const
1165  {
1166  return vec;
1167  }
1168 
1169  // overload for a seq - invoke rvalue-specific implicit conversion
1170  template<typename Gen,
1171  typename Vec = std::vector<typename seq<Gen>::value_type>>
1172  Vec operator()(seq<Gen> r) const
1173  {
1174  return static_cast<Vec>(std::move(r));
1175  }
1176 
1177  // overload for other iterable: move-insert elements into vec
1178  template<typename Iterable,
1179  typename Vec = std::vector<typename Iterable::value_type> >
1180  Vec operator()(Iterable src) const
1181  {
1182  // Note: this will not compile with std::set
1183  // in conjunction with move-only value_type because
1184  // set's iterators are const, and std::move will try
1185  // and fail to use the copy-constructor.
1186 
1187  return this->operator()( Vec{
1188  std::make_move_iterator(src.begin()),
1189  std::make_move_iterator(src.end()) });
1190  }
1191 
1192  // an overload for map that will return a vector of
1193  // std::vector<std::pair<Key, Value>>> rather than
1194  // std::vector<std::pair<const Key, Value>>>, which is map's
1195  // value_type.
1196  // We want to remove the const because otherwise the vector's
1197  // functionality is crippled because the value-type is not
1198  // move-assigneable, so we can't do anything useful with it.
1199  //
1200  // TODO: generalize this for sets and arbitrary associative containers,
1201  // pre- and post- c++17.
1202  template<typename Key,
1203  typename Value,
1204  typename Vec = std::vector<std::pair<Key, Value>>>
1205  Vec operator()(std::map<Key, Value> m) const
1206  {
1207  Vec v{};
1208  v.reserve(m.size());
1209 
1210 #if __cplusplus >= 201703L
1211  while(!m.empty()) {
1212  auto h = m.extract(m.begin());
1213  v.emplace_back(std::move(h.key()),
1214  std::move(h.mapped()));
1215  }
1216 #else
1217  for(auto it = m.begin(), it_end = m.end();
1218  it != it_end;
1219  it = m.erase(it))
1220  {
1221  v.emplace_back(std::move(it->first), // this makes a copy due to const key
1222  std::move(it->second));
1223  }
1224 #endif
1225  return v;
1226  }
1227  };
1228 
1229 
1230  template<typename Container>
1231  struct to
1232  {
1233  Container dest;
1234 
1235  // pass-through if dest is empty and same type.
1236  Container operator()(Container src) && // rvalue-specific because dest will be moved-from
1237  {
1238  if(dest.empty()) {
1239  return std::move(src);
1240  }
1241 
1242  for(auto&& x : src) {
1243  dest.insert(dest.end(), std::move(x));
1244  }
1245  return std::move(dest);
1246  }
1247 
1248 
1249  template<typename Iterable>
1250  Container operator()(Iterable src) && // rvalue-specific because dest will be moved-from
1251  {
1252 #if 0
1253  // won't compile with std::set
1254  dest.insert(dest.end(),
1255  std::make_move_iterator(src.begin()),
1256  std::make_move_iterator(src.end()));
1257 #else
1258  for(auto&& x : src) {
1259  dest.insert(dest.end(), std::move(x));
1260  }
1261 #endif
1262  return std::move(dest);
1263  }
1264  };
1265 
1266 
1267  struct counts
1268  {
1269  template<typename Iterable>
1270  std::map<typename Iterable::value_type, size_t> operator()(Iterable&& xs) const
1271  {
1272  auto ret = std::map<typename Iterable::value_type, size_t>{};
1273  for(auto&& x : xs) {
1274  ++ret[x];
1275  }
1276  return ret;
1277  }
1278  };
1279 
1280  /////////////////////////////////////////////////////////////////////
1281  template<typename Pred>
1283  {
1284  const Pred pred;
1285  bool ret;
1286 
1287  // e.g. bool ret = vals % !fn::exists_where(pred);
1289  {
1290  // don't want to make operator! non-const for lvalues,
1291  // so instead making it rvalue-specific to prevent
1292  // any misuse.
1293 
1294  ret = !ret;
1295  return std::move(*this);
1296  }
1297 
1298  template<typename Iterable>
1299  bool operator()(const Iterable& iterable) const
1300  {
1301  for(const auto& x : iterable)
1302  if(pred(x))
1303  return ret;
1304  return !ret;
1305  }
1306  };
1307 
1308  // NB[3]: In for_each, foldl, foldl_d, foldl_1 we don't really need
1309  // the overloads for seq, because seq is Iterable, but by providing
1310  // them we work with underlying gens directly, bypassing the iterator
1311  // machinery layer of seq, potentially allowing the compiler to do
1312  // better job with optimization.
1313 
1314  /////////////////////////////////////////////////////////////////////
1315  template<typename F>
1316  struct for_each
1317  {
1318  F fn; // may be non-const, hence operator()s are also non-const.
1319 
1320  template<typename Iterable>
1321  void operator()(Iterable&& src)
1322  {
1323  for(auto it = src.begin(); it != src.end(); ++it) {
1324  fn(*it);
1325  }
1326 
1327  // Used to return by perfect-forwarding, i.e.
1328  // return-type = Iterable&&, and return std::forward<Iterable>(src);
1329  //
1330  // The intent was to allow downstream stages
1331  // after for_each. However,
1332  // 1) If Iterable is a single-pass seq,
1333  // it's not usable after the loop (will cause runtime error
1334  // if we try to iterate over it again).
1335  // 2) -Weffc++ says "should return by value" when
1336  // Iterable is passed by rvalue.
1337  //
1338  // So instead, will treat for_each as lfold-into-void.
1339  }
1340 
1341 
1342  // See NB[3]
1343  template<typename Gen>
1345  {
1346  for(auto x = src.get_gen()(); x; x = src.get_gen()()) {
1347  fn(std::move(*x));
1349  }
1350  }
1351  };
1352 
1353  template<typename F2>
1355  {
1356  F2 fn2; // may be non-const, hence operator()s are also non-const.
1357 
1358  template<typename Iterable>
1359  void operator()(Iterable&& src)
1360  {
1361  impl::require_iterator_category_at_least<std::forward_iterator_tag>(src);
1362 
1363  auto it2 = src.begin();
1364  if(it2 == src.end()) {
1365  return;
1366  }
1367  auto it1 = it2;
1368  ++it2;
1369 
1370  for(; it2 != src.end(); it1 = it2, ++it2) {
1371  fn2(*it1, *it2);
1372  }
1373  }
1374  };
1375 
1376 
1377  /////////////////////////////////////////////////////////////////////
1378  template<typename Ret, typename Op>
1379  struct foldl
1380  {
1381  Ret init;
1383 
1384  template<typename Iterable>
1385  Ret operator()(Iterable&& src) && // rvalue-specific because init will be moved-from
1386  { // (we have to, because Ret may be move-only)
1387 
1388  static_assert(std::is_same<Ret, decltype(fold_op(std::move(init), *src.begin()))>::value,
1389  "Type of Init must be the same as the return-type of F");
1390 
1391  for(auto it = src.begin(); it != src.end(); ++it) {
1392  init = fold_op(std::move(init), *it);
1393  }
1394 
1395  // NB: can't use std::accumulate because it does not do the std::move(init)
1396  // internally until c++20, so it won't compile with move-only types,
1397  // and will make copies for copyable types.
1398 
1399  return std::move(init);
1400  }
1401 
1402  // See NB[3]
1403  template<typename Gen>
1404  Ret operator()(seq<Gen> src) &&
1405  {
1406  for(auto x = src.get_gen()(); x; x = src.get_gen()()) {
1407  init = fold_op(std::move(init), std::move(*x));
1408  impl::recycle(src.get_gen(), *x, impl::resolve_overload{});
1409  }
1410  return std::move(init);
1411  }
1412  };
1413 
1414  /////////////////////////////////////////////////////////////////////
1415  template<typename Op>
1416  struct foldl_d
1417  {
1419 
1420  struct any
1421  {
1422  template<typename T>
1423  operator T() const;
1424  };
1425 
1426  template<typename Iterable>
1427  auto operator()(Iterable&& src) const -> decltype(fold_op(any(), *src.begin()))
1428  {
1429  using ret_t = decltype(fold_op(any(), *src.begin()));
1430  auto ret = ret_t{};
1431 
1432  for(auto it = src.begin(); it != src.end(); ++it) {
1433  ret = fold_op(std::move(ret), *it);
1434  }
1435 
1436  return ret;
1437  }
1438 
1439 
1440  // See NB[3]
1441  template<typename Gen>
1442  auto operator()(seq<Gen> src) const -> decltype(fold_op(any(), std::move(*src.get_gen()())))
1443  {
1444  using ret_t = decltype(fold_op(any(), std::move(*src.get_gen()())));
1445  auto ret = ret_t{};
1446 
1447  for(auto x = src.get_gen()(); x; x = src.get_gen()()) {
1448  ret = fold_op(std::move(ret), std::move(*x));
1449  impl::recycle(src.get_gen(), *x, impl::resolve_overload{});
1450  }
1451 
1452  return ret;
1453  }
1454  };
1455 
1456  /////////////////////////////////////////////////////////////////////
1457  template<typename F>
1458  struct foldl_1
1459  {
1461 
1462  template<typename Iterable>
1463  auto operator()(Iterable&& src) const -> decltype(fold_op(std::move(*src.begin()), *src.begin()))
1464  {
1465  auto it = src.begin();
1466  auto it_end = src.end();
1467 
1468  if(it == it_end) {
1469  RANGELESS_FN_THROW("Expected nonempty.");
1470  }
1471 
1472  auto init = *it;
1473 
1474  for(++it; it != it_end; ++it) {
1475  init = fold_op(std::move(init), *it);
1476  }
1477 
1478  return init;
1479  }
1480 
1481  // See NB[3]
1482  template<typename Gen>
1483  auto operator()(seq<Gen> src) const -> decltype(fold_op(std::move(*src.get_gen()()), std::move(*src.get_gen()())))
1484  {
1485  auto x1 = src.get_gen()();
1486 
1487  if(!x1) {
1488  RANGELESS_FN_THROW("Expected nonempty.");
1489  }
1490 
1491  auto init = std::move(*x1);
1492 
1493  for(auto x = src.get_gen()(); x; x = src.get_gen()()) {
1494  init = fold_op(std::move(init), std::move(*x));
1495  }
1496 
1497  return init;
1498  }
1499  };
1500 
1501  /////////////////////////////////////////////////////////////////////////
1502 
1503  // define operator() overload composing an input-seq
1504  // (gen in OutGen presumed to go first)
1505  // Basically, we unwrap the input seq, yanking its gen,
1506  // compose our gen over it, and wrap it back into seq.
1507 #define RANGELESS_FN_OVERLOAD_FOR_SEQ(...) \
1508  template<typename InGen> \
1509  auto operator()(seq<InGen> in) const -> seq<gen<InGen>> \
1510  { \
1511  return { { std::move(in.get_gen()), __VA_ARGS__ } }; \
1512  }
1513 
1514  // Default implementation of operator() for cases where
1515  // there's no eager logic for Container-arg, and
1516  // we want to treat it the same as seq (overload above)
1517  // so we wrap Cont as to_seq::gen and do same as above.
1518  //
1519 #define RANGELESS_FN_OVERLOAD_FOR_CONT(...) \
1520  template<typename Cont> \
1521  auto operator()(Cont cont) const -> seq<gen<to_seq::gen<Cont>>> \
1522  { \
1523  return { { { std::move(cont), { }, false }, __VA_ARGS__ } }; \
1524  } \
1525  // ^^^^^^^^^^
1526  // NB: it would be better, of course, to specify that `{ }` and `false`
1527  // as defaults in declarations of to_seq::gen fields instead of specifying them here,
1528  // but GCC-4.9.3 has problems with aggregate initialization in a presence
1529  // of field-defaults.
1530 
1531 
1532 #define RANGELESS_FN_OVERLOAD_FOR_VIEW(...) \
1533  template<typename Iterator> \
1534  auto operator()(view<Iterator> v) const \
1535  -> seq<gen<to_seq::gen<view<Iterator>>>> \
1536  { \
1537  return { { { std::move(v), { }, false }, __VA_ARGS__ } }; \
1538  }
1539 
1540  /////////////////////////////////////////////////////////////////////
1541  template<typename F>
1542  struct transform
1543  {
1545 
1546  template<typename InGen>
1547  struct gen
1548  {
1549  InGen gen;
1551 
1552  using value_type = decltype(map_fn(std::move(*gen())));
1553 
1554  static_assert(!std::is_same<value_type, void>::value, "You forgot a return-statement in your transform-function.");
1555 
1557  {
1558  // NB: passing map_fn as ref, as it may be stateful (e.g. counting)
1559  //return gen().transform(std::ref(map_fn));
1560 
1561  auto x = gen();
1562  if(!x) {
1563  return { };
1564  }
1565 
1566  auto ret = map_fn(std::move(*x));
1568  return std::move(ret); // I'd expect copy elision here, but
1569  // GCC4.9.3 tries to use copy-constructor here
1570  }
1571  };
1572 
1575  // Given a container, we return a lazy seq rather than
1576  // transforming all elements eagerly, because inputs may be
1577  // "small", while outputs may be "large" in terms of
1578  // memory and/or computation, so we want to defer it.
1579  };
1580 
1581 
1582  /////////////////////////////////////////////////////////////////////
1584  {
1585  const size_t win_size;
1586 
1587  template<typename Iterable>
1588  struct gen_c
1589  {
1590  using iterator = typename Iterable::iterator;
1592 
1593  Iterable cont;
1596  bool started;
1597  const size_t win_size;
1598 
1600  {
1601  if(!started) {
1602  started = true;
1603 
1604  win_beg = cont.begin();
1605  win_end = cont.begin();
1606 
1607  // advance view's it_end by win_size
1608  size_t n = 0;
1609  for(size_t i = 0; i < win_size && win_end != cont.end(); ++i) {
1610  ++win_end;
1611  ++n;
1612  }
1613 
1614  if(n < win_size) {
1615  return { };
1616  } else {
1617  return value_type{ win_beg, win_end };
1618  }
1619  }
1620 
1621  if(win_end == cont.end()) {
1622  return { };
1623  }
1624 
1625  ++win_beg;
1626  ++win_end;
1627 
1628  return { { win_beg, win_end } };
1629  }
1630  };
1631 
1632  template<typename Iterable>
1633  auto operator()(Iterable inps) const -> seq<gen_c<Iterable>>
1634  {
1635  impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
1636 
1637  return { { std::move(inps),
1638  {}, {}, // iteratos
1639  false, // started
1640  win_size } };
1641  }
1642 
1643  /////////////////////////////////////////////////////////////////////
1644 
1645  // for seq: buffer win_size elements in a queue
1646  template<typename InGen>
1647  struct gen
1648  {
1649  InGen gen;
1650 
1651  using inp_t = typename InGen::value_type;
1652  using queue_t = std::deque<inp_t>;
1654 
1657  const size_t win_size;
1658 
1660  {
1661  if(!queue.empty()) {
1662  queue.pop_front();
1663  }
1664 
1665  while(queue.size() < win_size) {
1666  auto x = gen();
1667  if(!x) {
1668  return { };
1669  }
1670  queue.push_back(std::move(*x));
1671  }
1672 
1673  return { { queue.begin(), queue.end() } };
1674  }
1675  };
1676 
1677  RANGELESS_FN_OVERLOAD_FOR_SEQ( {}, {{}, {}}, win_size )
1678  };
1679 
1680 
1681  /////////////////////////////////////////////////////////////////////
1682 
1683 #if 0
1684  Note: leaving the original implementation for reference.
1685  template<typename F>
1686  struct adapt
1687  {
1688  F fn;
1689 
1690  template<typename Gen>
1691  struct gen
1692  {
1693  Gen gen; // upstream nullary generator
1694  F fn; // unary user-function taking the generator (NOT the result)
1695 
1696  auto operator()() -> decltype(fn(gen))
1697  {
1698  // fn may be taking gen by value [](auto gen){...},
1699  // so the state of the original (possibly mutable) gen
1700  // will not be updated. We force passing by-reference here
1701  // with reference-wrapper, such that the above construct
1702  // in the user code invokes the original gen.
1703  return fn(std::ref(gen));
1704  }
1705  };
1706 
1709  };
1710 #else
1711 
1712  /////////////////////////////////////////////////////////////////////
1713  // The implementation below was added to enable the user-code (fn)
1714  // interrogate the passed gen whether it can yield another value
1715  // (so the user-code can wrap-up without throwing), so it prefetches
1716  // the next value from in_gen, and the gen-wrapper conversion to
1717  // bool is false iff the prefetched maybe<...> is empty.
1718  //
1719  // The alternative is to have gen return a maybe<...>,
1720  // but we want to isolate the user-code from
1721  // implementation details.
1722  template<typename F>
1723  struct adapt
1724  {
1725  F fn;
1726 
1727  template<typename InGen>
1728  struct gen
1729  {
1730  InGen in_gen; // upstream nullary generator
1731  F fn; // unary user-function taking the generator (NOT the result)
1732 
1733  using inp_t = typename InGen::value_type;
1734 
1736  bool started;
1737 
1738  // the gen-wrapper that will be passed to fn
1739  struct gen_wr
1740  {
1742 
1743  auto operator()() -> inp_t
1744  {
1745  assert(parent);
1746 
1747  if(!parent->inp) {
1748  // user-code called gen() too many times
1749  throw end_seq::exception{};
1750  }
1751 
1752  auto ret = std::move(*parent->inp);
1753  parent->next();
1754  return ret;
1755  }
1756 
1757  explicit operator bool() const
1758  {
1759  assert(parent);
1760 
1761  return bool(parent->inp);
1762  }
1763  };
1764 
1765  void next()
1766  {
1767  inp = in_gen();
1768  }
1769 
1770  using value_type = decltype(fn(gen_wr{ nullptr }));
1771 
1773  {
1774  if(!started) {
1775  started = true;
1776  next();
1777  }
1778 
1779  // user-function fn may throw end-of-inputs,
1780  // either explicitly or by invoking gen after
1781  // its conversion to bool equals false. We
1782  // catch it here and return empty-maybe exactly
1783  // as we do in catch_end-wrapper.
1784  try {
1785  return { fn(gen_wr{ this }) };
1786 
1787  } catch( const end_seq::exception& ) {
1788  return { };
1789  }
1790  }
1791  };
1792 
1795  };
1796 
1797 #endif // adapt
1798 
1799  /////////////////////////////////////////////////////////////////////
1800  template<typename Pred>
1801  struct take_while
1802  {
1803  Pred pred;
1804 
1805  template<typename InGen>
1806  struct gen
1807  {
1808  InGen gen;
1809  Pred pred;
1811 
1812  using value_type = typename InGen::value_type;
1813 
1815  {
1816  if(found_unsatisfying) {
1817  return { };
1818  }
1819 
1820  auto x = gen();
1821  if(!pred(*x)) {
1822  found_unsatisfying = true;
1823  return { };
1824  }
1825  return std::move(x);
1826  }
1827  };
1828 
1830 
1831  template<typename Cont>
1832  Cont operator()(Cont cont) const
1833  {
1834  auto it = std::find_if_not(cont.begin(), cont.end(), pred);
1835  cont.erase(it, cont.end());
1836  return cont;
1837  }
1838  };
1839 
1840  /////////////////////////////////////////////////////////////////////
1841  struct take_last
1842  {
1843  const size_t cap;
1844 
1845  template<typename Gen>
1846  auto operator()(seq<Gen> r) const -> std::vector<typename seq<Gen>::value_type>
1847  {
1848  // consume all elements, keep last `cap` in the queue
1849  std::vector<typename seq<Gen>::value_type> queue;
1850 
1851  queue.reserve(cap);
1852 
1853  size_t i = 0; // count of insertions
1854 
1855  for(auto x = r.get_gen()(); x; x = r.get_gen()()) {
1856  if(i < cap) {
1857  // NB: can't call queue.resize() because that imposes
1858  // default-constructible on value_type, so instead
1859  // push_back in the beginning.
1860  queue.push_back(std::move(*x));
1861  } else {
1862  queue[i % cap] = std::move(*x);
1863  }
1864  ++i;
1865  }
1866 
1867  if(cap < i) {
1868  // put the contents in proper order.
1869  auto it = queue.begin();
1870  std::advance(it, i % cap); // oldest inserted element
1871  std::rotate(queue.begin(), it, queue.end());
1872  }
1873 
1874  return queue;
1875  }
1876 
1877  template<typename Iterable>
1878  Iterable operator()(Iterable&& inps) const
1879  {
1880  // Iterable may be a container or view
1881  static_assert(std::is_rvalue_reference<Iterable&&>::value, "");
1882 
1883  // in case cont is a view:
1884  impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
1885  const auto size = size_t(std::distance(inps.begin(), inps.end()));
1886 
1887  if(cap < size) {
1888  auto it = inps.begin();
1889  std::advance(it, size - cap);
1890  inps.erase(inps.begin(), it);
1891  }
1892  return std::move(inps);
1893  }
1894 
1895  template<typename Cont>
1896  Cont operator()(const Cont& cont) const
1897  {
1898  Cont ret{};
1899 
1900  if(cap < cont.size()) {
1901  auto it = cont.begin();
1902  std::advance(it, cont.size() - cap);
1903  ret.insert(ret.end(), it, cont.end());
1904  }
1905  return ret;
1906  }
1907  };
1908 
1909  /////////////////////////////////////////////////////////////////////////
1910  struct drop_last
1911  {
1912  const size_t n;
1913 
1914  template<typename InGen>
1915  struct gen
1916  {
1917  InGen gen;
1918  size_t cap;
1919 
1920  using value_type = typename InGen::value_type;
1921  using vec_t = std::vector<value_type>;
1922 
1924  size_t i;
1925 
1927  {
1928  if(queue.capacity() < cap) {
1929  queue.reserve(cap);
1930  }
1931 
1932  while(i < cap) {
1933  auto x = gen();
1934  if(!x) {
1935  return { };
1936  }
1937  queue.push_back(std::move(*x));
1938  ++i;
1939  }
1940 
1941  auto& dest = queue[i++ % cap];
1942  auto ret = std::move(dest);
1943  auto x = gen();
1944  if(!x) {
1945  return { };
1946  } else {
1947  dest = std::move(*x);
1948  return { std::move(ret) };
1949  }
1950  }
1951  };
1952 
1954 
1955  template<typename Iterable>
1956  Iterable operator()(Iterable&& inps) const
1957  {
1958  // Iterable may be a container or view
1959  static_assert(std::is_rvalue_reference<Iterable&&>::value, "");
1960 
1961  // in case cont is a view:
1962  impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
1963  const auto size = size_t(std::distance(inps.begin(), inps.end()));
1964 
1965  if(n < size) {
1966  auto it = inps.begin();
1967  std::advance(it, size - n);
1968  inps.erase(it, inps.end());
1969  } else {
1970  inps.clear();
1971  }
1972 
1973  return std::move(inps);
1974  }
1975 
1976 
1977  template<typename Cont>
1978  Cont operator()(const Cont& cont) const
1979  {
1980  Cont ret{};
1981 
1982  if(n < cont.size()) {
1983  auto it = cont.begin();
1984  std::advance(it, cont.size() - n);
1985  ret.insert(ret.end(), cont.begin(), it);
1986  }
1987 
1988  return ret;
1989  }
1990  };
1991 
1992  /////////////////////////////////////////////////////////////////////
1993  template<typename Pred>
1994  struct drop_while
1995  {
1996  Pred pred;
1997 
1998  template<typename InGen>
1999  struct gen
2000  {
2001  InGen gen;
2002  Pred pred;
2004 
2005  using value_type = typename InGen::value_type;
2006 
2008  {
2009  auto x = gen();
2010  while(!found_unsatisfying && x && pred(*x)) {
2011  x = gen();
2012  }
2013 
2014  found_unsatisfying = true;
2015  return x;
2016  }
2017  };
2018 
2020 
2021  template<typename Iterable>
2022  Iterable operator()(Iterable inps) const
2023  {
2024  auto it = std::find_if_not(inps.begin(), inps.end(), pred);
2025  inps.erase(inps.begin(), it);
2026  return inps;
2027  }
2028  };
2029 
2030  /////////////////////////////////////////////////////////////////////
2031  // used by take_first, drop_first
2033  {
2034  const size_t cap;
2035  mutable size_t num_calls;
2036 
2037  template<typename T>
2038  bool operator()(const T&) const
2039  {
2040  return num_calls++ < cap;
2041  }
2042  };
2043 
2044  /////////////////////////////////////////////////////////////////////
2045  template<typename Pred>
2046  struct where
2047  {
2048  Pred pred; // NB: may be mutable lambda, e.g.
2049  // where([i = 0]() mutable { return i++ < 10; }).
2050  //
2051  // In container-specific overloads will need to
2052  // make a copy and use that to be const-compliant.
2053 
2054  /////////////////////////////////////////////////////////////////////////
2055  template<typename InGen>
2056  struct gen
2057  {
2058  InGen gen;
2059  Pred pred;
2060 
2061  using value_type = typename InGen::value_type;
2062 
2063  static_assert(std::is_same<decltype(pred(*gen())), bool>::value, "The return value of predicate must be convertible to bool.");
2064  // is_convertible<..., bool> would suffice, but if it's not bool there's
2065  // a good chance that the user code is inadvertently doing something
2066  // the programmer did not intend, so we'll be a little more stringent
2067  // to guard against this.
2068 
2070  {
2071  auto x = gen();
2072  while(x && !pred(*x)) {
2073  x = gen();
2074  }
2075 
2076  return x;
2077  }
2078  };
2079 
2081 
2082  /////////////////////////////////////////////////////////////////////////
2083 
2084  // If cont is passed as const-reference,
2085  // make another container, copying only the
2086  // elements satisfying the predicate.
2087  template<typename Cont>
2088  Cont operator()(const Cont& cont) const
2089  {
2090  Cont ret{};
2091  auto pred_copy = pred; // in case copy_if needs non-const access
2092  std::copy_if(cont.begin(),
2093  cont.end(),
2094  std::inserter(ret, ret.end()),
2095  pred_copy);
2096  return ret;
2097  }
2098 
2099  // Why the above overload won't bind to non-const-reference args,
2100  // necessitating this overload?
2101  template<typename Cont>
2102  Cont operator()(Cont& cont) const
2103  {
2104  const Cont& const_cont = cont;
2105  return this->operator()(const_cont);
2106  }
2107 
2108  // If cont is passed as rvalue-reference,
2109  // erase elements not satisfying predicate.
2110  // (this also supports the case of container
2111  // with move-only value-type).
2112  template<typename Cont>
2113  Cont operator()(Cont&& cont) const //-> typename std::enable_if<std::is_rvalue_reference<Cont&&>::value, Cont>::type
2114  {
2115  static_assert(std::is_rvalue_reference<Cont&&>::value, "");
2116 
2117  x_EraseFrom(cont, impl::resolve_overload{}); // SFINAE-dispatch to erase-remove or iterate-erase overload.
2118  return std::move(cont); // must move, because Cont may contain move-only elements
2119  // (e.g. won't compile otherwise with Cont=std::vector<std::unique_ptr<int>>)
2120  }
2121 
2122  private:
2123  template<typename Cont>
2124  void x_EraseRemove(Cont& cont) const
2125  {
2126  auto pred_copy = pred;
2127  cont.erase(
2128  std::remove_if(
2129  cont.begin(), cont.end(),
2130  [&pred_copy](const typename Cont::value_type& x)
2131  {
2132  return !pred_copy(x);
2133  }),
2134  cont.end());
2135 
2136  // Using std::not1(pred) instead of the lambda above won't compile:
2137  // error: no type named 'argument_type'...
2138  }
2139 
2140 
2141  // High-priority overload for containers where can call remove_if.
2142  template<typename Cont>
2143  auto x_EraseFrom(Cont& cont, pr_high) const -> decltype(void(cont.front()))
2144  { // ^^^^^^^^^^ discussion below
2145  // This overload must be made unpalatable to SFINAE unless
2146  // std::remove_if is viable for Cont, e.g. feature-checking
2147  // as follows:
2148  //
2149  // A) Can call std::remove:
2150  // -> decltype(void( std::remove(cont.begin(), cont.end(), *cont.begin()) ))
2151  //
2152  // B) Or simplifying, iterator's reference_type is non-const (assignable),
2153  // -> decltype(void( *cont.begin() = std::move(*cont.begin()) ))
2154  // or -> decltype(std::swap(*cont.begin(), *cont.begin()))
2155  //
2156  // For a std::map, even though map's value_type is not move-assignable,
2157  // (due to key being const, the lines below should not and would not compile,
2158  // and yet SFINAE still considers this overload viable (??)
2159  //
2160  // std::remove(cont.begin(), cont.end(), *cont.begin());
2161  // *cont.begin() = std::move(*cont.begin());
2162  //
2163  // I'm not sure why SFINAE fails to reject it in the decltype,
2164  // resulting in ambiguous resolution of x_EraseFrom.
2165  //
2166  // Anyway, that's why we're instead feature-testing for SequenceContainer
2167  // based the presence of cont.front()
2168  // https://en.cppreference.com/w/cpp/named_req/SequenceContainer
2169  //
2170  // Update: This is no longer an issue with newer compilers, so this must have been
2171  // a compiler bug. However, Leaving the cont.front() check in place for now
2172  // to support older compilers.
2173 
2174  x_EraseRemove(cont);
2175  }
2176 
2177  // for a view I can't tell which idiom to use in SFINAE
2178  // (e.g. is it a view into a map or into a vec?)
2179  // So will specialize for view and require random_access_iterator,
2180  // so we can be sure erase-remove is viable
2181  template<typename Iterator>
2182  void x_EraseFrom(view<Iterator>& v, pr_high) const
2183  {
2184  impl::require_iterator_category_at_least<std::random_access_iterator_tag>(v);
2185  x_EraseRemove(v);
2186  }
2187 
2188  // Low-priority overload where remove_if is not viable, but
2189  // the container has equal_range method (e.g. set and associative
2190  // containers) so it is reasonable to expect that iterate-erase
2191  // idiom is applicable.
2192  template<typename Cont>
2193  auto x_EraseFrom(Cont& cont, pr_low) const
2194  -> decltype(void(
2195  cont.equal_range(
2196  std::declval<typename Cont::key_type const&>())))
2197  {
2198  auto pred_copy = pred;
2199  for(auto it = cont.begin(), it_end =cont.end();
2200  it != it_end;
2201  it = pred_copy(*it) ? std::next(it)
2202  : cont.erase(it))
2203  {
2204  ;
2205  }
2206  }
2207 
2208  template<typename NotACont>
2209  static void x_EraseFrom(NotACont&, pr_lowest)
2210  {
2211  static_assert(sizeof(NotACont) == 0, "The argument to fn::impl::where is expected to be either a seq<...> or a sequence container or an associative container having equal_range method.");
2212  TheTypeInQuestionIs<NotACont>{};
2213  }
2214  };
2215 
2216  /////////////////////////////////////////////////////////////////////
2217  template<typename SortedRange, typename F>
2219  {
2220  const SortedRange& r;
2221  const bool is_subtract; // subtract or intersect r
2223 
2224  bool operator()(const typename SortedRange::value_type& x) const
2225  {
2226  return is_subtract ^ std::binary_search(r.begin(), r.end(), x, comp);
2227  }
2228  };
2229 
2230  /////////////////////////////////////////////////////////////////////
2231  template<typename F>
2233  {
2234  const F key_fn;
2235  const int use_max; // 1 for max, -1 for use-min
2236 
2237  /////////////////////////////////////////////////////////////////
2238  // Note: rather than returning a seq, as with where() or transform(),
2239  // we're returning a vector with accumulated results (we had to accumulate
2240  // the results somewhere, and there's no point in wrapping back in seq.
2241  template<typename InGen,
2242  typename Ret = typename std::vector<typename seq<InGen>::value_type> >
2243  auto operator()(seq<InGen> in) const -> Ret
2244  {
2245  Ret ret{};
2246 
2247  auto& gen = in.get_gen();
2248 
2249  for(auto x = gen(); x; x = gen()) {
2250 
2251  const auto which = ret.empty() ? 0
2252  : impl::compare(key_fn(ret.front()),
2253  key_fn(*x)) * use_max;
2254  if(which < 0) {
2255  ret.clear();
2256  ret.push_back(std::move(*x));
2257 
2258  } else if(which > 0) {
2259  ;
2260  } else {
2261  ret.push_back(std::move(*x));
2262  }
2263  }
2264 
2265  if(ret.capacity() >= ret.size() * 2) {
2266  ret.shrink_to_fit();
2267  }
2268 
2269  return ret;
2270  }
2271 
2272  /////////////////////////////////////////////////////////////////
2273  template<typename Cont,
2274  typename Ret = std::vector<typename Cont::value_type> >
2275  Ret operator()(Cont cont) const
2276  {
2277  // TODO: Take Cont as forwarding reference instead of by value
2278  // such that if it is passed by lvalue-reference we don't need to
2279  // copy all elements; will only copy the maximal ones.
2280  // (copy or move value from the iterator depending on whether
2281  // cont is lvalue or rvalue-reference?)
2282 
2283  // NB[2]: if we're taking lvalue of key_fn(element),
2284  // be mindful that key may contain references to keyed object.
2285  // (hopefully const, but we can't even assume that).
2286  // (e.g. make_tuple(....) unwraps reference-wrappers and returns
2287  // a tuple that may contain references.
2288  //
2289  // Therefore:
2290  // 1) we can't reassign keys, e.g. best_key = max(best_key, current_key),
2291  // as this will assign the internal reference (if non-const)
2292  // or will not compile (if reference is const).
2293  //
2294  // 2) The value of key may become invalidated if referenced
2295  // element is assigned or moved from (explicitly, or under the hood,
2296  // e.g. while reallocating when a std::vector is resized in push_back,
2297  // or when the element is moved to a different position by erase-remove
2298  // algorithm.
2299 
2300  // NB: we could reuse the same logic for both input and Cont use-cases,
2301  // but having multi-pass capability with Cont allows us to do less
2302  // memory churn (we only need to move elements-of-interest into ret).
2303 
2304  Ret ret{};
2305 
2306  if(cont.empty())
2307  return ret;
2308 
2309  auto first_best_it = cont.begin();
2310  auto last_best_it = cont.begin();
2311  size_t n = 1; // count of max-elements
2312 
2313  {
2314  auto it = cont.begin();
2315  for(++it; it != cont.end(); ++it) {
2316  const int which = impl::compare(key_fn(*it),
2317  key_fn(*first_best_it)) * use_max;
2318  if(which < 0) {
2319  ; // not-best
2320  } else if(which > 0) {
2321  // new-best
2322  first_best_it = last_best_it = it;
2323  n = 1;
2324  } else {
2325  last_best_it = it;
2326  n++;
2327  }
2328  }
2329  }
2330 
2331  ret.reserve(n);
2332  ret.push_back(std::move(*first_best_it));
2333  ++first_best_it;
2334  ++last_best_it; // convert to end
2335 
2336  for(auto it = first_best_it; it != last_best_it; ++it)
2337  if(impl::compare(key_fn(*it),
2338  key_fn(ret.back())) * use_max >= 0)
2339  {
2340  ret.push_back(std::move(*it));
2341  }
2342 
2343  return ret;
2344 
2345 #if 0 // An example of what NOT to do:
2346  auto best_key = key_fn(*cont.begin());
2347  for(const auto& e : cont) {
2348  auto key = key_fn(e);
2349  if(impl::compare(best_key, key)*use_max > 0) {
2350  best_key = std::move(key); // BUG: modifies referenced object via
2351  // internal non-const references in key.
2352  // (or will not compile if references are const)
2353  }
2354 
2355  return fn::where(
2356  [&, this](const typename Ret::value_type& x)
2357  {
2358  return impl::compare(key_fn(x), best_key)*use_max >= 0;
2359  })(std::forward<Cont>(cont));
2360  // BUG: best_key may contain a reference, which is invalidated mid-processing
2361  // when best-element is moved inside erase-remove loop in fn::where.
2362 #endif
2363  }
2364  };
2365 
2366 
2367  /////////////////////////////////////////////////////////////////////
2368  struct reverse
2369  {
2370  template<typename Gen>
2371  auto operator()(seq<Gen> r) const -> std::vector<typename seq<Gen>::value_type>
2372  {
2373  auto vec = to_vector{}(std::move(r));
2374  std::reverse(vec.begin(), vec.end());
2375  return vec;
2376  }
2377 
2378 #if 0
2379  template<typename Iterable>
2380  struct reversed
2381  {
2382  Iterable src;
2383  using value_type = typename Iterable::value_type;
2384  using iterator = typename Iterable::reverse_iterator;
2385  using const_iterator = typename Iterable::const_reverse_iterator;
2386 
2387  iterator begin()
2388  {
2389  return src.rbegin();
2390  }
2391 
2392  iterator end()
2393  {
2394  return src.rend();
2395  }
2396 
2397  const_iterator begin() const
2398  {
2399  return src.rbegin();
2400  }
2401 
2402  const_iterator end() const
2403  {
2404  return src.rend();
2405  }
2406 
2407  const_iterator cbegin() const
2408  {
2409  return src.crbegin();
2410  }
2411 
2412  const_iterator cend() const
2413  {
2414  return src.crend();
2415  }
2416  };
2417 
2418  template<typename Iterable>
2419  reversed<Iterable> operator()(Iterable src) const
2420  {
2421  return reversed<Iterable>{ std::move(src) };
2422  }
2423 
2424 #else // The above approach is more clever, and works for all containers that support bidirectional iteration.
2425  // In practice, however, the input is a vector and the user programmer expects the reversed vector as output.
2426  // So in the spirit of pragmatism, will expect a reversible sequence container as input, and reverse eagerly.
2427  // (Since it costs at least O(n) to create a container, reversing in O(n) does not add
2428  // to asymptotic complexity).
2429 
2430  template<typename ReversibleContainer>
2431  auto operator()(ReversibleContainer cont) const -> ReversibleContainer
2432  {
2433  std::reverse(cont.begin(), cont.end()); // compilation hint: expecting ReversibleContainer - consider fn::to_vector() first.
2434  return cont;
2435  }
2436 #endif
2437 
2438  template<typename Iterator>
2440  {
2441  impl::require_iterator_category_at_least<std::bidirectional_iterator_tag>(v);
2442 
2443  using rev_it_t = std::reverse_iterator<Iterator>;
2444  return { rev_it_t{ v.end() },
2445  rev_it_t{ v.begin() } };
2446  }
2447  };
2448 
2449  // NB: sort and reverse have identical signatures for overloads
2450 
2451  /////////////////////////////////////////////////////////////////////
2452  // I made a decision to deviate from STL naming convention,
2453  // where std::sort is unstable, and made fn::sort/sort_by a stable-sort.
2454  //
2455  // I think STL should have followed the principle of least astonishment and made
2456  // std::sort a stable-sort, and have an additonal std::unstable_sort version.
2457  // (STL is known for its poor names that tend to surprise novice programmers).
2458  // That is, by default sort should do "the most right" thing,
2459  // and have an differently named (e.g. "unstable_sort") optimizing
2460  // version that can make additional assumptions about the inputs.
2461  //
2462  // In real-life sort_by/group_all_by/unique_all_by use-cases we don't
2463  // simply sort ints or strings where unstable-sort would do; rather,
2464  // we sort some objects by some subset of properties, where the sort-key only
2465  // partially differentiates between the objects, and a two objects
2466  // that are equivalent according to the sort key don't necessarily
2467  // compare equal, and so we shouldn't be swapping their relative order.
2468  struct stable_sort_tag {};
2470  template<typename F, typename SortTag = stable_sort_tag>
2471  struct sort_by
2472  {
2473  const F key_fn;
2474 
2475  template<typename Gen>
2476  auto operator()(seq<Gen> r) const -> std::vector<typename seq<Gen>::value_type>
2477  {
2478  return this->operator()(to_vector{}(std::move(r)));
2479  }
2480 
2481  template<typename Iterable>
2482  Iterable operator()(Iterable src) const
2483  {
2484  impl::require_iterator_category_at_least<std::random_access_iterator_tag>(src);
2485 
2486  // this will fire if Iterable is std::map, where value_type is std::pair<const Key, Value>,
2487  // which is not move-assignable because of constness.
2488  static_assert(std::is_move_assignable<typename Iterable::value_type>::value, "value_type must be move-assignable.");
2489 
2490  s_sort( src,
2491  [this](const typename Iterable::value_type& x,
2492  const typename Iterable::value_type& y)
2493  {
2494  return lt{}(key_fn(x), key_fn(y));
2495  }
2496  , SortTag{});
2497 
2498  return src;
2499  }
2500 
2501  private:
2502  template<typename Iterable, typename Comp>
2503  static void s_sort(Iterable& src, Comp comp, stable_sort_tag)
2504  {
2505  std::stable_sort(src.begin(), src.end(), std::move(comp)); // [compilation-error-hint]: expecting sortable container; try fn::to_vector() first.
2506  }
2507 
2508  template<typename Iterable, typename Comp>
2509  static void s_sort(Iterable& src, Comp comp, unstable_sort_tag)
2510  {
2511  std::sort(src.begin(), src.end(), std::move(comp)); // [compilation-error-hint]: expecting sortable container; try fn::to_vector() first.
2512  }
2513  };
2514 
2515  /////////////////////////////////////////////////////////////////////////
2516 
2517  // NB: initially thought of having stable_sort_by and unstable_sort_by versions,
2518  // and for unstable_sort_by/Cont use std::sort, and for unstable_sort_by/seq<..>
2519  // seq use lazy heap sort. The unstable-ness, however, is different between the two.
2520  // So instead decided to go with lazy_sort_by for both Cont and seq<>
2521 
2522  // Initially dump all elements and heapify in O(n);
2523  // lazily yield elements with pop_heap in O(log(n))
2524  //
2525  // TODO: can we make this stable? E.g. falling-back on pointer comparison (probably not)
2526  // or keeping a vector of std::pair<decltype(gen()), size_t> where ::second is the
2527  // original ordinal.
2528  template<typename F>
2530  {
2531  const F key_fn;
2532 
2533  template<typename InGen>
2534  struct gen
2535  {
2536  InGen gen;
2537  const F key_fn;
2538 
2539  using value_type = typename InGen::value_type;
2540  using vec_t = std::vector<value_type>;
2541 
2542  static_assert(std::is_move_assignable<value_type>::value, "value_type must be move-assignable.");
2543 
2544  vec_t heap;
2546 
2548  {
2549  auto op_gt = [this](const value_type& x,
2550  const value_type& y)
2551  {
2552  return lt{}(key_fn(y), key_fn(x));
2553  };
2554 
2555  if(!heapified) {
2556  assert(heap.empty());
2557  heapified = true;
2558 
2559  // TODO: if gen is to_gen wrapper, move elements
2560  // directly from the underlying Iterable.
2561  for(auto x = gen(); x; x = gen()) {
2562  heap.push_back(std::move(*x));
2563  }
2564 
2565  std::make_heap(heap.begin(), heap.end(), op_gt);
2566  }
2567 
2568  if(heap.empty()) {
2569  return { };
2570  }
2571 
2572  std::pop_heap(heap.begin(), heap.end(), op_gt);
2573  auto ret = std::move(heap.back());
2574  heap.pop_back();
2575  return { std::move(ret) };
2576  }
2577  };
2578 
2579  RANGELESS_FN_OVERLOAD_FOR_SEQ( key_fn, {}, false )
2580  RANGELESS_FN_OVERLOAD_FOR_CONT( key_fn, {}, false )
2581  };
2582 
2583  /////////////////////////////////////////////////////////////////////
2584  template<typename F>
2586  {
2587  const F key_fn;
2588  const size_t cap;
2589 
2590  template<typename Iterable>
2591  auto operator()(Iterable src) const -> std::vector<typename Iterable::value_type>
2592  {
2593  // TODO: if Iterable is a vector, do partial-sort, decreasing, take_first(n), and reverse.
2594  //
2595  // Take by forwarding-reference here instead of by-value?
2596  // (Same question as in where_max_by)
2597 
2598  using value_type = typename Iterable::value_type;
2599 
2600  // this will fire if Iterable is std::map, where value_type is std::pair<const Key, Value>,
2601  // which is not move-assignable because of constness.
2602  static_assert(std::is_move_assignable<value_type>::value, "value_type must be move-assignable.");
2603 
2604  auto op_gt = [this](const value_type& x,
2605  const value_type& y)
2606  {
2607  return lt{}(key_fn(y), key_fn(x));
2608  };
2609 
2610  // NB: can't use priority_queue, because it provides
2611  // const-only exposition of elements, so we can't use
2612  // it with move-only types.
2613 
2614  std::vector<value_type> heap{}; // min-heap, (min at front)
2615  heap.reserve(cap);
2616 
2617  if(cap > 0)
2618  for(auto&& x : src)
2619  {
2620  const bool insert =
2621  heap.size() < cap
2622  || [&]
2623  {
2624  const auto& key_x = key_fn(x); // NB: temporary lifetime extension
2625  const auto& key_h = key_fn(heap.front());
2626 
2627  // key_fn is expected to be "light", but in case it's not negligibly light
2628  // we factor-out evaluation of key_fn here, because we can.
2629 
2630  return lt{}(key_x, key_h) ? false // worse than current-min
2631  : lt{}(key_h, key_x) ? true // better than current-min
2632  : false; // equiv to current-min (we're at capacity, so keeping current min)
2633  }();
2634 
2635  if(!insert) {
2636  continue;
2637  }
2638 
2639  if(heap.size() >= cap) {
2640  std::pop_heap(heap.begin(), heap.end(), op_gt);
2641  heap.pop_back();
2642  }
2643 
2644  heap.push_back(std::move(x));
2645  std::push_heap(heap.begin(), heap.end(), op_gt);
2646  }
2647 
2648  std::sort_heap(heap.begin(), heap.end(), op_gt);
2649  std::reverse(heap.begin(), heap.end());
2650 
2651  return heap;
2652  }
2653  };
2654 
2655  /////////////////////////////////////////////////////////////////////
2656  template<typename F, typename BinaryPred = impl::eq>
2658  {
2659  // We parametrize to both key_fn and pred2 to reuse
2660  // this for both
2661  // group_adjacent_by: key_fn:user-provided, pred2=impl::eq
2662  // group_adjacent_if: key_fn=impl::by::identity, pred2:user-provided.
2663 
2664  const F key_fn;
2665  const BinaryPred pred2;
2666 
2667  /////////////////////////////////////////////////////////////////////
2668  // A simple version that accumulates equivalent-group in a vector,
2669  // and yield vector_t. This makes it easy to deal-with (no seq-of
2670  // seqs), but it needs to allocate a return std::vector per-group.
2671  // (Edit: unless the use-case supports recycling (see below))
2672  //
2673  template<typename InGen>
2674  struct gen
2675  {
2676  InGen gen;
2677  const F key_fn;
2678  const BinaryPred pred2;
2679 
2680  using inp_t = typename InGen::value_type;
2681 
2682  using value_type = typename std::conditional<
2683  std::is_same<inp_t, char>::value,
2684  std::string,
2685  std::vector<inp_t> >::type;
2686 
2687  static_assert(std::is_move_assignable<value_type>::value, "value_type must be move-assignable.");
2688 
2689 
2690  value_type next;
2692 
2693  // instead of allocating a new vector, the caller, prior to calling
2694  // the operator(), may choose to disown existing vector so we can
2695  // reuse its internal storage
2696 
2697  void recycle(value_type& grbg)
2698  {
2699  garbage = std::move(grbg);
2700  }
2701 
2703  {
2704  // NB: number of calls to key_fn shall be max(0, 2*(n-1))
2705  // (as required by fn::chunker)
2706 
2707  auto curr = std::move(next);
2708  next = std::move(garbage);
2709  next.clear(); // clearing does not deallocate internal storage
2710 
2711  for(auto x = gen(); x; x = gen()) {
2712  if(curr.empty() || pred2(key_fn(curr.back()), key_fn(*x))) {
2713  curr.push_back(std::move(*x));
2714  } else {
2715  next.push_back(std::move(*x));
2716  break;
2717  }
2718  }
2719 
2720  if(curr.empty()) {
2721  return { };
2722  }
2723 
2724  return std::move(curr);
2725  }
2726  };
2727 
2728  RANGELESS_FN_OVERLOAD_FOR_SEQ( key_fn, pred2, {}, {} )
2729 
2730  // view may be an InputRange, so treat as seq.
2731  RANGELESS_FN_OVERLOAD_FOR_VIEW( key_fn, pred2, {}, {} )
2732 
2733  /////////////////////////////////////////////////////////////////////
2734  template<typename Cont>
2735  auto operator()(Cont cont) const -> std::vector<Cont>
2736  {
2737  // NB: number of calls to key_fn shall be max(0, 2*(n-1))
2738  // (see chunker)
2739 
2740  std::vector<Cont> ret;
2741 
2742  auto it = cont.begin();
2743  const auto it_end = cont.end();
2744 
2745  if(it == it_end) {
2746  return ret;
2747  }
2748 
2749  ret.push_back(Cont{});
2750  ret.back().insert(ret.back().end(), std::move(*it)); // [compilation-error-hint]: Expecting Cont's value-type to be end-insertable container.
2751  ++it;
2752 
2753  for(; it != it_end; ++it) {
2754  if(!pred2(key_fn(*ret.back().crbegin()), // NB: last!
2755  key_fn(*it)))
2756  {
2757  ret.push_back(Cont{});
2758  }
2759  auto& dest = ret.back();
2760  dest.insert(dest.end(), std::move(*it));
2761  }
2762 
2763  return ret;
2764  }
2765  };
2766 
2767 
2768  /////////////////////////////////////////////////////////////////////
2769  template<typename F, typename BinaryPred = impl::eq>
2771  {
2772  const F key_fn;
2773  const BinaryPred pred2;
2774 
2775  template<typename InGen>
2776  struct gen
2777  {
2778  // subgen for subseq - yield elements of the same group
2779  struct subgen
2780  {
2781  using value_type = typename InGen::value_type;
2783 
2785  {
2786  assert(parent);
2787  return parent->next();
2788  }
2789  };
2790 
2791  /////////////////////////////////////////////////////////////////
2792 
2793  using element_type = typename InGen::value_type;
2795 
2796  InGen in_gen;
2797  const F key_fn;
2798  const BinaryPred pred2; // returns true iff two elemens belong to same group
2799  maybe<element_type> current; // current element of the current group
2801 
2802  /////////////////////////////////////////////////////////////////
2803 
2804  maybe<element_type> next() // called from subgen::operator()()
2805  {
2806  if(!current || reached_subend) {
2807  reached_subend = true;
2808  return {};
2809  }
2810 
2811  auto next = in_gen();
2812  reached_subend = !next || !pred2(key_fn(*current), key_fn(*next));
2813  std::swap(current, next);
2814  return std::move(next);
2815  }
2816 
2817  maybe<value_type> operator()() // return seq for next group
2818  {
2819  if(!current) { // starting initial group
2820  current = in_gen();
2821  } else {
2822 
2823  // NB: the user-code may have accessed the group only
2824  // partially (or not at all), in which case we must skip
2825  // over the rest elements in the group until we reach
2826  // the next one.
2827  while(!reached_subend) {
2828  next();
2829  }
2830  }
2831 
2832  if(!current) { // reached final end
2833  return {};
2834  }
2835 
2836  reached_subend = false;
2837  return { subgen{ this } };
2838  }
2839  };
2840 
2841  RANGELESS_FN_OVERLOAD_FOR_SEQ( key_fn, pred2, {}, false )
2842  RANGELESS_FN_OVERLOAD_FOR_VIEW( key_fn, pred2, {}, false )
2843  RANGELESS_FN_OVERLOAD_FOR_CONT( key_fn, pred2, {}, false )
2844  };
2845 
2846 
2847  /////////////////////////////////////////////////////////////////////
2848  // used for in_groups_of(n)
2849  struct chunker
2850  {
2851  const size_t chunk_size;
2852  mutable size_t n_calls;
2853 
2854  template<typename T>
2855  size_t operator()(const T&) const
2856  {
2857  // chunker is called with group_adjacent_by.
2858  // If we had one call to key_fn per element,
2859  // we could chunk in groups of 10 like
2860  // elems % fn::group_adjacent_by([n = 0UL](const auto){ return n++/10; });
2861  //
2862  // in group_adjacent_by we call the key_fn 2*(n-1) times.
2863  return ++n_calls/2/chunk_size;
2864  }
2865  };
2866 
2867  /////////////////////////////////////////////////////////////////////
2868  template<typename F>
2870  {
2871  private:
2873 
2874  public:
2875  const F key_fn;
2876 
2877  // group_all_by: convert input to vector, sort by key_fn,
2878  // and delegate to group_adjacent_by::gen
2879  //
2880  // (could instead delegate to the eager overload below,
2881  // since we need to do the sort anyway, but the difference
2882  // is that group_adjacent_by will recycle std::vector storage
2883  // while yielding groups one by one, rather than having to
2884  // allocate a separate std::vector per-group.
2885 
2886  template<typename Gen> // Cont or seq<...>
2887  auto operator()(seq<Gen> range) const ->
2888  seq<
2889  typename group_adjacent_by_t::template gen<
2890  to_seq::gen<
2891  std::vector<typename seq<Gen>::value_type>>>>
2892  {
2893  return
2894  group_adjacent_by_t{ key_fn, {} }(
2895  impl::to_seq{}(
2896  sort_by<F>{ key_fn }(
2897  impl::to_vector{}(
2898  std::move(range)))));
2899  }
2900 
2901  /////////////////////////////////////////////////////////////////
2902  template<typename Cont>
2903  auto operator()(Cont cont) const
2904  //-> std::vector<std::vector<typename Cont::value_type>>
2905  //The above is almost correct, except if Cont is a map,
2906  //conversion to vector removes the key-constness, so we
2907  //need to do it via decltype
2908  -> decltype(
2909  group_adjacent_by_t{ key_fn, {} }(
2910  impl::to_vector{}(
2911  std::move(cont))))
2912  {
2913 #if 0
2914  // An example of what not to do
2915  using key_t = remove_cvref_t<decltype(key_fn(*cont.begin()))>;
2916  std::map<key_t, Cont, lt_t> m;
2917  for(auto&& x : cont) {
2918  auto& dest = m[key_fn(x)];
2919  dest.insert(dest.end(), std::move(x));
2920  // BUG: the key in the map just became invalidated
2921  // after move(x), if it contained references to it.
2922  }
2923  cont.clear();
2924 
2925  std::vector<Cont> ret;
2926  ret.reserve(m.size());
2927  for(auto& kv : m) {
2928  ret.push_back(std::move(kv.second));
2929  }
2930  return ret;
2931 
2932  // Can't also implement is as collect elems into
2933  // std::set<Cont, decltype(opless_by_keyfn_on_element)>,
2934  // because if value_type is move-only, we won't be able
2935  // to move-out the elements from the set since
2936  // set provides only const access to the elements.
2937 #else
2938  return group_adjacent_by_t{ key_fn, {} }(
2939  impl::sort_by<F>{ key_fn }(
2940  impl::to_vector{}(
2941  std::move(cont))));
2942 #endif
2943  }
2944  };
2945 
2946 
2947 
2948  /////////////////////////////////////////////////////////////////////
2949  // Flatten a range-of-ranges.
2950  // Inverse of group_all_by or group_adjacent_by(original elements are in key-order)
2951  //
2952  // This is the bind operator for the List monad.
2953  //
2954  // What do we name this?
2955  //
2956  // Haskell: concat
2957  // Elixir: concat
2958  // Elm: concat
2959  // O'Caml: concat, flatten
2960  // Scala: flatten
2961  // clojure: flatten
2962  // python: chain
2963  // D: chain
2964  // F#: collect
2965  // javascript: flat
2966  // range-v3: join
2967  // LINQ: SelectMany
2968  //
2969  struct concat
2970  {
2971  template<typename InGen>
2972  struct gen
2973  {
2974  InGen gen;
2975 
2976  using gen_value_t = typename InGen::value_type;
2978  // via maybe, because might not be default-constructible;
2979  // or could be a seq<...>, holding a closure under the hood,
2980  // rendering the seq not move-assigneable.
2981 
2982  using iterator = typename gen_value_t::iterator;
2983  using value_type = typename gen_value_t::value_type;
2984 
2987 
2988 #if 0 // We don't really need this
2989 
2990  // -Weffc++ recommends explicit assignment operator because
2991  // we have pointer members (presumably current_group), so we
2992  // explicitly make this move-only.
2993  gen& operator=(gen&&) = default;
2994  gen(gen&&) = default;
2995 
2996  gen& operator=(const gen&) = delete;
2997  gen(const gen&) = delete;
2998 #endif
2999 
3001  {
3002  // get next group if !started or reached end-of-current
3003  while(!current_group || it == (*current_group).end()) {
3004  current_group = gen();
3005 
3006  if(!current_group) {
3007  return { };
3008  }
3009 
3010  it = (*current_group).begin();
3011  }
3012 
3013  //postfix++ may not be available
3014  value_type ret = std::move(*it);
3015  ++it;
3016  return { std::move(ret) };
3017  }
3018  };
3019 
3020  RANGELESS_FN_OVERLOAD_FOR_SEQ( {}, typename gen<InGen>::iterator() )
3021  //^^ simply {} does not compile with GCC-4.9.3
3022 
3023  /////////////////////////////////////////////////////////////////
3024 
3025  template<typename Iterable,
3026  typename Ret = typename Iterable::value_type>
3027  Ret operator()(Iterable src) const
3028  {
3029  // TODO: return a vector instead? What if cont is a set or a map?
3030 
3031  Ret ret{};
3032  ret.clear(); // [compilation-error-hint]: Expecting Iterable::value_type to be a container.
3033 
3034  for(auto&& v : src) {
3035  ret.insert(ret.end(),
3036  std::make_move_iterator(v.begin()),
3037  std::make_move_iterator(v.end()));
3038  }
3039 
3040  return ret;
3041  }
3042 
3043  // The case of vector-of-seq can't be handled by the above overload,
3044  // because seq can't be end-inserted into.
3045  // So we'll wrap container-of-seq into seq, and treat as seq-of-seq.
3046  template<typename Gen>
3047  auto operator()(std::vector<seq<Gen>> vec_of_seqs) const
3049  { //^^^^^^^^^^^^^^^^^^^^^ input vec
3050  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ wrapped as seq
3051  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ composed with this
3052  // TODO: needs a test.
3053 
3054  return { { { std::move(vec_of_seqs) } } };
3055  }
3056  };
3057 
3058 
3059  /////////////////////////////////////////////////////////////////////
3060  template<typename F>
3062  {
3063  const F key_fn;
3064 
3065  template<typename InGen>
3066  struct gen
3067  {
3068  InGen gen;
3069  const F key_fn;
3070 
3071  using value_type = typename InGen::value_type;
3072 
3074  // wrapped into maybe, because might not be default-constructible
3075 
3077 
3079  {
3080  auto curr = std::move(next);
3081  next.reset();
3082 
3083  for(auto x = gen(); x; x = gen()) {
3084  if(!curr) {
3085  curr = std::move(x);
3086  } else if( impl::eq{}(key_fn(*curr), key_fn(*x))) {
3087  continue; // skip equivalent elements
3088  } else {
3089  next = std::move(x);
3090  break;
3091  }
3092  }
3093 
3094  return curr;
3095  }
3096  };
3097 
3099 
3100  template<typename Iterable>
3101  Iterable operator()(Iterable inps) const
3102  {
3103  impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
3104 
3105  inps.erase(
3106  std::unique(
3107  inps.begin(), inps.end(),
3108  [this](const typename Iterable::value_type& x,
3109  const typename Iterable::value_type& y)
3110  {
3111  return impl::eq{}(key_fn(x), key_fn(y));
3112  }),
3113  inps.end());
3114 
3115  return inps;
3116  }
3117  };
3118 
3119 
3120 
3121  /////////////////////////////////////////////////////////////////////
3122  template<typename F>
3124  {
3125  const F key_fn;
3126 
3127  template<typename InGen>
3128  struct gen
3129  {
3130  InGen gen;
3131  const F key_fn; // lifetime of returned key shall be independent of arg.
3132 
3133  using value_type = typename InGen::value_type;
3134 
3135  using key_t = typename std::decay<decltype(key_fn(*gen()))>::type;
3136  // key_fn normally yields a const-reference, but we'll be storing
3137  // keys in a map, so need to decay the type (remove_cvref would do).
3138 
3139  static_assert(std::is_default_constructible<key_t>::value, "The type returned by key_fn in unique_all_by must be default-constructible and have the lifetime independent of arg.");
3140  // In case key_fn returns a reference-wrapper or a tie-tuple containing
3141  // a reference, these will become invalidated as keys in the map
3142  // when the referenced object goes out of scope, so we guard against
3143  // these by requiring default-constructible on key_t.
3144 
3145  using seen_t = std::map<key_t, bool>;
3146  // might as well have used std::set, but to #include fewer things will
3147  // repurpose std::map that's already included for other things.
3148 
3150 
3152  {
3153  auto x = gen();
3154 
3155  if(!x) {
3156  return { };
3157  }
3158  auto k = key_fn(*x);
3159 
3160  while(!seen.emplace(std::move(k), true).second) {
3161  x = gen();
3162  if(!x) {
3163  break;
3164  }
3165  k = key_fn(*x);
3166  }
3167  return x;
3168  }
3169  };
3170 
3172 
3173 
3174  template<typename Iterable>
3175  auto operator()(Iterable src) const
3176  -> decltype( // see the corresponding overload in group_all_by
3177  unique_adjacent_by<F>{ key_fn }(
3178  to_vector{}(
3179  std::move(src))))
3180  {
3181  return unique_adjacent_by<F>{ key_fn }(
3182  sort_by<F>{ key_fn }(
3183  to_vector{}(
3184  std::move(src))));
3185  }
3186  };
3187 
3188 
3189  /////////////////////////////////////////////////////////////////////
3190  // Concat a pair of (possibly heterogeous) `Iterables`.
3191  template<typename Iterable2>
3192  struct append
3193  {
3194  Iterable2 src2;
3195 
3196  template<typename Iterable1>
3197  struct gen
3198  {
3199  Iterable1 inps1;
3200  Iterable2 inps2;
3201  typename Iterable1::iterator it1;
3202  typename Iterable2::iterator it2;
3203  int which; // 0: not-started;
3204  // 1: in range1
3205  // 2: in range2
3206  using value_type =
3207  typename std::common_type<
3208  typename Iterable1::value_type,
3209  typename Iterable2::value_type
3210  >::type;
3211 
3213  {
3214  return which == 1 && it1 != inps1.end() ? std::move(*it1++)
3215  : which == 2 && it2 != inps2.end() ? std::move(*it2++)
3216  : which == 0 ? (which = 1, it1 = inps1.begin(), (*this)())
3217  : which == 1 ? (which = 2, it2 = inps2.begin(), (*this)())
3218  : maybe<value_type>{ };
3219  }
3220  };
3221 
3222  template<typename Iterable1>
3223  auto operator()(Iterable1 src1) && -> seq<gen<Iterable1>> // rvalue-specific because src2 is moved-from
3224  {
3225  return { { std::move(src1), std::move(src2), {}, {}, 0 } };
3226  }
3227  };
3228 
3229  /////////////////////////////////////////////////////////////////////
3230  template<typename Iterable2, typename BinaryFn>
3231  struct zip_with
3232  {
3233  Iterable2 src2;
3234  BinaryFn fn;
3235 
3236  template<typename Iterable1>
3237  struct gen
3238  {
3239  BinaryFn fn;
3240  Iterable1 src1;
3241  Iterable2 src2;
3242  typename Iterable1::iterator it1;
3243  typename Iterable2::iterator it2;
3244  bool started;
3245 
3246  using value_type = decltype(fn(std::move(*it1),
3247  std::move(*it2)));
3248 
3250  {
3251  if(!started) {
3252  it1 = src1.begin();
3253  it2 = src2.begin();
3254  started = true;
3255  }
3256 
3257  if(it1 == src1.end() || it2 == src2.end()) {
3258  return { };
3259  }
3260 
3261  auto ret = fn(std::move(*it1), std::move(*it2));
3262  ++it1;
3263  ++it2;
3264  return { std::move(ret) };
3265  }
3266  };
3267 
3268  template<typename Iterable1>
3269  auto operator()(Iterable1 src1) && -> seq<gen<Iterable1>> // rvalue-specific because src2 is moved-from
3270  {
3271  return { { std::move(fn), std::move(src1), std::move(src2), {}, {}, false } };
3272  }
3273  };
3274 
3275  /////////////////////////////////////////////////////////////////////////
3276  template<typename BinaryFn>
3278  {
3279  BinaryFn fn;
3280 
3281  template<typename Iterable>
3282  struct gen
3283  {
3284  BinaryFn fn;
3285  Iterable src;
3286  typename Iterable::iterator it;
3287  bool started;
3288 
3289  using value_type = decltype(fn(*it, *it));
3290 
3292  {
3293  if(!started) {
3294  it = src.begin();
3295  started = true;
3296  }
3297 
3298  auto prev_it = it == src.end() ? it : it++;
3299 
3300  if(it != src.end()) {
3301  return { fn(*prev_it, *it) };
3302  } else {
3303  return { };
3304  }
3305  }
3306  };
3307 
3308  template<typename Iterable>
3309  auto operator()(Iterable src) && -> seq<gen<Iterable>>
3310  {
3311  impl::require_iterator_category_at_least<std::forward_iterator_tag>(src);
3312  return { { std::move(fn), std::move(src), {}, false } };
3313  }
3314  };
3315 
3316  /////////////////////////////////////////////////////////////////////////
3317  template<typename Iterable2, typename BinaryFn>
3319  {
3320  Iterable2 src2;
3321  BinaryFn fn;
3322 
3323  template<typename Iterable1>
3324  struct gen
3325  {
3326  BinaryFn fn;
3327  Iterable1 src1;
3328  Iterable2 src2;
3329  typename Iterable1::iterator it1;
3330  typename Iterable2::iterator it2;
3331  bool started;
3332 
3333  // Checking against input-range semantics.
3334  // Checking against moving iterators (yielding rvalue-references)
3335  // because if fn takes a param by value and the iterator yields
3336  // it will be moved-from.
3337  static_assert(!std::is_rvalue_reference<decltype(*--it1)>::value, "For cartesian-product expecting upstream iterable to be a bidirectional range yielding lvalue-references or values");
3338  static_assert(!std::is_rvalue_reference<decltype(*--it2)>::value, "For cartesian-product expecting parameter-iterable to be a bidirectional range yielding lvalue-references or values");
3339 
3340  using value_type = decltype(fn(*it1, *it2));
3341 
3343  {
3344  if(!started) {
3345  it1 = src1.begin();
3346  it2 = src2.begin();
3347  started = true;
3348  if(it1 == src1.end() || it2 == src2.end()) {
3349  return { };
3350  }
3351  }
3352 
3353  while(it2 == src2.end()) {
3354  it2 = src2.begin();
3355 
3356  ++it1;
3357  if(it1 == src1.end()) {
3358  return { };
3359  }
3360  }
3361 
3362  auto ret = fn(*it1, *it2);
3363  ++it2;
3364  return { std::move(ret) };
3365  }
3366  };
3367 
3368  template<typename Iterable1>
3369  auto operator()(Iterable1 src1) && -> seq<gen<Iterable1>> // rvalue-specific because range2 is moved-from
3370  {
3371  return { { std::move(fn), std::move(src1), std::move(src2), {}, {}, false } };
3372  }
3373  };
3374 
3375  /////////////////////////////////////////////////////////////////////////
3376 
3378  {
3379  template<class Ret, class Arg>
3381  {
3382  using ret = Ret;
3383  using arg = Arg;
3384  };
3385 
3386  template<class L>
3388  : lambda_traits<decltype(&L::operator())>
3389  {};
3390 
3391  // NB: not providing non-const version (must be pure)
3392  template<class Ret, class Class, class Arg>
3393  struct lambda_traits<Ret(Class::*)(Arg) const>
3394  : lambda_traits_detail<Ret, Arg>
3395  {};
3396  };
3397 
3398  template<typename F>
3399  struct memoizer
3400  {
3402  using Arg = typename std::remove_reference<typename traits::arg>::type;
3403  using Ret = typename traits::ret; // NB: can be const and/or reference
3404  using Cache = std::map<Arg, Ret>;
3405 
3406  F fn;
3407  mutable Cache m; // mutable, because operator() must be const
3408  // e.g. we may be memoizing some key_fn, and
3409  // those are expected to be const
3410 
3411  const Ret& operator()(const Arg& arg) const
3412  {
3413  auto it = m.find(arg);
3414  return it != m.end() ? it->second
3415  : m.emplace(arg, fn(arg)).first->second;
3416  }
3417  };
3418 
3419  /////////////////////////////////////////////////////////////////////////
3420  template<typename F>
3422  {
3423  F fn;
3425 
3426  void dismiss()
3427  {
3428  dismissed = true;
3429  }
3430 
3431  ~scope_guard() noexcept(noexcept(fn()))
3432  {
3433  if(!dismissed)
3434  fn(); // NB: it's up to m_fn to decide whether to catch exceptions.
3435  }
3436  };
3437 
3438 
3439 } // namespace impl
3440 
3441  /////////////////////////////////////////////////////////////////////////
3442 
3443  template<typename T>
3445 
3446  /// @brief Type-erase a `seq`.
3447  ///
3448  /// Wrap the underlying nullary invokable as std::function.
3449  template<typename Gen, typename T = typename Gen::value_type>
3451  {
3452  return { std::move(seq) };
3453  }
3454 
3455  /// @defgroup to_vec to_vector/to_seq
3456  /// @{
3457 
3458  /// @brief Move elements of an `Iterable` to std::vector.
3460  {
3461  return {};
3462  }
3463 
3464  /// @brief Wrap an `Iterable`, taken by value, as `seq` yielding elements by-move.
3465  ///
3466  /// This is a dual of `to_vector`. It can be used to adapt your own `InputRange` as
3467  /// `seq`, but it can also be used to wrap a container to force lazy evaluation
3468  /// e.g. `std::move(container) % fn::to_seq() % fn::group_adjacent_by(key_fn) % fn::take_first()`
3470  {
3471  return {};
3472  }
3473 
3474  /// e.g. `auto set_of_ints = fn::seq(...) % ... % fn::to(std::set<int>{})`;
3475  template<typename Container>
3476  impl::to<Container> to(Container dest)
3477  {
3478  return { std::move(dest) };
3479  }
3480 
3481  /// @brief return map: value_type -> size_t
3483  {
3484  return {};
3485  }
3486 
3487 
3488  /// @}
3489  /// @defgroup transform Transform and Adapt
3490  ///
3491  /// @{
3492 
3493  /// @brief Create a custom processing-stage function-object.
3494  ///
3495  /// This is somewhat similar to `fn::transform`, except the correspondence between
3496  /// inputs and outputs is not necessarily 1:1, and instead of taking a single element to transform
3497  /// we take a nullary generator callable `gen` and use it to fetch however many input elements
3498  /// we need to generate the next output element.
3499  ///
3500  /// NB: If `bool(gen)==false`, the next invocation of gen() shall throw `fn::end_seq::exception` signaling end-of-inputs.
3501  /*!
3502  @code
3503  auto my_transform = [](auto fn)
3504  {
3505  return fn::adapt([fn = std::move(fn)](auto gen)
3506  {
3507  return fn(gen());
3508  });
3509  };
3510 
3511  auto my_where = [](auto pred)
3512  {
3513  return fn::adapt([pred = std::move(pred)](auto gen)
3514  {
3515  auto x = gen();
3516  while(!pred(x)) {
3517  x = gen();
3518  }
3519  return x;
3520  });
3521  };
3522 
3523  auto my_take_while = [](auto pred)
3524  {
3525  return fn::adapt([pred = std::move(pred)](auto gen)
3526  {
3527  auto x = gen();
3528  return pred(x) ? std::move(x) : fn::end_seq();
3529  });
3530  };
3531 
3532  auto my_intersperse = [](auto delim)
3533  {
3534 #if 1
3535  return [delim = std::move(delim)](auto inputs)
3536  {
3537  return fn::seq([ delim,
3538  inputs = std::move(inputs),
3539  it = inputs.end(),
3540  started = false,
3541  flag = false]() mutable
3542  {
3543  if(!started) {
3544  started = true;
3545  it = inputs.begin();
3546  }
3547  return it == inputs.end() ? fn::end_seq()
3548  : (flag = !flag) ? std::move(*it++)
3549  : delim;
3550  });
3551  };
3552 
3553 #elif 0 // or
3554 
3555  return [delim = std::move(delim)](auto inputs)
3556  {
3557  return std::move(inputs)
3558  % fn::transform([delim](auto inp)
3559  {
3560  return std::array<decltype(inp), 2>{{ std::move(inp), delim }};
3561  })
3562  % fn::concat()
3563  % fn::drop_last(); // drop trailing delim
3564  };
3565 
3566 #else // or
3567 
3568  return fn::adapt([delim, flag = false](auto gen) mutable
3569  {
3570  return !gen ? fn::end_seq()
3571  : (flag = !flag) ? gen()
3572  : delim;
3573  });
3574 #endif
3575  };
3576 
3577 
3578  auto my_inclusive_scan = []
3579  {
3580  return fn::adapt([sum = 0](auto gen) mutable
3581  {
3582  return sum += gen();
3583  });
3584  };
3585 
3586  auto res =
3587  fn::seq([i = 0]() mutable
3588  {
3589  return i++;
3590  }) // 0,1,2,3,...
3591 
3592  % my_where([](int x)
3593  {
3594  return x >= 3;
3595  }) // 3,4,5,...
3596 
3597  % my_take_while([](int x)
3598  {
3599  return x <= 5;
3600  }) // 3,4,5
3601 
3602  % my_intersperse(-1) // 3,-1,4,-1,5
3603 
3604  % my_transform([](int x)
3605  {
3606  return x + 1;
3607  }) // 4,0,5,0,6
3608 
3609  % my_inclusive_scan() // 4,4,9,9,15
3610 
3611  % fn::to_vector();
3612 
3613  VERIFY((res == vec_t{{4, 4, 9, 9, 15}}));
3614  @endcode
3615 
3616  A more realistic example: suppose you have a pipeline
3617  transforming inputs to outputs in parallel, and you want to
3618  compress the output, but the outputs are small and compressing
3619  them individually would be ineffective, and you want to
3620  serialize the incoming results into a buffer of some minimum
3621  size, e.g. 100kb, before passing it to the compressing stage.
3622  @code
3623  auto make_result = [](std::string s){ return s; };
3624  auto compress_block = [](std::string s){ return s; };
3625  auto write_to_ostr = [](std::string s){ std::cout << s; };
3626 
3627  namespace fn = rangeless::fn;
3628  using fn::operators::operator%;
3629 
3630  fn::seq([&]() -> std::string
3631  {
3632  std::string line;
3633  return std::getline(std::cin, line) ? std::move(line)
3634  : fn::end_seq();
3635  })
3636 
3637  % fn::transform_in_parallel(make_result)
3638 
3639  % fn::adapt([](auto get_next)
3640  {
3641  std::ostringstream buf{};
3642 
3643  while(get_next && buf.tellp() < 100000) {
3644  buf << get_next();
3645  }
3646 
3647  return buf.tellp() ? buf.str() : fn::end_seq();
3648  })
3649 
3650  % fn::transform_in_parallel(compress_block)
3651 
3652  % fn::for_each(write_to_ostr);
3653 
3654  @endcode
3655  */
3656  template<typename F>
3658  {
3659  return { std::move(fn) };
3660  }
3661 
3662  ///////////////////////////////////////////////////////////////////////////
3663  /// @brief Create a `seq` yielding results of applying the transform functions to input-elements.
3664  ///
3665  /// Returns a unary function-object, which will capture the arg by value and
3666  /// return an adapted `seq<...>` which will yield results of invoking
3667  /// `map_fn` on the elements (passed by value) of arg.
3668  /// See `fn::where` for an example.
3669  template<typename F>
3671  {
3672  // Rationale:
3673  // <br>
3674  // 1) A possible implementation for a container-input could assume that
3675  // `transform` function is inexpensive to recompute on-demand (this is
3676  // this approach in `range-v3` which may call `transform` multiple times
3677  // per element depending on the access pattern from the downstream views).
3678  //
3679  // 2) An implementation could require the result-type to be cacheable
3680  // and assume it is 'light' in terms of memory requirements and memoize the results.
3681  //
3682  // Our approach of applying `transform` lazily allows us to
3683  // make neither assumption and apply `transform` at most once per element and without caching.
3684  // The user-code may always follow that by fn::to_vector() when necessary.
3685 
3686  return { std::move(map_fn) };
3687  }
3688 
3689 #if 0
3690  // see comments around struct composed
3691  template<typename F, typename... Fs>
3692  auto transform(F fn, Fs... fns) -> impl::transform<decltype(impl::compose(std::move(fn), std::move(fns)...))>
3693  {
3694  return { impl::compose(std::move(fn), std::move(fns)...) };
3695  }
3696 #endif
3697 
3698 
3699 
3700 
3701  /// @}
3702  /// @defgroup folding Folds and Loops
3703  /// @{
3704 
3705  /////////////////////////////////////////////////////////////////////////////
3706  /*! @brief Range-based version of c++20 (copy-free) `std::accumulate`
3707  *
3708  * @see foldl_d
3709  * @see foldl_1
3710  @code
3711  using namespace fn::operators;
3712  const std::string x = vec_t{ 1, 2, 3 }
3713  % fn::foldl(std::string{"^"}, // init
3714  [](std::string out, int in) // fold-op
3715  {
3716  return std::move(out) + "|" + std::to_string(in);
3717  });
3718 
3719  VERIFY(x == "^|1|2|3");
3720  @endcode
3721 
3722  NB: The body of the fold-loop is `init = binary_op(std::move(init), *it);`
3723  If `it` is a `move`-ing iterator, like that of an `seq`,
3724  you'd take `in` by value or rvalue-reference in your binary operator,
3725  whereas if it's a regular iterator yielding lvalue-references, you'd
3726  take it by const or non-const reference.
3727  */
3728  template<typename Result, typename Op>
3729  impl::foldl<Result, Op> foldl(Result init, Op binary_op)
3730  {
3731  // NB: idiomatically the init value goes after the binary op,
3732  // but most of the time binary-op is a multiline lambda, and having
3733  // the init arg visually far-removed from the call-site
3734  // make things less readable, i.e. foldl([](...){ many lines }, init).
3735  // So placing the binary-op last.
3736  // (Tried it both ways, and found this order preferable).
3737 
3738  return { std::move(init), std::move(binary_op) };
3739  }
3740 
3741  /// Fold-Left-with-Default: this version uses default-initialized value for init.
3742  /*!
3743  * @see foldl
3744  * @see foldl_1
3745  @code
3746  const std::string x = vec_t{ 1, 2, 3 }
3747  % fn::foldl_d(
3748  [](std::string out, int in)
3749  {
3750  return std::move(out) + "|" + std::to_string(in);
3751  });
3752 
3753  VERIFY(x == "|1|2|3");
3754  @endcode
3755  */
3756  template<typename Op>
3758  {
3759  return { std::move(binary_op) };
3760  }
3761 
3762  /////////////////////////////////////////////////////////////////////////////
3763  /// Init-free version of foldl (first element is used as init); requires at least one element.
3764  /*!
3765  * @see foldl
3766  * @see foldl_d
3767  *
3768  @code
3769  const auto min_int =
3770  std::vector<std::string>{{ "11", "-333", "22" }}
3771  % fn::transform([](const string& s) { return std::stoi(s); })
3772  % fn::foldl_1([](int out, int in) { return std::min(out, in); });
3773 
3774  VERIFY(min_int == -333);
3775  @endcode
3776  */
3777  template<typename Op>
3779  {
3780  return { std::move(binary_op) };
3781  }
3782 
3783 
3784  /// Return a `seq` yielding a view of a fixed-sized sliding window over elements.
3785  ///
3786  /// If the input is a `seq`, last `win_size` elements are internally cached in a deque.
3787  /*!
3788  @code
3789  const auto result =
3790  make_inputs({ 1,2,3,4 })
3791  % fn::sliding_window(2)
3792  % fn::foldl(0L, [](long out, auto v)
3793  {
3794  VERIFY(std::distance(v.begin(), v.end()) == 2);
3795  auto it = v.begin();
3796  return (out * 1000) + (*it * 10) + *std::next(it);
3797  });
3798  VERIFY(result == 12023034);
3799  @endcode
3800  */
3801  inline impl::sliding_window sliding_window(size_t win_size)
3802  {
3803  return { win_size };
3804  }
3805 
3806  /// Invoke fn on each element.
3807  ///
3808  /// NB: this is similar to a left-fold with binary-op `(nullptr_t, x) -> nullptr_t`
3809  /// where `x` is consumed by-side-effect, and the binary-op is simplified to unary `(x)->void`.
3810  template<typename F>
3812  {
3813  return { std::move(fn) };
3814  }
3815 
3816 
3817  /// Invoke binary fn on each pair of adjacent elements.
3818  ///
3819  /// NB: the inputs must satisfy `ForwardRange` or stronger.
3820  template<typename F2>
3822  {
3823  return { std::move(fn2) };
3824  }
3825 
3826  /// @}
3827  /// @defgroup filtering Filtering
3828  /// @{
3829 
3830  /// @brief Yield elements until pred evaluates to false.
3831  template<typename P>
3833  {
3834  return { std::move(pred) };
3835  }
3836 
3837  /// @brief Yield first `n` elements.
3839  {
3840  return {{ n, 0UL }};
3841  }
3842 
3843  /// @brief Yield last `n` elements.
3844  ///
3845  /// Buffering space requirements for `seq`: `O(n)`.
3846  inline impl::take_last take_last(size_t n = 1)
3847  {
3848  return { n };
3849  }
3850 
3851  /// @brief Drop elements until pred evaluates to false.
3852  template<typename P>
3854  {
3855  return { std::move(pred) };
3856  }
3857 
3858  /// @brief Drop first `n` elements.
3860  {
3861  return {{ n, 0UL }};
3862  }
3863 
3864  /// @brief Drop last `n` elements.
3865  ///
3866  /// Buffering space requirements for `seq`: `O(n)`.
3867  inline impl::drop_last drop_last(size_t n = 1)
3868  {
3869  return { n };
3870  }
3871 
3872  ///////////////////////////////////////////////////////////////////////////
3873  /// @brief Filter elements.
3874  ///
3875  /// Returns a unary function-object.
3876  /*!
3877  @code
3878  // 1) If arg is a container passed by lvalue-reference,
3879  // return a copy of the container with elements
3880  // satisfying the predicate:
3881  auto nonempty_strs = strs % fn::where([](auto&& s) { return !s.empty(); });
3882 
3883  // 2.1) If arg is a sequence container passed by rvalue,
3884  // remove the unsatisfying elements using erase-remove idiom and return the container.
3885  //
3886  // 2.2) If arg is a container having equal_range method (sets, associative containers, etc),
3887  // remove the unsatisfying elements using iterate-erase idiom and return the container.
3888  strs = std::move(strs) % fn::where([](auto&& s) { return !s.empty(); });
3889 
3890  // 3) If arg is a seq<G>, return adapted seq<...> that shall
3891  // yield elements satisfying the predicate:
3892  auto res = fn::seq([i = 0]
3893  {
3894  return i < 5 ? i++ : fn::end_seq();
3895 
3896  }) % fn::where( [](int x) { return x > 2; }) // 3, 4
3897  % fn::transform( [](int x) { return x + 1; }) // 4, 5
3898  % fn::foldl_d( [](int out, int in) { return out*10 + in; });
3899  VERIFY(res == 45);
3900  @endcode
3901  */
3902  template<typename P>
3904  {
3905  return { std::move(pred) };
3906  }
3907 
3908  /// @see `where_in_sorted`
3909  template<typename SortedForwardRange, typename F>
3911  {
3912  return { { r, false, { std::move(key_fn) } } };
3913  }
3914 
3915  ///////////////////////////////////////////////////////////////////////////
3916  /// @brief Intersect with a sorted range.
3917  ///
3918  /// `elems %= fn::where_in_sorted(whitelist);`
3919  template<typename SortedForwardRange>
3921  {
3922  return { { r, false, { { } } } };
3923  }
3924 
3925  /// @see `where_not_in_sorted`
3926  template<typename SortedForwardRange, typename F>
3928  {
3929  return { { r, true, { std::move(key_fn) } } };
3930  }
3931 
3932  ///////////////////////////////////////////////////////////////////////////
3933  /// @brief Subtract a sorted range.
3934  ///
3935  /// `elems %= fn::where_not_in_sorted(blacklist);`
3936  template<typename SortedForwardRange>
3938  {
3939  return { { r, true, { { } } } };
3940  }
3941 
3942 
3943 
3944  ///////////////////////////////////////////////////////////////////////////
3945  /// @brief Filter elements to those having maximum value of fn.
3946  ///
3947  /*!
3948  @code
3949  // 1) If Arg is a container (taken by value), find the max-element
3950  // and return a vector of max-elements (moved-from the original container).
3951  strs = std::move(strs) % fn::where_max_by([](auto&& s) { return s.size(); });
3952 
3953  // 2) If Arg is a seq, iterates the seq and returns
3954  // std::vector<seq<...>::value_type> containing maximal elements.
3955  auto res = fn::seq([i = 0]
3956  {
3957  return i < 5 ? i++ : fn::end_seq();
3958  }) % fn::where_max_by([](int x) { return x % 2; });
3959  VERIFY((res == vec_t{{1, 3}}));
3960  @endcode
3961 
3962  Buffering space requirements for `seq`: `O(k)`, where `k` = maximum number of max-elements in a prefix of seq over all prefixes of seq.
3963  e.g.
3964  <br>`[1,0,1,1,0,1,1,9]: k = 5`
3965  <br>`[1,3,1,1,3,1,1,9]: k = 2`
3966  */
3967  template<typename F>
3969  {
3970  return { std::move(key_fn), 1 };
3971  }
3972 
3974  {
3975  return { by::identity{}, 1 };
3976  }
3977 
3978  /// Filter elements to those having maximum value of fn.
3979  /// @see where_max_by
3980  template<typename F>
3982  {
3983  return { std::move(key_fn), -1 };
3984  }
3985 
3987  {
3988  return { by::identity{}, -1 };
3989  }
3990 
3991  /// @code
3992  /// const bool any = vals % fn::exists_where(pred);
3993  /// const bool none = vals % !fn::exists_where(pred);
3994  /// const bool all = vals % !fn::exists_where(not_pred);
3995  /// @endcode
3996  template<typename Pred>
3998  {
3999  return { std::move(p), true };
4000  }
4001 
4002 
4003  /// @}
4004  /// @defgroup grouping Grouping
4005  /// @{
4006 
4007  /// @brief Similar to `group_adjacent_by`, but presorts the elements.
4008  ///
4009  /// @see group_adjacent_by
4010  /*!
4011  @code
4012  using alns_t = std::vector<CRef<CSeq_align>>;
4013 
4014  std::move(alignments)
4015 
4016  % fn::group_all_by([&](CConstRef<CSeq_align> aln)
4017  {
4018  return GetLocusId( aln->GetSeq_id(0) );
4019  })
4020 
4021  % fn::for_each([&](alns_t alns)
4022  {
4023  // Process alignments for a locus...
4024  });
4025 
4026  Note: template<typename Cont> impl::group_all_by<F>::operator()(Cont inputs)
4027  takes Cont by-value and moves elements into the output.
4028  @endcode
4029 
4030  Buffering space requirements for `seq`: `O(N)`.
4031  */
4032  template<typename F>
4034  {
4035  return { std::move(key_fn) };
4036  }
4037 
4039  {
4040  return { by::identity{} };
4041  }
4042 
4043  /////////////////////////////////////////////////////////////////////////
4044 
4045  /// @brief Group adjacent elements.
4046  /// @see group_all_by
4047  /// @see concat
4048  ///
4049  /// If arg is a container, works similar to `group_all_by`, except
4050  /// returns a `std::vector<Cont>` where each container
4051  /// contains adjacently-equal elements having same value of key.
4052  ///
4053  /// If arg is a `seq<...>`, composes a `seq<...>`
4054  /// that shall yield `vector<value_type>`s having same value of key.
4055  /// (NB: if the value_type is a char, the group-type is std::string).
4056  ///
4057  /// Buffering space requirements for `seq`: `O(max-groupsize)`.
4058  template<typename F>
4060  {
4061  return { std::move(key_fn), {} };
4062  }
4063 
4064  /////////////////////////////////////////////////////////////////////////
4065  /// @brief Group adjacent elements.
4066  ///
4067  /// This is similar to regular `group_adjacent_by`, except the result type
4068  /// is a seq yielding subseqs of equivalent elements, rather than vectors.
4069  /// @code
4070  /// fn::seq(...)
4071  /// % fn::group_adjacent_by(key_fn, fn::to_seq())
4072  /// % fn::for_each([&](auto group_seq) // type of group_seq is a seq<...> instead of vector<...>
4073  /// {
4074  /// for(auto elem : group_seq) {
4075  /// // ...
4076  /// }
4077  /// });
4078  /// @endcode
4079  ///
4080  /// This is useful for cases where a subseq can be arbitrarily large, and you want
4081  /// to process grouped elements on-the-fly without accumulating them in a vector.
4082  ///
4083  /// This comes at the cost of more constrained functionality, since all groups and
4084  /// all elements in each group can only be accessed once and in order.
4085  template<typename F>
4087  {
4088  return { std::move(key_fn), {} };
4089  }
4090 
4091  /////////////////////////////////////////////////////////////////////////
4092 
4094  {
4095  return { by::identity{}, {} };
4096  }
4097 
4099  {
4100  return { by::identity{}, {} };
4101  }
4102 
4103  /////////////////////////////////////////////////////////////////////////
4104 
4105  /// @brief Group adjacent elements if binary predicate holds.
4106  template<typename BinaryPred>
4108  {
4109  return { {}, std::move(pred2) };
4110  }
4111 
4112  /// @brief Group adjacent elements if binary predicate holds.
4113  template<typename BinaryPred>
4115  {
4116  return { {}, std::move(pred2) };
4117  }
4118 
4119  /////////////////////////////////////////////////////////////////////////
4120 
4121 
4122  /// @brief Group adjacent elements into chunks of specified size.
4123  /*!
4124  @code
4125  std::move(elems)
4126  % fn::in_groups_of(5)
4127  % fn::for_each(auto&& group)
4128  {
4129  ASSERT(group.size() <= 5);
4130  });
4131  @endcode
4132 
4133  Buffering space requirements for `seq`: `O(n)`.
4134  */
4136  {
4137  if(n < 1) {
4138  RANGELESS_FN_THROW("Batch size must be at least 1.");
4139  }
4140  return { impl::chunker{ n, 0 }, {} };
4141  }
4142 
4143 
4144  /// @}
4145  /// @defgroup ordering Ordering
4146  /// @{
4147 
4148  /// @brief Reverse the elements in the input container.
4149  ///
4150  /// Buffering space requirements for `seq`: `O(N)`.
4152  {
4153  return {};
4154  }
4155 
4156  /// @brief stable-sort and return the input.
4157  /*!
4158  @code
4159  auto res =
4160  std::list<std::string>{{ "333", "1", "22", "333", "22" }}
4161  % fn::to_vector()
4162  % fn::sort_by([](const std::string& s)
4163  {
4164  return fn::by::decreasing(s.size());
4165  })
4166  % fn::unique_adjacent();
4167 
4168  VERIFY(( res == std::vector<std::string>{{ "333", "22", "1" }} ));
4169  @endcode
4170 
4171  Buffering space requirements for `seq`: `O(N)`.
4172  */
4173  template<typename F>
4175  {
4176  return { std::move(key_fn) };
4177  }
4178 
4179  /// @brief `sort_by with key_fn = by::identity`
4181  {
4182  return { by::identity{} };
4183  }
4184 
4185 
4186  template<typename F>
4188  {
4189  return { std::move(key_fn) };
4190  }
4191 
4193  {
4194  return { by::identity{} };
4195  }
4196 
4197 
4198  /// @brief Unstable lazy sort.
4199  ///
4200  /// Initially move all inputs into a `std::vector` and heapify in `O(n)`,
4201  /// and then lazily yield elements with `pop_heap` in `O(log(n))`. This is more efficient
4202  /// if the downstream stage is expected to consume a small fraction of
4203  /// sorted inputs.
4204  ///
4205  /// Buffering space requirements for `seq`: `O(N)`.
4206  template<typename F>
4208  {
4209  return { std::move(key_fn) };
4210  }
4211 
4212  /// @brief `lazy_sort_by with key_fn = by::identity`
4214  {
4215  return { by::identity{} };
4216  }
4217 
4218  /// @brief Return top-n elements, sorted by key_fn.
4219  ///
4220  /// This is conceptually similar to `fn::sort_by(key_fn) % fn::take_last(n)`,
4221  /// but is more efficient: the implementation mantains a priority-queue of
4222  /// top-n max-elements encountered so-far.
4223  ///
4224  /// Buffering space requirements: `O(n)`; time complexity: `O(N*log(n))`
4225  template<typename F>
4227  {
4228  return { std::move(key_fn), n };
4229  }
4230 
4231  /// @brief Return top-n elements, sorted by identity.
4233  {
4234  return { by::identity{}, n };
4235  }
4236 
4237 
4238 
4239  /// @}
4240  /// @defgroup uniq Uniquefying
4241  /// @{
4242 
4243  /// @brief Keep first element from every adjacently-equal run of elements.
4244  ///
4245  /// If arg is a container, apply erase-unique idiom and return
4246  /// the container.
4247  ///
4248  /// If arg is a `seq<In>`, compose `seq<Out>` that
4249  /// will yield first element from every adjacently-equal run of elements.
4250  template<typename F>
4252  {
4253  return { std::move(key_fn) };
4254  }
4255 
4257  {
4258  return { by::identity{} };
4259  }
4260 
4261  /// @brief Uniquefy elements globally, as-if `unique_adjacent_by` pre-sorted by same key.
4262  ///
4263  /// If arg is a container, move contents to vector, and then sort-by and unique-adjacent-by.
4264  ///
4265  /// If arg is a `seq<In>`, compose `seq<Out>` that will
4266  /// keep values of key_fn in a set, and skip already-seen elements.
4267  ///
4268  /// NB: the lifetime of value returned by key_fn must be independent of arg.
4269  template<typename F>
4271  {
4272  return { std::move(key_fn) };
4273  }
4274 
4276  {
4277  return { by::identity{} };
4278  }
4279 
4280 
4281  /// @}
4282  /// @defgroup concat Combining
4283  /// @{
4284 
4285  /// @brief Flatten the result of `group_all_by` or `group_adjacent_by`.
4286  ///
4287  /// Given a `ContainerA<ContainerB<...>>`, move all elements and return `ContainerB<...>`.
4288  ///
4289  /// Given a seq-of-iterables `seq<In>`, compose `seq<Out>` that will lazily yield elements
4290  /// of each iterable in seq.
4292  {
4293  return {};
4294  }
4295 
4296  /// @brief Yield elements of next after elements of arg.
4297  /*!
4298  @code
4299  auto res = vec_t{{1,2}}
4300  % fn::append( vec_t{{3}} )
4301  % fn::to_vector();
4302 
4303  VERIFY((res == vec_t{{1,2,3}}));
4304  @endcode
4305  */
4306  template<typename Iterable>
4308  {
4309  return { std::move(next) };
4310  }
4311 
4312  /// @brief Yield pairs of elements, (up to end of the shorter range)
4313  /*!
4314  @code
4315  auto res = vec_t{{1,2}}
4316  % fn::zip_with( vec_t{{3,4,5}}, [](int x, int y)
4317  {
4318  return x*10 + y;
4319  })
4320  % fn::to_vector();
4321 
4322  VERIFY((res == vec_t{{13, 24}}));
4323  @endcode
4324  */
4325  template<typename Iterable, typename BinaryFn>
4327  {
4328  // We could have provided zip2 instead, returning a pair of elements,
4329  // but more often than not that pair will need to be transformed,
4330  // so instead we provide generalized zip_with that also takes the
4331  // binary transform-function, obviating the need in separate transform-stage.
4332  // If necessary, the transform-function can simply yield std::make_pair.
4333 
4334  return { std::move(second), std::move(fn) };
4335  }
4336 
4337  /// @brief Yield invocations of `fn` over pairs of adjacent inputs.
4338  template<typename BinaryFn>
4340  {
4341  return { std::move(fn) };
4342  }
4343 
4344  // @brief Outer zip_with.
4345  template<typename Iterable, typename BinaryFn>
4347  {
4348  return { std::move(second), std::move(fn) };
4349  }
4350 
4351  /// @}
4352  /// @defgroup el_access Element Access
4353  /// @{
4354 
4355  /////////////////////////////////////////////////////////////////////////////
4356  /*! @brief Access unique element matching the predicate.
4357  *
4358  * Throw unless found exactly one element matching the predicate.
4359  * Returns const or non-const reference depending on the constness of the container.
4360  * @see set_unique
4361  @code
4362  const CConstRef<CUser_object>& model_evidence_uo =
4363  fn::get_unique(seq_feat.GetExts(), [](CConstRef<CUser_object> uo)
4364  {
4365  return uo->GetType().GetStr() == "ModelEvidence";
4366  });
4367  @endcode
4368  */
4369  template<typename Container, typename P>
4370  auto get_unique(Container& container, P&& pred) -> decltype(*container.begin())
4371  {
4372  auto best_it = container.end();
4373  size_t n = 0;
4374 
4375  for(auto it = container.begin(),
4376  it_end = container.end();
4377 
4378  it != it_end; ++it)
4379  {
4380  if(pred(*it)) {
4381  best_it = it;
4382  ++n;
4383  }
4384  }
4385 
4386  if(n != 1) {
4387  RANGELESS_FN_THROW("Expected unique element satisfying search criteria, found "
4388  + std::to_string(n) + ".");
4389  }
4390 
4391  return *best_it;
4392  }
4393 
4394  /////////////////////////////////////////////////////////////////////////////
4395  /// @brief Similar to get_unique, but end-insert an element if missing.
4396  ///
4397  /*!
4398  @code
4399  CRef<CSeqdesc>& gb_desc =
4400  fn::set_unique(seq_entry.SetDescr().Set(), [](CConstRef<CSeqdesc> d)
4401  {
4402  return d->IsGenbank();
4403  },
4404  [] // add if missing (must satisfy pred)
4405  {
4406  auto g = Ref(new CSeqdesc);
4407  g->SetGenbank();
4408  return g;
4409  });
4410  @endcode
4411  */
4412  template<typename Container, typename P, typename Construct>
4413  auto set_unique(Container& container, P&& pred, Construct&& con) -> decltype(*container.begin())
4414  {
4415  auto best_it = container.end();
4416  size_t n = 0;
4417 
4418  for(auto it = container.begin(),
4419  it_end = container.end();
4420 
4421  it != it_end; ++it)
4422  {
4423  if(pred(*it)) {
4424  best_it = it;
4425  ++n;
4426  }
4427  }
4428 
4429  if(n == 0) {
4430  best_it = container.insert(container.end(), con());
4431  ++n;
4432  if(!pred(*best_it)) {
4433  RANGELESS_FN_THROW("New element does not satisfy predicate.");
4434  }
4435  }
4436 
4437  if(n != 1) {
4438  RANGELESS_FN_THROW("Expected unique element satisfying search criteria, found "
4439  + std::to_string(n) + ".");
4440  }
4441 
4442  return *best_it;
4443  }
4444 
4445 
4446  /////////////////////////////////////////////////////////////////////////////
4447 
4448  /// e.g. `const CConstRef<CSeq_align> aln = first_or_default( get_alns_annot(...)->Get() );`
4449  template<typename Container>
4450  auto first_or_default(const Container& c) -> typename Container::value_type
4451  {
4452  return c.begin() == c.end() ? typename Container::value_type{} : *c.begin();
4453  }
4454 
4455  template<typename Container, typename Pred>
4456  auto first_or_default(const Container& c, Pred&& pred) -> typename Container::value_type
4457  {
4458  auto it = std::find_if(c.begin(), c.end(), std::forward<Pred>(pred));
4459  return it == c.end() ? typename Container::value_type{} : *it;
4460  }
4461 
4462  template<typename Container>
4463  auto last_or_default(const Container& c) -> typename Container::value_type
4464  {
4465  return c.rbegin() == c.rend() ? typename Container::value_type{} : *c.rbegin();
4466  }
4467 
4468  template<typename Container, typename Pred>
4469  auto last_or_default(const Container& c, Pred&& pred) -> typename Container::value_type
4470  {
4471  auto it = std::find_if(c.rbegin(), c.rend(), std::forward<Pred>(pred));
4472  return it == c.rend() ? typename Container::value_type{} : *it;
4473  }
4474 
4475  /// @}
4476  /// @defgroup other Util
4477  /// @{
4478 
4479  /// @brief Memoizing wrapper for non-recursive non-mutable unary lambdas (not synchronized).
4480  /*!
4481  @code
4482  size_t exec_count = 0;
4483  auto fn = make_memoized([&](int x){ exec_count++; return x*2; });
4484 
4485  VERIFY(fn(1) == 2);
4486  VERIFY(fn(2) == 4);
4487  VERIFY(fn(1) == 2);
4488  VERIFY(exec_count == 2);
4489  @endcode
4490  */
4491  template<typename F>
4493  {
4494  return { std::move(fn), {} };
4495  }
4496 
4497  /////////////////////////////////////////////////////////////////////////
4498  /// @brief Basic scope guard - execute some code in guard`s destructor.
4499  /*!
4500  @code
4501  {{
4502  // ...
4503 
4504  auto on_exit = fn::make_scope_guard([&]
4505  {
4506  std::cerr << "Executing clean-up or roll-back...\n";
4507  });
4508 
4509  on_exit.dismiss(); // Cancel if no longer applicable.
4510  }}
4511  @endcode
4512  */
4513  template<typename F>
4515  {
4516  return { std::move(fn), false };
4517  }
4518 
4519  /// @}
4520 
4521 
4522 namespace operators
4523 {
4524  // Why operator % ?
4525  // Because many other libraries overload >> or | for various purposes,
4526  // so in case of compilation errors involving those
4527  // you get an honorable mention of every possible overload in TU.
4528  //
4529  // Also, in range-v3 it is used for composition of views
4530  // rather than a function application, so we want to avoid possible confusion.
4531 
4532  /// @brief `return std::forward<F>(fn)(std::forward<Arg>(arg))`
4533  ///
4534  /// This is similar to Haskell's operator `(&) :: a -> (a -> b) -> b |infix 1|` or F#'s operator `|>`
4535 
4536 #if 0 && (defined(__GNUC__) || defined(__clang__))
4537  __attribute__ ((warn_unused_result))
4538  // A user may forget to iterate over the sequence, e.g.
4539  // std::move(inputs) % fn::transform(...); // creates and immediately destroys a lazy-seq.
4540  // whereas the user code probably intended:
4541  // std::move(inputs) % fn::transform(...) % fn::for_each(...);
4542  //
4543  // To deal with this we could make operator% nodiscard / warn_unused_result,
4544  // but disabling for now because I can't figure out how to suppress the
4545  // warning from the final % for_each(...).
4546 #endif
4547  template<typename Arg, typename F>
4548  auto operator % (Arg&& arg, F&& fn) -> decltype( std::forward<F>(fn)(std::forward<Arg>(arg)) )
4549  {
4550  // NB: forwarding fn too because it may have rvalue-specific overloads
4551  return std::forward<F>(fn)(std::forward<Arg>(arg));
4552  }
4553 
4554  // Note: in operator %= and <<= below we're not returning the original reference
4555  // because the operators are right-to-left associative, so it makes no sense to do it.
4556 
4557  /// @brief `arg = fn::to(Arg{})(std::forward<F>(fn)(std::move(arg)));`
4558  ///
4559  /// `strs %= fn::where([](const std::string& s){ return !s.empty(); }); // drop empty strings`
4560  template<typename Arg, typename F>
4561  auto operator %= (Arg& arg, F&& fn) -> decltype(void(std::forward<F>(fn)(std::move(arg))))
4562  {
4563  // NB: forwarding fn too because it may have rvalue-specific overloads.
4564  // Note: result-type may be not the same as arg, so we
4565  // have to move the elements rather than simply assign.
4566  arg = fn::to(Arg{})(std::forward<F>(fn)(std::move(arg)));
4567  }
4568 
4569  /// @brief End-insert elements of cont2 into cont1 by-move.
4570  /*!
4571  @code
4572  out <<= GetItems();
4573 
4574  // equivalent of:
4575  {{
4576  auto items = GetItems();
4577  for(auto&& item : items) {
4578  out.insert(out.end(), std::move(item));
4579  }
4580  }}
4581  @endcode
4582  */
4583  template<class Container1, class Container2>
4584  auto operator<<=(Container1& cont1,
4585  Container2&& cont2) -> decltype(void(cont1.insert(cont1.end(), std::move(*cont2.begin()))))
4586  {
4587  static_assert(std::is_rvalue_reference<Container2&&>::value, "");
4588  cont1.insert(cont1.end(),
4589  std::make_move_iterator(cont2.begin()),
4590  std::make_move_iterator(cont2.end()));
4591  }
4592 
4593  // Could also take Container2 by value, but taking by rvalue-reference instead
4594  // will preserve the internal storage of the container (instead of it being
4595  // freed here when going out of scope if we took it by value). In some cases
4596  // this may be desirable. So instead having separate overloads for
4597  // Container2&& and const Container2& that will copy elements.
4598 
4599  template<class Container1, class Container2>
4600  auto operator<<=(Container1& cont1,
4601  const Container2& cont2) -> decltype(void(cont1.insert(cont1.end(), *cont2.begin())))
4602  {
4603  cont1.insert(cont1.end(),
4604  cont2.begin(),
4605  cont2.end());
4606  }
4607 
4608  // I would have expected that seq-based input would work with the above overload as well,
4609  // but that is not so - after wrapping into std::make_move_iterator we're getting
4610  // compilation errors about missing operators +,+=,-,-= for the iterator.
4611  // Hence the special overload for seq (it already yields rvalue-references)
4612  template<class Container1, class Gen>
4613  void operator<<=(Container1& cont1, impl::seq<Gen> seq)
4614  {
4615  cont1.insert(cont1.end(), seq.begin(), seq.end());
4616  }
4617 
4618  template<class Container>
4619  void operator<<=(Container& cont, typename Container::value_type el)
4620  {
4621  cont.insert(cont.end(), std::move(el));
4622  }
4623 
4624 } // namespace operators
4625 
4626 } // namespace fn
4627 
4628 } // namespace rangeless
4629 
4630 #if RANGELESS_ENABLE_TSV
4631 
4632 #include <string>
4633 #include <iostream>
4634 #include <cctype> // for MSVC v19.16
4635 #include <cstdlib>
4636 #include <cstring>
4637 
4638 namespace rangeless
4639 {
4640 namespace tsv
4641 {
4642  using row_t = std::vector<std::string>;
4643 
4644  struct params
4645  {
4646  std::string header = "";
4647  // If specified, throw unless it is encountered verbatim in data before first data-row.
4648  // Used for checking that the file content corresponds to the program's expectations.
4649  // Skipped, even if skip_comments = false.
4650  //
4651  // e.g. "#Col1 name\tCol2 name" - Column names are in a comment before the data rows.
4652  // or "Col1 name\tCol2 name" - Column names are in the first data-row.
4653  // or "# File descriptor 42" - some arbitrary comment.
4654 
4655  std::string filename = ""; // Report filename in exception messages.
4656 
4657  bool skip_comments = true; // Skip lines starting with '#'.
4658  bool truncate_blanks = true; // Truncate leading and trailing spaces.
4659  bool skip_empty = true; // Skip lines that are empty (checked after truncate_blanks is applied).
4660  };
4661 
4662  /////////////////////////////////////////////////////////////////////////
4663 
4665  {
4666  public:
4667  get_next_line(std::istream& istr, params p = params{})
4668  : m_istr{ istr }
4669  , m_params{ std::move(p) }
4670  {}
4671 
4672  auto operator()() -> std::reference_wrapper<const std::string>
4673  {
4674  if(!m_istr) {
4675  throw std::runtime_error("Stream " + m_params.filename + " is not in good state before reading.");
4676  }
4677 
4678  m_line.clear();
4679  while(std::getline(m_istr, m_line))
4680  if(x_prepare())
4681  {
4682  return { m_line };
4683  }
4684 
4685  if( m_istr.bad()
4686  || (m_istr.fail() && !m_istr.eof())
4687  || !m_line.empty())
4688  {
4689  throw std::runtime_error("Stream " + m_params.filename + " terminated abnormally.");
4690  } else {
4691  rangeless::fn::end_seq(); // finished normally.
4692  }
4693 
4694  return { m_line };
4695  }
4696 
4697  private:
4698  std::istream& m_istr;
4699  const params m_params;
4700  bool m_found_header = false;
4701  std::string m_line = "";
4702 
4703  // preprocess the line and return true iff returnable
4704  bool x_prepare()
4705  {
4706  if(!m_line.empty() && m_line.back() == '\r') {
4707  m_line.pop_back();
4708  }
4709 
4710  const bool is_comment = !m_line.empty() && m_line[0] == '#';
4711 
4712  if( !m_params.header.empty()
4713  && !m_found_header
4714  && m_line == m_params.header)
4715  {
4716  m_found_header = true;
4717  m_line.clear();
4718  return false;
4719  }
4720 
4721  if(m_params.truncate_blanks) {
4722  while(!m_line.empty() && m_line.back() == ' ') {
4723  m_line.pop_back();
4724  }
4725 
4726  size_t i = 0;
4727  while(i < m_line.size() && m_line[i] == ' ') {
4728  ++i;
4729  }
4730  m_line.erase(0, i);
4731  }
4732 
4733  if( (m_params.skip_empty && m_line.empty())
4734  || (m_params.skip_comments && !m_line.empty() && m_line[0] == '#'))
4735  {
4736  m_line.clear();
4737  return false;
4738  }
4739 
4740  if( !m_line.empty() && !is_comment // data-line
4741  && !m_params.header.empty() && !m_found_header) // did not find expected header-line
4742  {
4743  throw std::runtime_error(
4744  "Did not find expected header: '"
4745  + m_params.header + "'"
4746  + (m_params.filename.empty() ? "" : ( " in file: " + m_params.filename)));
4747  }
4748 
4749  return true;
4750  }
4751  };
4752 
4753  /////////////////////////////////////////////////////////////////////////
4754 
4756  {
4757  private:
4758  const char m_delim;
4759  const bool m_truncate_blanks;
4760  tsv::row_t m_row;
4761 
4762  public:
4763  split_on_delim(char delim = '\t', bool truncate_blanks = true)
4764  : m_delim{ delim }
4765  , m_truncate_blanks{ truncate_blanks }
4766  , m_row{}
4767  {}
4768 
4769  // If we're an rvalue, support usage like `const auto row = tsv::split_on_delim{ ',' }("a,bb,ccc");`
4770  // or, if we want to reuse existing row's storage: `row = tsv::spit_on_delim{ ',' }("a,bb,ccc", std::move(row));`
4771  auto operator()(const std::string& line, row_t ret = {}) const && -> tsv::row_t
4772  {
4773  ret.resize(size_t(1 + std::count(line.begin(), line.end(), m_delim)));
4774 
4775  size_t i = 0;
4776  auto capture_next = [&](size_t b, size_t e)
4777  {
4778  if(e == std::string::npos) {
4779  e = line.size();
4780  }
4781 
4782  while(m_truncate_blanks && b < e && line[b] == ' ') {
4783  ++b;
4784  }
4785  while(m_truncate_blanks && b < e && line[e-1] == ' ') {
4786  --e;
4787  }
4788 
4789  ret[i++].assign(line, b, e - b);
4790  };
4791 
4792  size_t start_pos = 0, end_pos = 0;
4793 
4794  do {
4795  end_pos = line.find(m_delim, start_pos);
4796  capture_next(start_pos, end_pos);
4797  start_pos = end_pos + 1;
4798  } while(end_pos != std::string::npos);
4799 
4800  return ret; // copy elision guaranteed here in c++11?
4801  }
4802 
4803  // The operator below is for repeated invocations when we're an lvalue.
4804  //
4805  // To prevent unnecesary heap allocatinos, instead of returning row_t,
4806  // we return a const reference-wrapper, and reuse the allocated storage
4807  // in m_row.
4808  auto operator()(const std::string& line) & -> std::reference_wrapper<const tsv::row_t>
4809  {
4810  m_row = std::move(*this)(line, std::move(m_row));
4811  return { m_row };
4812  }
4813  };
4814 
4815  /// @brief Read tab-separated-values from stream.
4816  /*!
4817  @code
4818  std::string result = "";
4819  std::istringstream istr{"foo\n#comment\n\n\n bar \tbaz\n"};
4820 
4821  for(const std::vector<std::string>& row : tsv::from(istr)) {
4822  for(const auto& f : row) {
4823  result += f;
4824  result += "|";
4825  }
4826  result += ";";
4827  });
4828 
4829  VERIFY(result == "foo|;bar|baz|;");
4830  @endcode
4831  */
4833  {
4834  return fn::transform( split_on_delim{ delim, params.truncate_blanks } )(
4835  fn::seq( get_next_line{ istr, std::move(params) }) );
4836  }
4837 
4838  /// @brief Utility to parse numbers.
4839  ///
4840  /// This is a dispatcher for `std::strto*` functions with additional functionality:
4841  /// throws `std::domain_error` if can't parse, or out of bounds, or input has trailing non-whitespaces, or the destination type is unsigned and the input is a negative number.
4842  /*!
4843  * @code
4844  * bouble a = tsv::to_num(""); // throws - expected a number
4845  * double b = tsv::to_num(" 123xyz"); // throws - trailing garbage not allowed
4846  * int8_t c = tsv::to_num(" 12345 "); // throws - out of range
4847  * float d = tsv::to_num("12e-456"); // throws - underflow
4848  * uint16_t e = tsv::to_num("-1"); // throws - negative number while destination is unsigned
4849  * @endcode
4850  */
4851  class to_num
4852  {
4853  public:
4854  to_num(const to_num&) = delete; // prevent nonsense like auto x = tsv::num("123") from compiling
4855  to_num& operator=(const to_num&) = delete;
4856 
4857  explicit to_num(const char* str)
4858  : m_beg{ str }
4859  , m_end{ m_beg + std::strlen(str) }
4860  {}
4861 
4862  template<typename Str> // string, string_view, CTempString etc.
4863  explicit to_num(const Str& str)
4864  : m_beg{ str.begin() == str.end() ? nullptr : &*str.begin() }
4865  , m_end{ str.begin() == str.end() ? nullptr : &*str.begin() + str.size() }
4866  {}
4867 
4868  /// Conversion to an enum or enum-class
4869  template<typename Enum, typename std::enable_if<std::is_enum<Enum>::value>::type* = nullptr>
4870  operator Enum() const && // rvalue-specific such that no possibility of m_beg/m_end becoming dangling
4871  {
4872  auto value = typename std::underlying_type<Enum>::type{};
4873  value = std::move(*this);
4874  return Enum(value);
4875  }
4876 
4877  /// Conversion to an arithmetic type
4878  template<typename Number, typename std::enable_if<std::is_arithmetic<Number>::value>::type* = nullptr>
4879  operator Number() const &&
4880  {
4881  auto ret = Number{};
4882  char* endptr = nullptr;
4883 
4884  errno = 0;
4885  x_parse(ret, &endptr);
4886 
4887  throw_if(errno, ret, "under-or-overflow");
4888  throw_if(!endptr || endptr == m_beg, ret, "could not interpret");
4889  throw_if(endptr > m_end, ret, "parsed past the end");
4890 
4891  for(; endptr < m_end; ++endptr) { // verify that there's no garbage past the end
4892  throw_if(!std::isspace(*endptr), ret, "trailing non-whitespace characters");
4893  }
4894  return ret;
4895  }
4896 
4897  /// Convert to `uint8_t` first; throw unless 0 or 1; return as bool.
4898  operator bool() const &&
4899  {
4900  uint8_t ret = std::move(*this);
4901  throw_if(ret != 0 && ret != 1, ret, "out of bounds");
4902  return ret;
4903  }
4904 
4905  private:
4906  const char* m_beg;
4907  const char* m_end;
4908 
4909  template<typename T>
4910  void throw_if(bool cond, const T&, const char* message) const
4911  {
4912  if(cond) {
4913  throw std::domain_error(
4914  "Can't parse '"
4915  + std::string(m_beg, size_t(m_end-m_beg))
4916  + "' as numeric type '" + typeid(T).name()
4917  + "' - " + message + ".");
4918  }
4919  }
4920 
4921  void x_parse(long double& d, char** endptr) const
4922  {
4923  d = std::strtold(m_beg, endptr);
4924  }
4925 
4926  void x_parse(double & d, char** endptr) const
4927  {
4928  d = std::strtod(m_beg, endptr);
4929  }
4930 
4931  void x_parse(float& d, char** endptr) const
4932  {
4933  d = std::strtof(m_beg, endptr);
4934  }
4935 
4936  template<typename Integral>
4937  void x_parse(Integral& x, char** endptr) const
4938  {
4939  static_assert(std::is_integral<Integral>::value, "");
4940 
4941  // NB: can do another round of static dispatching here,
4942  // but chose pragmatic approach instead.
4943 
4944  if(std::is_signed<Integral>::value) {
4945 
4946  auto num = std::strtoll(m_beg, endptr, 10);
4947  x = static_cast<Integral>(num);
4948  throw_if(x != num, x, "overflow");
4949 
4950  } else {
4951 
4952  auto ptr = m_beg;
4953  while(ptr < m_end && std::isspace(*ptr)) {
4954  ++ptr;
4955  }
4956  throw_if(ptr < m_end && *ptr == '-', x, "negative number in unsigned conversion");
4957 
4958  auto num = std::strtoull(ptr, endptr, 10);
4959  x = static_cast<Integral>(num);
4960  throw_if(x != num, x, "overflow");
4961  }
4962  }
4963  }; // to_num
4964 
4965 
4966 } // namespace tsv
4967 
4968 } // namespace rangeless
4969 
4970 #endif // ENABLE_TSV
4971 
4972 
4973 
4974 #if RANGELESS_FN_ENABLE_RUN_TESTS
4975 #include <list>
4976 #include <string>
4977 #include <tuple>
4978 #include <set>
4979 #include <array>
4980 #include <iostream>
4981 #include <sstream>
4982 #include <cctype>
4983 #include <memory>
4984 
4985 #ifndef VERIFY
4986 #define VERIFY(expr) if(!(expr)) RANGELESS_FN_THROW("Assertion failed: ( "#expr" ).");
4987 #endif
4988 
4989 namespace rangeless
4990 {
4991 namespace fn
4992 {
4993 namespace impl
4994 {
4995 
4996 // move-only non-default-constructible type wrapping an int.
4997 // Will use it as our value_type in tests to verify that
4998 // we're supporting this.
4999 struct X
5000 {
5001  int value;
5002 
5003  X(int i) : value{ i }
5004  {}
5005 
5006 #if defined(__GNUC__) && (__GNUC___ >= 5)
5007  X() = delete;
5008 
5009  // We want to test that everything compiles even if the
5010  // type is not default-constructibse, however, with GCC 4.9.3
5011  // that results in
5012  // /opt/ncbi/gcc/4.9.3/include/c++/4.9.3/bits/stl_algobase.h:573:4: error: static assertion failed: type is not assignable
5013  // when calling std::erase or std::rotate on a vector<X>.
5014  //
5015  // So making leaving X default-constructible.
5016 #endif
5017  X(X&&) = default;
5018  X& operator=(X&&) = default;
5019 
5020  X(const X&) = delete;
5021  X& operator=(const X&) = delete;
5022 
5023  operator int&()
5024  {
5025  return value;
5026  }
5027 
5028  operator const int& () const
5029  {
5030  return value;
5031  }
5032 };
5033 using Xs = std::vector<X>;
5034 
5035 // This is templated to unary-callable, because
5036 // we want to reuse the same battery of tests when
5037 // the input is a container and when the input-type
5038 // is a lazy seq.
5039 template<typename UnaryCallable>
5040 auto make_tests(UnaryCallable make_inputs) -> std::map<std::string, std::function<void()>>
5041 {
5042  std::map<std::string, std::function<void()>> tests{};
5043  using fn::operators::operator%;
5044 
5045  //make_inputs({1, 2, 3}); // returns Xs or seq yielding X's
5046 
5047  auto fold = fn::foldl_d([](int64_t out, int64_t in)
5048  {
5049  return out*10 + in;
5050  });
5051 
5052 
5053 #if 0
5054  tests["single test of interest"] = [&]
5055  {
5056 
5057  };
5058 #else
5059 
5060 
5061  /////////////////////////////////////////////////////////////////////////
5062 
5063  tests["Test for NB[3]"] = [&]
5064  {
5065  auto res = make_inputs({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20})
5066  % fn::transform([](X x) { return std::to_string(x); })
5067  % fn::foldl_d([](std::string out, std::string in)
5068  {
5069  return std::move(out) + "," + in;
5070  });
5071  VERIFY(res == ",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20");
5072  };
5073 
5074  tests["foldl"] = [&]
5075  {
5076  // ensure compilation with move-only inputs
5077  auto res = make_inputs({1,2,3})
5078  % fn::foldl(X{42}, [](X out, int in)
5079  {
5080  return X(out*10+in);
5081  });
5082  VERIFY(res == 42123);
5083  };
5084 
5085 
5086 
5087 
5088  /////////////////////////////////////////////////////////////////////////
5089 
5090  tests["sliding_window"] = [&]
5091  {
5092  //using view_t = fn::view<typename vec_t::iterator>;
5093  // TODO: does not compile if using auto instead of view_t
5094 
5095 #if __cplusplus >= 201402L
5096  // using auto-parameter for `v` in lambda, can be
5097  // either container's iterator, or deque<...>::iterator
5098  // depending on inputs type
5099 
5100  const auto result =
5101  make_inputs({ 1,2,3,4 })
5102  % fn::sliding_window(2)
5103  % fn::foldl(0L, [](long out, auto v)
5104  {
5105  VERIFY(std::distance(v.begin(), v.end()) == 2);
5106  auto it = v.begin();
5107  return (out * 1000) + (*it * 10) + *std::next(it);
5108  });
5109  VERIFY(result == 12023034);
5110 #endif
5111  };
5112 
5113  /////////////////////////////////////////////////////////////////////////
5114 
5115  tests["where"] = [&]
5116  {
5117  auto ret = make_inputs({1,2,3})
5118  % fn::where([](int x) { return x != 2; })
5119  % fold;
5120  VERIFY(ret == 13);
5121 
5122  //123 % fn::where([](int x) { return x == 2; });
5123  };
5124 
5125 
5126  tests["where_in_sorted"] = [&]
5127  {
5128  auto ret = make_inputs({1,2,3,4})
5129  % fn::where_in_sorted(std::vector<int>{{ 1, 3}})
5130  % fold;
5131  VERIFY(ret == 13);
5132  };
5133 
5134  tests["where_not_in_sorted"] = [&]
5135  {
5136  auto ret = make_inputs({1,2,3,4})
5137  % fn::where_not_in_sorted(std::vector<int>{{1, 3}})
5138  % fold;
5139  VERIFY(ret == 24);
5140  };
5141 
5142  tests["where_max_by"] = [&]
5143  {
5144  auto ret = make_inputs({1,3,1,3})
5145  % fn::where_max_by(fn::by::identity{})
5146  % fold;
5147  VERIFY(ret == 33);
5148  };
5149 
5150  tests["where_min_by"] = [&]
5151  {
5152  // NB: also testing compilation where key_fn returns a tuple
5153  // containing references (see NB[2])
5154  auto ret = make_inputs({5,3,5,3})
5155  % fn::where_min_by([](const int& x) { return std::tie(x); })
5156  % fold;
5157  VERIFY(ret == 33);
5158  };
5159 
5160  tests["take_while"] = [&]
5161  {
5162  auto ret = make_inputs({3,4,1,2})
5163  % fn::take_while([](int x) { return x > 1; })
5164  % fold;
5165  VERIFY(ret == 34);
5166  };
5167 
5168  tests["drop_while"] = [&]
5169  {
5170  auto ret = make_inputs({3,4,1,2})
5171  % fn::drop_while([](int x) { return x > 1; })
5172  % fold;
5173  VERIFY(ret == 12);
5174  };
5175 
5176 
5177  tests["take_last"] = [&]
5178  {
5179  auto ret =
5180  make_inputs({1,2,3})
5181  % fn::take_last(2)
5182  % fold;
5183  VERIFY(ret == 23);
5184 
5185  ret = make_inputs({1,2,3})
5186  % fn::take_last(3)
5187  % fold;
5188  VERIFY(ret == 123);
5189 
5190  ret = make_inputs({1,2,3})
5191  % fn::take_last(4)
5192  % fold;
5193  VERIFY(ret == 123);
5194 
5195  const auto inputs = std::vector<int>{{1,2,3}};
5196  ret = inputs % fn::take_last(2) % fold;
5197  VERIFY(ret == 23);
5198  };
5199 
5200  tests["drop_last"] = [&]
5201  {
5202  auto ret =
5203  make_inputs({1,2,3})
5204  % fn::drop_last(2)
5205  % fold;
5206 
5207  VERIFY(ret == 1);
5208 
5209  ret = make_inputs({1,2,3})
5210  % fn::drop_last(3)
5211  % fold;
5212 
5213  VERIFY(ret == 0);
5214 
5215  ret = make_inputs({1,2,3})
5216  % fn::drop_last(4)
5217  % fold;
5218 
5219  VERIFY(ret == 0);
5220 
5221  const auto inputs = std::vector<int>{{1,2,3}};
5222  ret = inputs % fn::drop_last(2) % fold;
5223  VERIFY(ret == 1);
5224  };
5225 
5226  tests["take_first"] = [&]
5227  {
5228  auto ret =
5229  make_inputs({1,2,3})
5230  % fn::take_first(2)
5231  % fold;
5232  VERIFY(ret == 12);
5233  };
5234 
5235  tests["drop_first"] = [&]
5236  {
5237  auto ret =
5238  make_inputs({1,2,3})
5239  % fn::drop_first(2)
5240  % fold;
5241  VERIFY(ret == 3);
5242  };
5243 
5244 
5245  /////////////////////////////////////////////////////////////////////////
5246 
5247  tests["append"] = [&]
5248  {
5249  auto res = make_inputs({1,2,3})
5250  % fn::append( make_inputs({4,5}) )
5251  % fold;
5252 
5253  VERIFY(res == 12345);
5254  };
5255 
5256  tests["zip_with"] = [&]
5257  {
5258  auto res = make_inputs({1,2})
5259  % fn::zip_with( make_inputs({3,4,5}), [](int x, int y)
5260  {
5261  return std::array<int, 2>{{x, y}};
5262  })
5263  % fn::concat()
5264  % fold;
5265 
5266  VERIFY(res == 1324);
5267  };
5268 
5269 
5270  /////////////////////////////////////////////////////////////////////////
5271 
5272  tests["enumerate"] = [&]
5273  {
5274  auto res = make_inputs({4,5,6})
5275  % fn::transform(fn::get::enumerated{})
5276  % fn::transform([](std::pair<size_t, int> p)
5277  {
5278  return std::array<int, 2>{{p.second, int(p.first)}};
5279  })
5280  % fn::concat()
5281  % fold;
5282 
5283  VERIFY(res == 405162);
5284  };
5285 
5286  /////////////////////////////////////////////////////////////////////////
5287 
5288  tests["values"] = [&]
5289  {
5290  auto inps = make_inputs({1,2,3});
5291 
5292  auto m = std::map<int, decltype(inps) >{};
5293  m.emplace(1, std::move(inps));
5294  m.emplace(2, make_inputs({4,5,6}));
5295 
5296  auto res = std::move(m)
5297  % fn::transform(fn::get::second{})
5298  % fn::concat()
5299  % fold;
5300 
5301  VERIFY(res == 123456);
5302  };
5303 
5304  /////////////////////////////////////////////////////////////////////////
5305 
5306  tests["group_adjacent"] = [&]
5307  {
5308  auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5309  % fn::group_adjacent()
5310  % fn::transform([](Xs v)
5311  {
5312  return int(v.size());
5313  })
5314  % fold;
5315  VERIFY(res == 12321);
5316  };
5317 
5318  tests["group_adjacent_if"] = [&]
5319  {
5320  auto res = make_inputs({1,2,2,4,4,4,2,2,1})
5321  % fn::group_adjacent_if([](const int& a, const int& b)
5322  {
5323  return abs(a - b) < 2;
5324  })
5325  % fn::transform([](Xs v)
5326  {
5327  return int(v.size());
5328  })
5329  % fold;
5330  VERIFY(res == 333);
5331  };
5332 
5333  tests["group_all"] = [&]
5334  {
5335  auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5336  % fn::group_all()
5337  % fn::transform([](Xs v)
5338  {
5339  return int(v.size());
5340  })
5341  % fold;
5342  VERIFY(res == 243);
5343  };
5344 
5345  tests["in_groups_of"] = [&]
5346  {
5347  auto res = make_inputs({1,2,3,4,5})
5348  % fn::in_groups_of(2)
5349  % fn::transform([](Xs v)
5350  {
5351  return int64_t(v.size());
5352  })
5353  % fold;
5354  VERIFY(res == 221);
5355  };
5356 
5357  tests["concat"] = [&]
5358  {
5359  auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5360  % fn::group_all()
5361  % fn::concat()
5362  % fold;
5363  VERIFY(res == 112222333);
5364  };
5365 
5366  tests["unique_adjacent"] = [&]
5367  {
5368  auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5370  % fold;
5371  VERIFY(res == 12321);
5372  };
5373 
5374  tests["unique_all"] = [&]
5375  {
5376  // NB: key-function requires copy-constructible in this use-case.
5377  // see unique_all_by::gen::operator()()
5378  auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5379 #if 0
5380  % fn::unique_all()
5381  // Normally this would work, but we've made our type X not default-constructible,
5382  // so when using identity key-fn, the type X returned by it cannot be
5383  // used as key-type to store seen elements. Instead, will use modified key-fn below.
5384 #elif 1
5385  % fn::unique_all_by([](const X& x) -> const int& { return x; })
5386 #elif 0
5387  % fn::unique_all_by([](const X& x) { const int& r = x; return std::tie(r); })
5388  // This is not expected to work because returned reference-wrapper is
5389  // not default-constructible.
5390 #endif
5391  % fold;
5392  VERIFY(res == 123);
5393  };
5394 
5395  tests["sort"] = [&]
5396  {
5397  auto res = make_inputs({3,2,4,1,5})
5398  % sort()
5399  % reverse()
5400  % fold;
5401  VERIFY(res == 54321);
5402 
5403  res = make_inputs({3,2,4,1,5})
5404  % unstable_sort()
5405  % fold;
5406  VERIFY(res == 12345);
5407  };
5408 
5409  tests["lazy_sort"] = [&]
5410  {
5411  auto res = make_inputs({3,2,4,1,5})
5412  % lazy_sort()
5413  % reverse()
5414  % fold;
5415  VERIFY(res == 54321);
5416  };
5417 
5418  tests["top_n"] = [&]
5419  {
5420  auto res = make_inputs({3,2,4,1,5,0})
5421  % take_top_n(3)
5422  % fold;
5423  VERIFY(res == 345);
5424  };
5425 
5426 
5427 #if __cplusplus >= 201402L
5428  tests["group_adjacent_as_subseqs"] = [&]
5429  {
5430  int res = 0;
5431  int group_num = 0;
5432 
5433  make_inputs({1,2,2,3,3,3,4,5})
5435  % fn::for_each([&](auto subseq)
5436  {
5437  //subseq.size(); // sanity-check: this should not compile, because type is seq<...>
5438 
5439  group_num++;
5440  if(group_num == 4) {
5441  return; // testing skipping a group without accessing it
5442  }
5443 
5444  size_t i = 0;
5445  for(const auto x : subseq) {
5446 
5447  // testing that things work as expected
5448  // for partially-accessed groups leaving
5449  // some elements unaccessed. Here we'll skip
5450  // the last 3 in 333 subgroup.
5451  if(i++ >= 2) {
5452  break;
5453  }
5454 
5455  res = res*10 + x;
5456  }
5457  res = res*10;
5458  });
5459 
5460  VERIFY(res == 1022033050);
5461  };
5462 #endif
5463 
5464 
5465  tests["key_fn returning a reference_wrapper"] = [&]
5466  {
5467  // testing compilation. see lt
5468  auto get_ref = [](const X& x) { return std::cref(x); };
5469 
5470  make_inputs({1,2,3}) % fn::group_all_by(get_ref);
5471  make_inputs({1,2,3}) % fn::group_adjacent_by(get_ref);
5472  make_inputs({1,2,3}) % fn::sort_by(get_ref);
5473  make_inputs({1,2,3}) % fn::unique_adjacent_by(get_ref);
5474  // make_inputs({1,2,3}) % fn::unique_all_by(get_ref);
5475  // This is static-asserted against for seq because the implementation
5476  // requires default-constructible key-type (see discussion in unique_all_by::gen)
5477  };
5478 
5479  tests["to"] = [&]
5480  {
5481  auto res = make_inputs({2,3,1,2}) % fn::to(std::set<int>{}) % fold;
5482  VERIFY(res == 123);
5483  };
5484 
5485 
5486  /////////////////////////////////////////////////////////////////////////
5487 #endif
5488 
5489  return tests;
5490 }
5491 
5492 
5493 /////////////////////////////////////////////////////////////////////////////
5494 /////////////////////////////////////////////////////////////////////////////
5495 /////////////////////////////////////////////////////////////////////////////
5496 static void run_tests()
5497 {
5498  using fn::operators::operator%;
5499 
5500 #if 0 // single test
5501 
5502  std::map<std::string, std::function<void()>> tests1{}, tests2{}, test_other{};
5503  test_other["single"] = [&]
5504  {
5505  auto res = Xs{}
5506  % fn::to_seq()
5507  % fn::group_all()
5508  % fn::transform([](Xs v)
5509  {
5510  return (int)v.size();
5511  });
5512  };
5513 
5514 #else // all tests
5515 
5516  std::map<std::string, std::function<void()>>
5517  test_cont{}, test_seq{}, test_view{}, test_other{};
5518 
5519  // make battery of tests where input is a container (Xs)
5520  test_cont = make_tests([](std::initializer_list<int> xs)
5521  {
5522  Xs ret;
5523  for(auto x : xs) {
5524  ret.push_back(X(x));
5525  }
5526  return ret;
5527  });
5528 
5529  // make battery of tests where input is an input-range
5530  test_seq = make_tests([](std::initializer_list<int> xs)
5531  {
5532  Xs ret;
5533  for(auto x : xs) {
5534  ret.push_back(X(x));
5535  }
5536  return fn::to_seq()(std::move(ret));
5537  });
5538 
5539  // make battery of tests where input is a view
5540  test_view = make_tests([](std::initializer_list<int> xs)
5541  {
5542  // will be returning views; will keep the underlying data
5543  // in a static vector.
5544 
5545  static std::vector<Xs> vecs{};
5546  vecs.push_back(Xs{});
5547  auto& ret = vecs.back();
5548 
5549  for(auto x : xs) {
5550  ret.push_back(X(x));
5551  }
5552  return fn::from(ret);
5553  });
5554 
5555 
5556  using vec_t = std::vector<int>;
5557 
5558  /////////////////////////////////////////////////////////////////////////
5559 
5560 
5561  /////////////////////////////////////////////////////////////////////////
5562 
5563  test_other["typerased"] = [&]
5564  {
5565  int i = 0;
5566  fn::any_seq_t<int> myseq = //fn::make_typerased(
5567  fn::seq([i]() mutable
5568  {
5569  return i < 10 ? i++ : fn::end_seq();
5570  })
5571  % fn::where([](int x)
5572  {
5573  return x % 2 == 0;
5574  });
5575 
5576  int res = 0;
5577  for(const auto& x : myseq) {
5578  res = res*10 + x;
5579  }
5580 
5581  VERIFY(res == 2468);
5582  };
5583 
5584  test_other["for_each"] = [&]
5585  {
5586  // NB: making sure that for_each compiles with mutable lambdas
5587  auto vec = vec_t{{1,2,3}};
5588  vec % fn::for_each([](int& x) mutable
5589  {
5590  x *= 10;
5591  });
5592  VERIFY(( vec == vec_t{{10,20,30}} ));
5593  };
5594 
5595  test_other["for_each_adjacent"] = [&]
5596  {
5597  auto vec = vec_t{{1,2,3,4}};
5598  vec % fn::for_each_adjacent([](int& x1, int& x2) mutable // making sure non-const-reference binds
5599  {
5600  return x2 = x1*10 + x2;
5601  });
5602 
5603  VERIFY(( vec == vec_t{{1,12,123,1234}} ));
5604  };
5605 
5606 
5607  test_other["zip_adjacent"] = [&]
5608  {
5609  auto res =
5610  vec_t{{1,2,3,4}}
5611  % fn::zip_adjacent([](int& x1, int& x2) // making sure non-const-reference binds
5612  {
5613  return x1*10 + x2;
5614  })
5615  % fn::to_vector();
5616 
5617  VERIFY(( res == std::vector<int>{{12,23,34}} ));
5618  };
5619 
5620 
5621 
5622  test_other["fold"] = [&]
5623  {
5624  const std::string x =
5625  vec_t{{1,2,3}} % fn::foldl(std::string{"^"},
5626  [](std::string s, int x_)
5627  {
5628  return std::move(s) + "|" + std::to_string(x_);
5629  }) ;
5630  VERIFY(x == "^|1|2|3");
5631  };
5632 
5633  test_other["foldl_d"] = [&]
5634  {
5635  const std::string x =
5636  vec_t{{1,2,3}} % fn::foldl_d( [](std::string s, int x_)
5637  {
5638  return std::move(s) + "|" + std::to_string(x_);
5639  });
5640 
5641  VERIFY(x == "|1|2|3");
5642  };
5643 
5644  test_other["foldl_1"] = [&]
5645  {
5646  const auto min_int =
5647  std::vector<std::string>{{ "11", "-333", "22" }}
5648  % fn::transform([](const std::string& s) { return std::stoi(s); })
5649  % fn::foldl_1([](int out, int in) { return std::min(out, in); });
5650 
5651  VERIFY(min_int == -333);
5652  };
5653 
5654 
5655  /////////////////////////////////////////////////////////////////////////
5656 
5657  /////////////////////////////////////////////////////////////////////////
5658  test_other["fn::where with associative containers"] = [&]
5659  {
5660  // verify what filtering works for containers where
5661  // std::remove_if is not supported (e.g. assotiative)
5662 
5663  auto ints2 = std::set<int>{{111, 333}};
5664 
5665  using fn::operators::operator%=;
5666 
5667  ints2 %= fn::where([](int x) { return x > 222; });
5668  VERIFY(ints2.size() == 1 && *ints2.begin() == 333);
5669 
5670  using map_t = std::map<int, int>;
5671  auto m = map_t{{ {1,111}, {3,333} }};
5672 
5673  m %= fn::where([](const map_t::value_type& x) { return x.second > 222; });
5674  VERIFY(m.size() == 1 && m.at(3) == 333);
5675 
5676  //*m.begin() = *m.begin();
5677  };
5678 
5679  test_other["fn::where with mutable lambdas"] = [&]
5680  {
5681  // must work with mutable lambda
5682  int i = 0;
5683  auto ints2 = vec_t{{1,2,3}} % fn::where([i](int) mutable { return i++ >= 1; });
5684  VERIFY(( ints2 == vec_t{{2, 3}} ));
5685  };
5686 
5687  test_other["fn::where with const_reference inputs"] = [&]
5688  {
5689  // check const-reference overload with non-sequence containers
5690  const auto ints1 = std::set<int>{1,2,3};
5691  auto ints2 = ints1 % fn::where([](int x_) { return x_ > 1; });
5692  VERIFY(( ints2.size() == 2 ));
5693  };
5694 
5695  test_other["fn::where with non-const reference inputs"] = [&]
5696  {
5697  // check const-reference overload with non-sequence containers
5698  auto ints1 = std::set<int>{1,2,3};
5699  auto ints2 = ints1 % fn::where([](int x_) { return x_ > 1; });
5700 
5701  VERIFY(( ints1.size() == 3 ));
5702  VERIFY(( ints2.size() == 2 ));
5703  };
5704 
5705 
5706  test_other["refs"] = [&]
5707  {
5708  auto inps = vec_t({1,2,3});
5709 
5710  auto res = fn::refs(inps)
5711  % fn::foldl_d([](int64_t out, int& in)
5712  {
5713  ++in;
5714  // NB: taking in by non-const reference to verify
5715  // that it binds to non-const reference-wrapper
5716  return out*10 + in;
5717  });
5718  VERIFY(res == 234);
5719 
5720  // check with const inputs
5721  const auto& const_inps = inps;
5722  res = fn::refs(const_inps)
5723  % fn::foldl_d([](int64_t out, const int& in)
5724  {
5725  return out*10 + in;
5726  });
5727  VERIFY(res == 234);
5728 
5729  };
5730 
5731 
5732  /////////////////////////////////////////////////////////////////////////
5733 
5734 
5735  test_other["memoized"] = [&]
5736  {
5737  size_t exec_count = 0;
5738  auto strs = std::vector<std::string>{{ "333", "4444", "22", "1" }};
5739 
5740  using fn::operators::operator%=;
5741  strs %= fn::sort_by(fn::make_memoized([&](const std::string& s)
5742  {
5743  exec_count++;
5744  return s.size();
5745  }));
5746 
5747  VERIFY((strs == std::vector<std::string>{{ "1", "22", "333", "4444" }}));
5748  VERIFY(exec_count == 4);
5749  };
5750 
5751  test_other["scope_guard"] = [&]
5752  {
5753  int i = 0;
5754  {{
5755  auto on_exit_add1 = fn::make_scope_guard([&]
5756  {
5757  i += 1;
5758  });
5759 
5760  auto on_exit_add10 = fn::make_scope_guard([&]
5761  {
5762  i += 10;
5763  });
5764 
5765  on_exit_add1.dismiss();
5766  }}
5767  VERIFY(i == 10);
5768  };
5769 
5770  test_other["operator<<=, operator%="] = [&]
5771  {
5772  using fn::operators::operator<<=;
5773  using fn::operators::operator%=;
5774 
5775  auto cont = vec_t{{1,2}};
5776  cont <<= std::set<int>{{3,4}}; // excerising rvalue-based overload
5777 
5778  const auto const_set = std::set<int>{{5,6}};
5779  cont <<= const_set; // excercising conts-reference overload.
5780 
5781  int i = 0;
5782  cont <<= fn::seq([&i]{ return i++ < 1 ? 7 : fn::end_seq(); }); // should also work for seq rhs
5783 
5784  cont <<= 9;
5785 
5786  cont %= fn::where([](int x) { return x % 2 != 0; });
5787 
5788  VERIFY((cont == vec_t{{1,3,5,7,9}}));
5789  };
5790 
5791 #if 0
5792  test_other["generate and output_iterator"] = []
5793  {
5794  int i = 0;
5795  auto r = fn::seq([&i]
5796  {
5797  return i < 5 ? i++ : fn::end_seq();
5798  });
5799 
5800  int sum = 0;
5801  std::copy(r.begin(), r.end(), fn::make_output_iterator([&](int x)
5802  {
5803  sum = sum * 10 + x;
5804  }));
5805 
5806  VERIFY(sum == 1234);
5807  };
5808 #endif
5809 
5810  test_other["get_unique/set_unique"] = [&]
5811  {
5812  vec_t ints{{1,2,3}};
5813 
5814  auto& x1 = get_unique(ints, [](int x_){ return x_ == 2; });
5815  VERIFY(x1 == 2);
5816 
5817  // verify that works with const
5818  const auto& const_ints = ints;
5819  const auto& x2 = get_unique(const_ints, [](int x_){ return x_ == 2; });
5820  VERIFY(&x1 == &x2);
5821 
5822  auto ints2 = ints;
5823  auto& y = set_unique(ints2, [](int x_) { return x_ == 42; },
5824  []{ return 42; });
5825 
5826  VERIFY( ints2.size() == 4
5827  && ints2.back() == 42
5828  && &ints2.back() == &y);
5829  };
5830 
5831  test_other["group_adjacent_by vector-storage-recycling"] = []
5832  {
5833  // Check that vec_t& passed by reference
5834  // is reused on subsequent iterations instead
5835  // of reallocated de-novo.
5836  std::set<int*> ptrs;
5837 
5838  auto result =
5839  vec_t{2,4,1,3,5,6,7,9}
5840  % fn::to_seq()
5841  % fn::group_adjacent_by([](int x) { return x % 2; })
5842  % fn::foldl_d([&](int64_t out, vec_t&& in)
5843  {
5844  in.reserve(64);
5845  ptrs.insert(in.data());
5846  return out*10 + int64_t(in.size());
5847  });
5848 
5849  VERIFY((result == 2312));
5850  VERIFY((ptrs.size() <= 2));
5851  };
5852 
5853  test_other["decreasing"] = [&]
5854  {
5855  // sort by longest-first, then lexicographically
5856 
5857  const auto inp = std::vector<std::string>{ "2", "333", "1", "222", "3" };
5858  const auto expected = std::vector<std::string>{ "222", "333", "1", "2", "3" };
5859 
5860  auto ret1 = inp % fn::sort_by([](const std::string& s)
5861  {
5862  return std::make_tuple(fn::by::decreasing(s.size()), std::ref(s));
5863  });
5864  VERIFY(ret1 == expected);
5865 
5866  auto ret2 = inp % fn::sort_by([](const std::string& s)
5867  {
5868  return std::make_tuple(s.size(), fn::by::decreasing(std::ref(s)));
5869  }) % fn::reverse() % fn::to_vector();
5870 
5871  VERIFY(ret2 == expected);
5872 
5873  auto ret3 = inp % fn::sort_by(fn::by::decreasing([](const std::string& s)
5874  {
5875  return std::make_tuple(s.size(), fn::by::decreasing(std::ref(s)));
5876  }));
5877 
5878  VERIFY(ret3 == expected);
5879 
5880  auto ret4 = inp;
5881  std::sort(ret4.begin(), ret4.end(), fn::by::make_comp([](const std::string& s)
5882  {
5883  return std::make_tuple(fn::by::decreasing(s.size()), std::ref(s));
5884  }));
5885 
5886  VERIFY(ret4 == expected);
5887  };
5888 
5889  test_other["by"] = [&]
5890  {
5891  // make sure first{}, second{}, and dereferenced{} return arg as reference (or reference-wrapper)
5892  // rather than by value.
5893 
5894  std::vector<std::pair<std::unique_ptr<int>, int>> v{};
5895 
5896  fn::sort_by(fn::by::first{})(std::move(v));
5897  fn::sort_by(fn::by::second{})(std::move(v));
5898 
5899  const auto xy = std::make_pair(10, 20);
5900  const auto& x = fn::by::first{}(xy);
5901  VERIFY(&x == &xy.first);
5902 
5903  std::vector<std::unique_ptr<int> > v2{};
5904  fn::sort_by(fn::by::dereferenced{})(std::move(v2));
5905  };
5906 
5907  test_other["exists_where"] = [&]
5908  {
5909  VERIFY( ( vec_t{{ 1, 2, 3}} % fn::exists_where([](int x){ return x == 2; }) ));
5910  VERIFY( !( vec_t{{ 1, 2, 3}} % fn::exists_where([](int x){ return x == 5; }) ));
5911  VERIFY( ( vec_t{{ 1, 2, 3}} % !fn::exists_where([](int x){ return x == 5; }) ));
5912  };
5913 
5914 
5915 #if __cplusplus >= 201402L
5916  test_other["compose"] = []
5917  {
5918  auto my_transform = [](auto fn)
5919  {
5920  return fn::adapt([fn = std::move(fn)](auto gen)
5921  {
5922  return fn(gen());
5923  });
5924  };
5925 
5926  auto my_where = [](auto pred)
5927  {
5928  return fn::adapt([pred = std::move(pred)](auto gen)
5929  {
5930  auto x = gen();
5931  while(!pred(x)) {
5932  x = gen();
5933  }
5934  return x;
5935  });
5936  };
5937 
5938  auto my_take_while = [](auto pred)
5939  {
5940  return fn::adapt([pred = std::move(pred)](auto gen)
5941  {
5942  auto x = gen();
5943  return pred(x) ? std::move(x) : fn::end_seq();
5944  });
5945  };
5946 
5947  auto my_intersperse = [](auto delim)
5948  {
5949 #if 1
5950  return [delim = std::move(delim)](auto inputs)
5951  {
5952  return fn::seq([ delim,
5953  inputs = std::move(inputs),
5954  it = inputs.end(),
5955  started = false,
5956  flag = false]() mutable
5957  {
5958  if(!started) {
5959  started = true;
5960  it = inputs.begin();
5961  }
5962  return it == inputs.end() ? fn::end_seq()
5963  : (flag = !flag) ? std::move(*it++)
5964  : delim;
5965  });
5966  };
5967 
5968 #elif 0 // or
5969 
5970  return [delim = std::move(delim)](auto inputs)
5971  {
5972  return std::move(inputs)
5973  % fn::transform([delim](auto inp)
5974  {
5975  return std::array<decltype(inp), 2>{{ delim, std::move(inp) }};
5976  })
5977  % fn::concat()
5978  % fn::drop_first(); // drop leading delim
5979  };
5980 
5981 #else // or
5982 
5983  return fn::adapt([delim, flag = false](auto gen) mutable
5984  {
5985  return !gen ? fn::end_seq()
5986  : (flag = !flag) ? gen()
5987  : delim;
5988  });
5989 #endif
5990  };
5991 
5992  auto my_inclusive_scan = []
5993  {
5994  return fn::adapt([sum = 0](auto gen) mutable
5995  {
5996  return sum += gen();
5997  });
5998  };
5999 
6000  auto res =
6001  fn::seq([i = 0]() mutable
6002  {
6003  return i++;
6004  }) // 0,1,2,3,...
6005 
6006  % my_where([](int x)
6007  {
6008  return x >= 3;
6009  }) // 3,4,5,...
6010 
6011  % my_take_while([](int x)
6012  {
6013  return x <= 5;
6014  }) // 3,4,5
6015 
6016  % my_intersperse(-1) // 3,-1,4,-1,5
6017 
6018  % my_transform([](int x)
6019  {
6020  return x + 1;
6021  }) // 4,0,5,0,6
6022 
6023  % my_inclusive_scan() // 4,4,9,9,15
6024 
6025  % fn::to_vector();
6026 
6027  VERIFY((res == vec_t{{4, 4, 9, 9, 15}}));
6028  };
6029 #endif // tests for compose
6030 
6031 
6032  test_other["cartesian_product_with"] = [&]
6033  {
6034  auto res =
6035  vec_t{{1,2}}
6036  % fn::cartesian_product_with( vec_t{{3,4,5}}, [](int x, int y)
6037  {
6038  return x*10+y;
6039  })
6040  % fn::foldl_d([](int64_t out, int64_t in)
6041  {
6042  return out*1000+in;
6043  });
6044 
6045  VERIFY(res == 13014015023024025);
6046  };
6047 
6048  test_other["guard_against_multiple_iterations_of_input_range"] = [&]
6049  {
6050  auto gen_ints = [](int i, int j)
6051  {
6052  return fn::seq([i, j]() mutable
6053  {
6054  return i < j ? i++ : fn::end_seq();
6055  });
6056  };
6057 
6058  auto xs =
6059  gen_ints(0, 6)
6060  % fn::transform([&](int x) { return gen_ints(x, x+2); })
6061  % fn::concat()
6062  % fn::where([](int x) { return x % 2 == 0; });
6063 
6064  // 011223344556
6065  int64_t res = 0;
6066  bool threw = true;
6067  try {
6068  // xs is a seq, so trying to iterate it
6069  // a second time shall throw.
6070  for(size_t i = 0; i < 2; i++) {
6071  for(auto x : xs) {
6072  res = res*10 + x;
6073  }
6074  }
6075  threw = false;
6076  } catch(...) {
6077  threw = true;
6078  }
6079  VERIFY(threw);
6080  VERIFY(res == 22446);
6081  };
6082 
6083 
6084  test_other["most 5 top frequent words"] = [&]
6085  {
6086  // TODO : for now just testing compilation
6087 
6088  std::istringstream istr{};
6089 
6090  auto my_isalnum = [](const int ch)
6091  {
6092  return std::isalnum(ch) || ch == '_';
6093  };
6094 
6095  using counts_t = std::map<std::string, size_t>;
6096 
6097  fn::from(
6098  std::istreambuf_iterator<char>(istr.rdbuf()),
6099  std::istreambuf_iterator<char>{})
6100 
6101  % fn::transform([](const char c) // tolower
6102  {
6103  return ('A' <= c && c <= 'Z') ? char(c - ('Z' - 'z')) : c;
6104  })
6105 
6106  % fn::group_adjacent_by(my_isalnum)
6107 
6108 #if 0
6109  // build word->count map
6110  % fn::foldl_d([&](counts_t out, const std::string& in)
6111  {
6112  if(my_isalnum(in.front())) {
6113  ++out[ in ];
6114  }
6115  return std::move(out);
6116  })
6117 #else
6118  % fn::where([&](const std::string& s)
6119  {
6120  return my_isalnum(s.front());
6121  })
6122  % fn::counts() // map:word->count
6123 #endif
6124 
6125  % fn::group_all_by([](const counts_t::value_type kv)
6126  {
6127  return kv.first.size(); // by word-size
6128  })
6129 
6130  % fn::transform(
6131  fn::take_top_n_by(5UL, fn::by::second{}))
6132 
6133  % fn::concat()
6134 
6135  % fn::for_each([](const counts_t::value_type& kv)
6136  {
6137  std::cerr << kv.first << "\t" << kv.second << "\n";
6138  })
6139  ;
6140  };
6141 
6142  test_other["placement-new without std::launder"] = [&]
6143  {
6144  struct S
6145  {
6146  const int n;
6147  const int& r;
6148  };
6149  const int x1 = 1;
6150  const int x2 = 2;
6151 
6152  impl::maybe<S> m{};
6153 
6154  m.reset(S{42, x1});
6155  VERIFY((*m).n == 42);
6156  VERIFY((*m).r == 1);
6157 
6158  m.reset(S{420, x2});
6159  VERIFY((*m).n == 420);
6160  VERIFY((*m).r == 2);
6161  };
6162 
6163  test_other["counts"] = [&]
6164  {
6165  auto res =
6166  vec_t{{ 1, 1,2, 1,2,3 }}
6167  % fn::counts()
6168  % fn::transform([](const std::map<int, size_t>::value_type& kv)
6169  {
6170  return kv.first * 10 + int(kv.second);
6171  })
6172  % fn::to_vector();
6173 
6174  VERIFY((res == vec_t{{13, 22, 31}}));
6175  };
6176 
6177 
6178  test_other["tsv"] = [&]
6179  {
6180  std::string result = "";
6181  std::istringstream istr{"Expected Header\n \t r1f1 \t \n#Comment: next line is empty, and next one is blanks\n\n \n r2f1 \tr2f2\t r2f3 "};
6182 
6183  tsv::params params{};
6184  params.header = "Expected Header";
6185  params.filename = "filename";
6186 
6187  tsv::from(istr, '\t', params) // tsv::from(istr, '\t', { "Expected Header", "filename" }) // won't compile in c++11
6188  % fn::for_each([&](const tsv::row_t& row)
6189  {
6190  for(const auto& f : row) {
6191  result += f;
6192  result += "|";
6193  }
6194  result += ";";
6195  });
6196 
6197  VERIFY(result == "|r1f1||;r2f1|r2f2|r2f3|;");
6198 
6199  // test split_on_delim when it's an rvalue, returning row_t
6200  const auto row = tsv::split_on_delim{ ',' }("a,bb,ccc");
6201  VERIFY((row == tsv::row_t{{"a", "bb", "ccc"}}));
6202  };
6203 
6204  test_other["to_num"] = [&]
6205  {
6206  VERIFY(123 == int(tsv::to_num(" +123 ")));
6207 
6208  double delta = 123.0 - double(tsv::to_num(" 123.0 "));
6209  if(delta < 0) {
6210  delta *= -1;
6211  }
6212  VERIFY(delta < 1e-10);
6213 
6214  VERIFY(bool(tsv::to_num(" 1 ")));
6215 
6216  try{
6217  (void)int8_t(tsv::to_num("-129")); // overflow
6218  VERIFY(false);
6219  } catch(const std::domain_error&) {
6220  ;
6221  }
6222 
6223  try{
6224  (void)int(tsv::to_num("123 4")); // trailing garbage
6225  VERIFY(false);
6226  } catch(const std::domain_error&) {
6227  ;
6228  }
6229 
6230  try{
6231  (void)uint16_t(tsv::to_num("-123")); // negative number for unsigned
6232  VERIFY(false);
6233  } catch(const std::domain_error&) {
6234  ;
6235  }
6236 
6237  enum class my_int_t : int{};
6238  my_int_t my_int = tsv::to_num("42");
6239  VERIFY(my_int == my_int_t(42));
6240  };
6241 
6242 
6243 #endif // single-test vs all
6244 
6245  /////////////////////////////////////////////////////////////////////////
6246  size_t num_failed = 0;
6247  size_t num_ok = 0;
6248  for(auto&& tests : { test_cont, test_seq, test_view, test_other })
6249  for(const auto& kv : tests)
6250  {
6251  try{
6252  kv.second();
6253  num_ok++;
6254  } catch(const std::exception& e) {
6255  num_failed++;
6256  std::cerr << "Failed test '" << kv.first << "' :" << e.what() << "\n";
6257  }
6258  }
6259  if(num_failed == 0) {
6260  std::cerr << "Ran " << num_ok << " tests - OK\n";
6261  } else {
6262  throw std::runtime_error(std::to_string(num_failed) + " tests failed.");
6263  }
6264 }
6265 
6266 } // namespace impl
6267 } // namespace fn
6268 } // namespacce rangeless
6269 
6270 
6271 #endif //RANGELESS_FN_ENABLE_RUN_TESTS
6272 
6273 
6274 /////////////////////////////////////////////////////////////////////////////
6275 //
6276 //
6277 // synchronized_queue, to_async, transform_in_parallel below
6278 //
6279 //
6280 /////////////////////////////////////////////////////////////////////////////
6281 
6282 
6283 #if RANGELESS_FN_ENABLE_PARALLEL
6284 #include <queue>
6285 #include <thread>
6286 #include <mutex>
6287 #include <condition_variable>
6288 #include <atomic>
6289 #include <future>
6290 #include <chrono>
6291 #include <memory>
6292 
6293 /////////////////////////////////////////////////////////////////////////////
6294 
6295 namespace rangeless
6296 {
6297 
6298 namespace mt
6299 {
6300 
6301 /////////////////////////////////////////////////////////////////////////////
6302 /// \brief A simple timer.
6303 struct timer
6304 {
6305  /// returns the time elapsed since timer's instantiation, in seconds.
6306  /// To reset: `my_timer = mt::timer{}`.
6307  operator double() const
6308  {
6309  return double(std::chrono::duration_cast<std::chrono::nanoseconds>(
6310  clock_t::now() - start_timepoint).count()) * 1e-9;
6311  }
6312 private:
6313  using clock_t = std::chrono::steady_clock;
6314  clock_t::time_point start_timepoint = clock_t::now();
6315 };
6316 
6317 namespace lockables
6318 {
6319 
6320 class atomic_mutex // without alignas(cacheline_size) to avoid overaligned-new pre-c++17
6321 { // instead will add padding around the fields
6322 protected:
6323  std::atomic<bool> m_locked = { false };
6324 
6325 public:
6326  bool try_lock() noexcept
6327  {
6328  return !m_locked.load(std::memory_order_relaxed)
6329  && !m_locked.exchange(true, std::memory_order_acquire);
6330  }
6331 
6332  void lock() noexcept
6333  {
6334  for(size_t i = 0; !try_lock(); i++) {
6335  std::this_thread::sleep_for(
6336  std::chrono::microseconds(5)); // the actual time is greater, depends on scheduler
6337  }
6338  }
6339 
6340  void unlock() noexcept
6341  {
6342  m_locked.store(false, std::memory_order_release);
6343  }
6344 };
6345 
6346 }
6347 
6349 {
6350 public:
6351  enum class status { success, closed, timeout };
6352 
6353  // deriving from end_seq::exception to enable
6354  // adapting queue as input-seq: fn::seq(my_queue.pop) % fn::for_each(...)
6355  // (push will throw queue_closed, which will terminate the seq).
6356 
6358  {};
6359 
6360  // NB: Core guideline T.62: Place non-dependent class template members in a non-templated base class
6361 };
6362 
6363 
6364 /////////////////////////////////////////////////////////////////////////////
6365 /*! \brief Optionally-bounded blocking concurrent MPMC queue.
6366  *
6367  * - Supports not-copy-constructible/not-default-constructible value-types (just requires move-assigneable).
6368  * - Can be used with lockables other than `std::mutex`, e.g. `mt::atomic_lock`.
6369  * - Contention-resistant: when used with `mt::atomic_lock` the throughput is comparable to state-of-the-art lock-free implementations.
6370  * - Short and simple implementation using only c++11 standard library primitives.
6371  * - Provides RAII-based closing semantics to communicate end-of-inputs
6372  * from the pushing end or failure/going-out-of-scope from the popping end.
6373  *
6374  * Related:
6375  * <br> <a href="http://www.boost.org/doc/libs/1_66_0/libs/fiber/doc/html/fiber/synchronization/channels/buffered_channel.html">`boost::fibers::buffered_channel`</a>
6376  * <br> <a href="http://www.boost.org/doc/libs/1_66_0/doc/html/thread/sds.html">`boost::sync_bounded_queue`</a>
6377  * <br> <a href="http://www.boost.org/doc/libs/1_66_0/doc/html/boost/lockfree/queue.html">`boost::lockfree::queue`</a>
6378  * <br> <a href="https://software.intel.com/en-us/node/506200">`tbb::concurrent_queue`</a>
6379  * <br> <a href="https://github.com/cameron314/concurrentqueue">`moodycamel::BlockingConcurrentQueue`</a>
6380  *
6381 @code
6382  // A toy example to compute sum of lengths of strings in parallel.
6383  //
6384  // Spin-off a separate async-task that enqueues jobs
6385  // to process a single input, and enqueues the
6386  // futures into a synchronized queue, while accumulating
6387  // the ready results from the queue in this thread.
6388 
6389  using queue_t = mt::synchronized_queue<std::future<size_t> >;
6390  queue_t queue{ 10 };
6391 
6392  auto fut = std::async(std::launch::async,[ &queue ]
6393  {
6394  auto close_on_exit = queue.close();
6395 
6396  for(std::string line; std::getline(std::cin, line); ) {
6397  queue <<=
6398  std::async(
6399  std::launch::async,
6400  [](const std::string& s) {
6401  return s.size();
6402  },
6403  std::move(line));
6404  }
6405  });
6406 
6407  size_t total = 0;
6408  queue >>= [&](queue_t::value_type x) { total += x.get(); };
6409  fut.get(); // rethrow exception, if any.
6410 @endcode
6411 */
6412 template <typename T, class BasicLockable = std::mutex>
6414 {
6415 public:
6416  using value_type = T;
6417 
6418  ///@{
6419 
6420  synchronized_queue(size_t cap = 1024)
6421  : m_capacity{ cap }
6422  {}
6423 
6424  ~synchronized_queue() = default;
6425  // What if there are elements in the queue?
6426  // If there are active poppers, we ought to
6427  // let them finish, but if there aren't any,
6428  // this will block indefinitely, so we'll
6429  // leave it to the user code to manage the
6430  // lifetime across multiple threads.
6431  //
6432  // Should we call x_close() ?
6433  // No point - we're already destructing.
6434  // (it also grabs the m_queue_mutex, which
6435  // theoretically may throw).
6436 
6437 
6438  // After careful consideration, decided not to provide
6439  // move-semantics; copy and move constructors are implicitly
6440  // deleted.
6441  //
6442  // A synchronized_queue can be thought of buffered mutex
6443  // (i.e. a synchronization primitive rather than just a
6444  // data structure), and mutexes are not movable.
6445 
6446  ///@}
6447  ///@{
6448 
6449  // push and pop are implemented as callable function-objects fields
6450  // rather than plain methods to enable usage like:
6451  //
6452  // Adapt queue as input-range:
6453  // fn::seq(synchronized_queue.pop) % fn::for_each(...)
6454  //
6455  // Adapt queue as sink-function:
6456  // std::move(inputs) % fn::for_each(my_queue.push);
6457  //
6458  // Adapt queue as output-iterator:
6459  // std::copy(inputs.begin(), inputs.end(), my_queue.push);
6460 
6461  /////////////////////////////////////////////////////////////////////////
6462  /// Implements insert_iterator and unary-invokable.
6463  struct push_t
6464  {
6465  using iterator_category = std::output_iterator_tag;
6466  using difference_type = void;
6468  using pointer = void;
6469  using reference = void;
6470 
6472 
6474  {
6475  this->operator()(std::move(val));
6476  return *this;
6477  }
6478 
6479  push_t& operator*() { return *this; }
6480  push_t& operator++() { return *this; }
6481  push_t operator++(int) { return *this; }
6482 
6483  /// Blocking push. May throw `queue_closed`
6484  void operator()(value_type val) noexcept(false)
6485  {
6486  // NB: if this throws, val is gone. If the user needs
6487  // to preserve it in case of failure (strong exception
6488  // guarantee), it should be using try_push which takes
6489  // value by rvalue-reference and moves it only in case of success.
6490  //
6491  // We could do the same here, but that would mean
6492  // that the user must always pass as rvalue, and
6493  // to pass by copy it would have to do so explicitly, e.g.
6494  //
6495  // void operator()(value_type&& val);
6496  // queue.push(std::move(my_value));
6497  // queue.push(my_const_ref); // won't compile.
6498  // queue.push(queueue_t::value_type( my_const_ref )); // explicit copy
6499  //
6500  // I think this would actually be a good thing, as it
6501  // makes the copying visible, but all other synchronied-queue
6502  // APIs allow pushing by const-or-forwarding-references,
6503  // so we have allow the same for the sake of consistency.
6504 
6505  const status st =
6506  m_queue.try_push(std::move(val), no_timeout_sentinel_t{});
6507 
6508  assert(st != status::timeout);
6509 
6510  if(st == status::closed) {
6511  throw queue_closed{};
6512  }
6513 
6514  assert(st == status::success);
6515  }
6516  };
6517  friend struct push_t;
6518 
6519 
6520  /////////////////////////////////////////////////////////////////////////
6521  /// Blocking push. May throw `queue_closed`.
6522  push_t push = { *this };
6523 
6524 
6525  /////////////////////////////////////////////////////////////////////////
6526  struct pop_t
6527  {
6529 
6531  {
6532  return m_queue.x_blocking_pop();
6533  }
6534  };
6535 
6536  friend struct pop_t;
6537 
6538  /////////////////////////////////////////////////////////////////////////
6539  /// Blocking pop. May throw `queue_closed`.
6540  pop_t pop = { *this };
6541 
6542 
6543  /////////////////////////////////////////////////////////////////////////
6544 
6545  ///@}
6546  ///@{
6547 
6548  /// \brief pop() the values into the provided sink-function until closed and empty.
6549  ///
6550  /// e.g. `queue >>= [&out_it](T x){ *out_it++ = std::move(x); };`
6551  /// <br>Queue is automatically closed if exiting via exception, unblocking the pushers.
6552  template<typename F>
6553  auto operator>>=(F&& sink) -> decltype((void)sink(this->pop()))
6554  {
6555  auto guard = this->close();
6556 
6557  while(true) {
6558  bool threw_in_pop = true;
6559 
6560  try {
6561  value_type val = this->pop();
6562  threw_in_pop = false;
6563  sink(std::move(val));
6564 
6565  } catch(queue_closed&) {
6566 
6567  if(threw_in_pop) {
6568  break; // threw in pop()
6569  } else {
6570  throw; // threw in sink() - not our business - rethrow;
6571  //
6572  // This could be an unhandled exception from
6573  // sink that is from some different queue that we
6574  // shouldn't be intercepting.
6575  //
6576  // If sink intends to close the queue
6577  // (e.g. break-out), it can do it explicitly
6578  // via the close-guard;
6579  }
6580  }
6581  }
6582 
6583  assert(closed() && m_queue.empty());
6584  }
6585 
6586  ///@}
6587  ///@{
6588 
6589 
6590  /////////////////////////////////////////////////////////////////////////
6591  /// In case of success, the value will be moved-from.
6592  template <typename Duration = std::chrono::milliseconds>
6593  status try_push(value_type&& value, Duration timeout = {})
6594  {
6595  // NB: we could have taken value as value_type&, but
6596  // the user-code may forget or not expect that the value
6597  // will be moved-from and may try to use it.
6598  //
6599  // With rvalue-reference the caller-code has to, e.g.
6600  // auto state = queue.try_push(std::move(x));
6601  //
6602  // making the move explicitly visible.
6603 
6604  const guard_t contention_guard{ m_push_mutex };
6605 
6606  lock_t queue_lock{ m_queue_mutex };
6607 
6608  ++m_num_waiting_to_push;
6609  const bool ok = x_wait_until([this]
6610  {
6611  return m_queue.size() < m_capacity || !m_capacity;
6612  },
6613  m_can_push, queue_lock, timeout);
6614  --m_num_waiting_to_push;
6615 
6616  if(!ok) {
6617  return status::timeout;
6618  }
6619 
6620  if(!m_capacity) {
6621  return status::closed;
6622  }
6623 
6624  assert(m_queue.size() < m_capacity);
6625 
6626  // if push throws, is the value moved-from?
6627  // No. std::move is just an rvalue_cast - no-op
6628  // if the move-assignment never happens.
6629  m_queue.push(std::move(value));
6630 
6631  const bool do_notify = m_num_waiting_to_pop > 0;
6632  queue_lock.unlock();
6633 
6634  if(do_notify) {
6635  m_can_pop.notify_one();
6636  }
6637 
6638  return status::success;
6639  }
6640 
6641 
6642  /////////////////////////////////////////////////////////////////////////
6643  /// In case of success, the value will be move-assigned.
6644  template <typename Duration = std::chrono::milliseconds>
6645  status try_pop(value_type& value, Duration timeout = {})
6646  {
6647  const guard_t contention_guard{ m_pop_mutex };
6648 
6649  lock_t queue_lock{ m_queue_mutex };
6650 
6651  ++m_num_waiting_to_pop;
6652  bool ok = x_wait_until([this]
6653  {
6654  return !m_queue.empty() || !m_capacity;
6655  },
6656  m_can_pop, queue_lock, timeout);
6657  --m_num_waiting_to_pop;
6658 
6659  if(!ok) {
6660  return status::timeout;
6661  }
6662 
6663  if(!m_queue.empty()) {
6664  ;
6665  } else if(!m_capacity) {
6666  return status::closed;
6667  } else {
6668  assert(false);
6669  }
6670 
6671  value = std::move(m_queue.front());
6672  m_queue.pop();
6673 
6674  const bool do_notify = m_num_waiting_to_push > 0;
6675  queue_lock.unlock();
6676 
6677  if(do_notify) {
6678  m_can_push.notify_one();
6679  }
6680 
6681  return status::success;
6682  }
6683 
6684  ///@}
6685  ///@{
6686 
6687  /////////////////////////////////////////////////////////////////////////
6688  size_t approx_size() const noexcept
6689  {
6690  return m_queue.size();
6691  }
6692 
6693  size_t capacity() const noexcept
6694  {
6695  return m_capacity;
6696  }
6697 
6698  bool closed() const noexcept
6699  {
6700  return !m_capacity;
6701  }
6702 
6703  /////////////////////////////////////////////////////////////////////////
6705  {
6706  private:
6707  synchronized_queue* ptr;
6708 
6709  public:
6710  close_guard(synchronized_queue& queue) : ptr{ &queue }
6711  {}
6712 
6713  close_guard(const close_guard&) = default; // -Weffc++ warning
6714  close_guard& operator=(const close_guard&) = default;
6715 
6716  void reset()
6717  {
6718  ptr = nullptr;
6719  }
6720 
6722  {
6723  if(ptr) {
6724  ptr->x_close();
6725  }
6726  }
6727  };
6728 
6729  /// \brief Return an RAII object that will close the queue in its destructor.
6730  ///
6731  /// @code
6732  /// auto guard = queue.close(); // close the queue when leaving scope
6733  /// queue.close(); // close the queue now (guard's is destroyed immediately)
6734  /// @endcode
6735  ///
6736  /// <br> NB: closing is non-blocking.
6737  /// <br>Blocked calls to try_push()/try_pop() shall return with status::closed.
6738  /// <br>Blocked calls to push()/pop() shall throw `queue_closed`.
6739  /// <br>Subsequent calls to push()/try_push() shall do as above.
6740  /// <br>Subsequent calls to pop()/try_pop() will succeed
6741  /// until the queue becomes empty, and throw/return-closed thereafter.
6742  close_guard close() noexcept
6743  {
6744  return close_guard{ *this };
6745  }
6746 
6747  ///@}
6748 
6749 private:
6750  using guard_t = std::lock_guard<BasicLockable>;
6751  using lock_t = std::unique_lock<BasicLockable>;
6752  using queue_t = std::queue<value_type>;
6753 
6754  using condvar_t = typename std::conditional<
6755  std::is_same<BasicLockable, std::mutex>::value,
6756  std::condition_variable,
6757  std::condition_variable_any >::type;
6758 
6759  struct no_timeout_sentinel_t
6760  {};
6761 
6762  template<typename F>
6763  bool x_wait_until(F condition, condvar_t& cv, lock_t& lock, no_timeout_sentinel_t)
6764  {
6765  cv.wait(lock, std::move(condition));
6766  return true;
6767  }
6768 
6769  template<typename Duration, typename F>
6770  bool x_wait_until(F condition, condvar_t& cv, lock_t& lock, Duration duration)
6771  {
6772  return cv.wait_for(lock, duration, std::move(condition));
6773  }
6774 
6775  value_type x_blocking_pop()
6776  {
6777  const guard_t contention_guard{ m_pop_mutex };
6778 
6779  lock_t queue_lock{ m_queue_mutex };
6780 
6781  ++m_num_waiting_to_pop;
6782  m_can_pop.wait(
6783  queue_lock,
6784  [this]
6785  {
6786  return !m_queue.empty() || !m_capacity;
6787  });
6788  --m_num_waiting_to_pop;
6789 
6790  if(m_queue.empty()) {
6791  throw queue_closed{};
6792  }
6793 
6794  value_type ret = std::move(m_queue.front());
6795  m_queue.pop();
6796 
6797  const bool do_notify = m_num_waiting_to_push > 0;
6798  queue_lock.unlock();
6799 
6800  if(do_notify) {
6801  m_can_push.notify_one();
6802  }
6803 
6804  return ret;
6805  }
6806 
6807  /////////////////////////////////////////////////////////////////////////
6808  /// \brief Closes the queue for more pushing.
6809  ///
6810  void x_close()
6811  {
6812  {
6813  guard_t g{ m_queue_mutex };
6814  m_capacity = 0;
6815  }
6816  m_can_pop.notify_all();
6817  m_can_push.notify_all();
6818  }
6819 
6820  // NB: open() is not provided, such that if closed() returns true,
6821  // we know for sure that it's staying that way.
6822 
6823  /////////////////////////////////////////////////////////////////////////
6824 
6825  const char m_padding0[64] = {};
6826 
6827  uint32_t m_num_waiting_to_push = 0;
6828  uint32_t m_num_waiting_to_pop = 0;
6829  size_t m_capacity = size_t(-1); // 0 means closed
6830  queue_t m_queue = queue_t{};
6831  BasicLockable m_queue_mutex = {};
6832  BasicLockable m_push_mutex = {}; // for managing contention in SPMC/MPSC cases
6833  BasicLockable m_pop_mutex = {};
6834  condvar_t m_can_push = {};
6835  condvar_t m_can_pop = {};
6836 
6837  const char m_padding1[64] = {};
6838 }; // synchronized_queue
6839 
6840 } // namespace mt
6841 
6842 /////////////////////////////////////////////////////////////////////////////
6843 
6844 namespace fn
6845 {
6846 
6847 namespace impl
6848 {
6849  struct async_wr
6850  {
6851  size_t queue_size;
6852 
6853  template<typename InGen>
6854  struct gen
6855  {
6856  using value_type = typename InGen::value_type;
6857 
6859 
6860  InGen in_gen; // nullary generator yielding maybe<...>
6861  const size_t queue_size;
6862  std::unique_ptr<queue_t> queue; // as unique-ptr, because non-moveable
6863  std::future<void> fut;
6864 
6866  {
6867  if(!queue) {
6868  queue.reset(new queue_t{ queue_size });
6869  fut = std::async(std::launch::async, [this]
6870  {
6871  auto guard = queue->close(); // close on scope-exit
6872  for(auto x = in_gen(); x; x = in_gen()) {
6873  queue->push(std::move(x));
6874  }
6875  queue->push({}); // last empty-maybe element
6876  });
6877  }
6878 
6879  try {
6880  auto x = queue->pop();
6881  if(!x) {
6882  fut.get(); // last element - allow future to rethrow
6883  assert(queue->closed());
6884  }
6885  return x;
6887  // pop() threw queue_closed before we saw the last empty-maybe
6888  // - allow the future to rethrow.
6889  fut.get();
6890  throw;
6891  }
6892  }
6893  };
6894 
6895  RANGELESS_FN_OVERLOAD_FOR_SEQ(queue_size, {}, {})
6896  };
6897 
6898  /////////////////////////////////////////////////////////////////////////
6899 
6900 
6901  // Default implementation of Async for par_transform below.
6902  struct std_async
6903  {
6904  template<typename NullaryCallable>
6905  auto operator()(NullaryCallable gen) const -> std::future<decltype(gen())>
6906  {
6907  return std::async(std::launch::async, std::move(gen));
6908  }
6909  };
6910 
6911  /////////////////////////////////////////////////////////////////////
6912  template<typename F, typename Async>
6914  {
6915  Async async;
6917  size_t queue_cap; // 0 means in-this-thread.
6918 
6920  {
6921  queue_cap = cap;
6922  return std::move(*this);
6923  }
6924 
6925 #if __cplusplus >= 201402L
6926 
6927  /// If a job granularity is too small, combine work in batches per-async-task.
6928  auto in_batches_of(size_t batch_size) && // rvalue-specific because will move-from
6929  {
6930  assert(batch_size >= 2);
6931 
6932  return [ map_fn = std::move(this->map_fn),
6933  async = std::move(this->async),
6934  queue_cap = std::move(this->queue_cap),
6935  batch_size
6936  ] (auto inputs)
6937  {
6938  // TODO: can capture map_fn and async below by-move and make this lambda mutable?
6939 
6940  auto batch_transform = [ map_fn ](auto inputs_batch) // [ inputs ] -> [ outputs ]
6941  {
6942  // NB:: since fn::transform is lazy, we need to force eager-evaluation
6943  // within the batch-transform function by converting to vector.
6944  return fn::to_vector()(
6945  fn::transform(map_fn)(
6946  std::move(inputs_batch)));
6947  };
6948 
6949  // par_batch_transform = fn::transform_in_parallel(...), but it has not been declared yet.
6950  auto par_batch_transform =
6951  impl::par_transform<decltype(batch_transform), Async>{ async, // by-move here?
6952  std::move(batch_transform),
6953  queue_cap };
6954 
6955  return fn::concat()( // flatten batches of outputs.
6956  std::move(par_batch_transform)( // par-transform batches of inputs.
6957  fn::in_groups_of(batch_size)( // batch the inputs.
6958  std::move(inputs))));
6959  };
6960  }
6961 
6962 #endif // __cplusplus >= 201402L
6963 
6964  template<typename InGen>
6965  struct gen
6966  {
6967  InGen gen;
6968  const Async async;
6969  const F map_fn;
6970  const size_t queue_cap;
6971 
6972  using value_type = decltype(map_fn(std::move(*gen())));
6973 
6974 #if 0
6975  using queue_t = std::deque<std::future<value_type>>;
6976 #else
6977  // Instead of assuming that async returns a std::future,
6978  // support the usage of any future-like type,
6979  // allowing integration of 3rd-party async-like libraries.
6981  {
6982  // we only need this in decltype context, but won't link without the body definition.
6984  {
6985  return value_type{};
6986  }
6987  };
6988  using future_like_t = decltype(async(value_type_callable{}));
6989  using queue_t = std::deque<future_like_t>;
6990 #endif
6991 
6993 
6994  /////////////////////////////////////////////////////////////////
6995 
6997  {
6998  // behave like a plain impl::transform in in-this-thread mode
6999  if(queue_cap == 0) {
7000  assert(queue.empty());
7001  auto x = gen();
7002  if(!x) {
7003  return { };
7004  } else {
7005  return map_fn(std::move(*x));
7006  }
7007  }
7008 
7009  struct job_t // wrapper for invoking fn on inp, passed by move
7010  {
7011  using input_t = typename InGen::value_type;
7012 
7013  const F& fn;
7014  input_t inp;
7015 
7016  auto operator()() -> decltype(fn(std::move(inp)))
7017  {
7018  return fn(std::move(inp));
7019  }
7020  };
7021 
7022  // if have more inputs, top-off the queue with async-tasks.
7023  while(queue.size() < queue_cap) {
7024  auto x = gen();
7025 
7026  if(!x) {
7027  break;
7028  }
7029 
7030  queue.emplace_back( async( job_t{ map_fn, std::move(*x) }));
7031  }
7032 
7033  if(queue.empty()) {
7034  return { };
7035  }
7036 
7037  auto ret = queue.front().get(); // this returns by-value
7038  queue.pop_front();
7039  return { std::move(ret) };
7040  }
7041  };
7042 
7043  RANGELESS_FN_OVERLOAD_FOR_SEQ( async, map_fn, queue_cap, {} )
7044  RANGELESS_FN_OVERLOAD_FOR_CONT( async, map_fn, queue_cap, {} )
7045  };
7046 
7047 } // namespace impl
7048 
7049 
7050  /// @defgroup parallel
7051  /// @{
7052 
7053 
7054  /// \brief Wrap generating `seq` in an async-task.
7055  /*!
7056  @code
7057  long i = 0, res = 0;
7058  fn::seq([&]{ return i < 9 ? i++ : fn::end_seq(); })
7059  % fn::transform([](long x) { return x + 1; })
7060  % fn::to_async(42) // the generator+transform will be offloaded to an async-task
7061  // and the elements will be yielded via 42-capacity blocking queue.
7062  // (If we wanted the generator and transform to be offloaded to
7063  // separate threads, we could insert another to_async() before transform()).
7064  % fn::for_each([&](long x) {
7065  res = res * 10 + x;
7066  });
7067  assert(res == 123456789);
7068  @endcode
7069  */
7070  inline impl::async_wr to_async(size_t queue_size = 16)
7071  {
7072  return { queue_size };
7073  }
7074 
7075 
7076  /// @brief Parallelized version of `fn::transform`
7077  ///
7078  /// Requires `#define RANGELESS_FN_ENABLE_PARALLEL 1` before `#include fn.hpp` because
7079  /// it brings in "heavy" STL `#include`s (`<future>` and `<thread>`).
7080  ///
7081  /// `queue_capacity` is the maximum number of simultaneosly-running `std::async`-tasks, each executing a single invocation of `map_fn`.
7082  ///
7083  /// NB: if the execution time of `map_fn` is highly variable, having higher capacity may help, such that
7084  /// tasks continue to execute while we're blocked waiting on a result from a long-running task.
7085  ///
7086  /// NB: If the tasks are too small compared to overhead of running as async-task,
7087  /// it may be helpful to batch them (see `fn::in_groups_of`), have `map_fn` produce
7088  /// a vector of outputs from a vector of inputs, and `fn::concat` the outputs.
7089  ///
7090  /// `map_fn` is required to be thread-safe.
7091  ///
7092  /// NB: the body of the `map_fn` would normally compute the result in-place,
7093  /// but it could also, for example, execute a subprocess do it, or offload it
7094  /// to a cloud or a compute-farm, etc.
7095  ///
7096  /// ---
7097  /// Q: Why do we need this? We have parallel `std::transform` and `std::transform_reduce` in c++17?
7098  ///
7099  /// A: Parallel `std::transform` requires a multi-pass `ForwardRange`
7100  /// rather than `InputRange`, and `std::terminate`s if any of the tasks throws.
7101  /// `std::transform_reduce` requires `ForwardRange` and type-symmetric, associative, and commutative `BinaryOp`
7102  /// (making it next-to-useless).
7103  ///
7104  /*!
7105  @code
7106  // Example: implement parallelized gzip compressor (a-la pigz)
7107 
7108  #define RANGELESS_FN_ENABLE_PARALLEL 1
7109  #include "fn.hpp"
7110 
7111  #include <util/compress/stream_util.hpp>
7112 
7113  int main()
7114  {
7115  auto& istr = std::cin;
7116  auto& ostr = std::cout;
7117 
7118  istr.exceptions(std::ios::badbit);
7119  ostr.exceptions(std::ios::failbit | std::ios::badbit);
7120 
7121  namespace fn = rangeless::fn;
7122  using fn::operators::operator%;
7123  using bytes_t = std::string;
7124 
7125  fn::seq([&istr]() -> bytes_t
7126  {
7127  auto buf = bytes_t(1000000UL, '\0');
7128  istr.read(&buf[0], std::streamsize(buf.size()));
7129  buf.resize(size_t(istr.gcount()));
7130  return !buf.empty() ? std::move(buf) : fn::end_seq();
7131  })
7132 
7133  % fn::transform_in_parallel([](bytes_t buf) -> bytes_t
7134  {
7135  // compress the block.
7136  std::ostringstream local_ostr;
7137  ncbi::CCompressOStream{
7138  local_ostr,
7139  ncbi::CCompressOStream::eGZipFile } << buf;
7140  return local_ostr.str();
7141 
7142  }).queue_capacity( std::thread::hardware_concurrency() )
7143 
7144  % fn::for_each([&ostr](bytes_t buf)
7145  {
7146  ostr.write(buf.data(), std::streamsize(buf.size()));
7147  });
7148 
7149  return istr.eof() && !istr.bad() ? 0 : 1;
7150  }
7151 
7152  @endcode
7153 
7154  See an similar examples using [RaftLib](https://medium.com/cat-dev-urandom/simplifying-parallel-applications-for-c-an-example-parallel-bzip2-using-raftlib-with-performance-f69cc8f7f962)
7155  or [TBB](https://software.intel.com/en-us/node/506068)
7156  */
7157  template<typename F>
7159  {
7160  return { impl::std_async{}, std::move(map_fn), std::thread::hardware_concurrency() };
7161  }
7162 
7163 
7164  /// @brief A version of `transform_in_parallel` that uses a user-provided Async (e.g. backed by a fancy work-stealing thread-pool implementation).
7165  ///
7166  /// `Async` is a unary invokable having the following signature:
7167  /// `template<typename NullaryInvokable> operator()(NullaryInvokable job) const -> std::future<decltype(job())>`
7168  ///
7169  /// NB: `Async` must be copy-constructible (may be passed via `std::ref` as appropriate).
7170  ///
7171  /// A single-thread pool can be used to offload the transform-stage to a separate thread if `transform` is not parallelizeable.
7172  /*!
7173  @code
7174  auto res2 =
7175  std::vector{{1,2,3,4,5}} // can be an InputRange
7176 
7177  % fn::transform_in_parallel([](auto x)
7178  {
7179  return std::to_string(x);
7180  },
7181  [&my_thread_pool](auto job) -> std::future<decltype(job())>
7182  {
7183  return my_thread_pool.enqueue(std::move(job));
7184  }).queue_capacity(10)
7185 
7186  % fn::foldl_d([](std::string out, std::string in)
7187  {
7188  return std::move(out) + "," + in;
7189  });
7190  VERIFY(res2 == ",1,2,3,4,5");
7191  @endcode
7192  */
7193  template<typename F, typename Async>
7195  {
7196  return { std::move(async), std::move(map_fn), std::thread::hardware_concurrency() };
7197  }
7198 
7199  ///@}
7200  // defgroup parallel
7201 
7202 } // namespace fn
7203 } // namespace rangeless
7204 
7205 
7206 
7207 
7208 
7209 #if RANGELESS_FN_ENABLE_RUN_TESTS
7210 #include <string>
7211 #include <iostream>
7212 #include <cctype>
7213 
7214 #ifndef VERIFY
7215 #define VERIFY(expr) if(!(expr)) RANGELESS_FN_THROW("Assertion failed: ( "#expr" ).");
7216 #endif
7217 
7218 namespace rangeless
7219 {
7220 namespace mt
7221 {
7222 namespace impl
7223 {
7224 
7225 static void run_tests()
7226 {
7227  // test that queue works with non-default-constructible types
7228  {{
7229  int x = 10;
7230  mt::synchronized_queue<std::reference_wrapper<int> > queue;
7231  queue.push( std::ref(x));
7232  queue.push( std::ref(x));
7233  queue.close();
7234 
7235  auto y = queue.pop();
7236  queue >>= [&](int& x_) { x_ = 20; };
7237  VERIFY(x == 20);
7238  VERIFY(y == 20);
7239  }}
7240 
7241  {{
7242  synchronized_queue<std::string> q{1};
7243  std::string s1 = "1";
7244  std::string s2 = "2";
7245 
7246  auto st1 = q.try_push(std::move(s1), std::chrono::milliseconds(10));
7247  auto st2 = q.try_push(std::move(s2), std::chrono::milliseconds(10));
7248 
7249  VERIFY(st1 == decltype(q)::status::success);
7250  VERIFY(s1 == "");
7251 
7252  VERIFY(st2 == decltype(q)::status::timeout);
7253  VERIFY(s2 == "2");
7254  }}
7255 
7256  {{
7257  std::cerr << "Testing queue...\n";
7258  using queue_t = mt::synchronized_queue<long, mt::lockables::atomic_mutex>;
7259 
7260  // test duration/timeout with try_pop
7261  {{
7262  queue_t q{ 10 };
7263  auto task = std::async(std::launch::async, [&] {
7264  std::this_thread::sleep_for(
7265  std::chrono::milliseconds(100));
7266  q.push(1);
7267  q.close();
7268  });
7269  long x = 0;
7270 
7271  auto res = q.try_pop(x, std::chrono::milliseconds(90));
7272  VERIFY(res == queue_t::status::timeout);
7273 
7274  auto res2 = q.try_pop(x, std::chrono::milliseconds(20)); // 110 milliseconds passed
7275  VERIFY(res2 == queue_t::status::success);
7276  VERIFY(x == 1);
7277 
7278  VERIFY(q.try_pop(x) == queue_t::status::closed);
7279  VERIFY(q.try_push(42) == queue_t::status::closed);
7280  }}
7281 
7282  // test duration/timeout with try_push
7283  {{
7284  queue_t q{ 1 };
7285  q.push(1); // make full.
7286 
7287  auto task = std::async(std::launch::async, [&] {
7288  std::this_thread::sleep_for(
7289  std::chrono::milliseconds(100));
7290  q.pop();
7291  });
7292 
7293  auto res = q.try_push(42, std::chrono::milliseconds(90));
7294  VERIFY(res == queue_t::status::timeout);
7295 
7296  auto res2 = q.try_push(42, std::chrono::milliseconds(20)); // 110 milliseconds passed
7297  VERIFY(res2 == queue_t::status::success);
7298  VERIFY(q.pop() == 42);
7299  }}
7300 
7301 
7302  {{ // test move, insert_iterator
7303  queue_t q1{ 10 };
7304 
7305  //*q1.inserter()++ = 123;
7306  q1.push(123);
7307 
7308  //auto q2 = std::move(q1);
7309  //assert(q1.empty());
7310  auto& q2 = q1;
7311 
7312  VERIFY(q2.approx_size() == 1);
7313  VERIFY(q2.pop() == 123);
7314  }}
7315 
7316  queue_t queue{ 2048 };
7317 
7318  mt::timer timer;
7319 
7320  std::vector<std::future<void>> pushers;
7321  std::vector<std::future<long>> poppers;
7322 
7323  const size_t num_cpus = std::thread::hardware_concurrency();
7324  std::cerr << "hardware concurrency: " << num_cpus << "\n";
7325  const size_t num_jobs = num_cpus / 2;
7326  const int64_t num = 100000;
7327 
7328  // using 16 push-jobs and 16 pop-jobs:
7329  // In each pop-job accumulate partial sum.
7330  for(size_t i = 0; i < num_jobs; i++) {
7331 
7332  // Using blocking push/pop
7333  /////////////////////////////////////////////////////////////////
7334 
7335  pushers.emplace_back(
7336  std::async(std::launch::async, [&]
7337  {
7338  for(long j = 0; j < num; j++) {
7339  queue.push(1);
7340  }
7341  }));
7342 
7343  poppers.emplace_back(
7344  std::async(std::launch::async, [&]
7345  {
7346  //return std::accumulate(queue.begin(), queue.end(), 0L);
7347  long acc = 0;
7348  queue >>= [&acc](long x){ acc += x; };
7349  return acc;
7350  }));
7351  }
7352 
7353  // wait for all push-jobs to finish, and
7354  // close the queue, unblocking the poppers.
7355  for(auto& fut : pushers) {
7356  fut.wait();
7357  }
7358 
7359  queue.close(); // non-blocking; queue may still be non-empty
7360 
7361  //std::cerr << "Size after close:" << queue.approx_size() << "\n";
7362 
7363  // pushing should now be prohibited,
7364  // even if the queue is not empty
7365  try {
7366  long x = 0;
7367  VERIFY(queue.try_push(std::move(x)) == queue_t::status::closed);
7368  queue.push(std::move(x));
7369  VERIFY(false);
7370  } catch(queue_t::queue_closed&) {}
7371 
7372  // collect subtotals accumulated from each pop-job.
7373  int64_t total = 0;
7374  for(auto& fut : poppers) {
7375  total += fut.get();
7376  }
7377  VERIFY(queue.approx_size() == 0);
7378 
7379 #if 0
7380  auto queue2 = std::move(queue); // test move-semantics
7381  try {
7382  long x = 0;
7383  assert(queue2.try_pop(x) == queue_t::status::closed);
7384  queue2.pop();
7385  assert(false);
7386  } catch(queue_t::closed&) {}
7387 #endif
7388 
7389  const auto n = int64_t(num_jobs) * num;
7390 
7391  VERIFY(total == n);
7392 
7393  // of async-tasks (blocking and non-blocking versions)
7394  std::cerr << "Queue throughput: " << double(total)/timer << "/s.\n";
7395  }}
7396 
7397  // test timeout;
7398  {{
7399  using queue_t = synchronized_queue<int>;
7400  queue_t queue{ 1 };
7401 
7402  int x = 5;
7403  auto res = queue.try_pop(x, std::chrono::milliseconds(10));
7404  VERIFY(res == queue_t::status::timeout);
7405  VERIFY(x == 5);
7406 
7407  queue.push(10);
7408  res = queue.try_push(10, std::chrono::milliseconds(10));
7409  VERIFY(res == queue_t::status::timeout);
7410  }}
7411 
7412 
7413  namespace fn = rangeless::fn;
7414  using fn::operators::operator%;
7415 
7416  // test to_async
7417  {{
7418  long i = 0;
7419  long res = 0;
7420 
7421  timer timer{};
7422 
7423  fn::seq([&]{ return i <= 1000000 ? i++ : fn::end_seq(); })
7424  % fn::to_async(4096) // the generator+transform will be offloaded to an async-task
7425  // and the elements will be yielded via 2048-capacity blocking queue.
7426  // (If we wanted the generator and transform to be offloaded to
7427  // separate threads, we could insert another to_async() before transform()).
7428  % fn::for_each([&](long x) {
7429  res = res + x;
7430  });
7431  VERIFY(res == 500000500000);
7432  std::cerr << "to_async throughput: " << double(1000000)/timer << "/s.\n";
7433  }}
7434 
7435  // test transform_in_parallel
7436  {{
7437  auto res = std::vector<int>({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20})
7438  % fn::transform_in_parallel([](int x) { return x; }).queue_capacity(10)
7439  % fn::foldl_d([](std::string out, int in)
7440  {
7441  return std::move(out) + "," + std::to_string(in);
7442  });
7443  VERIFY(res == ",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20");
7444 
7445 
7446 #if __cplusplus >= 201402L
7447  auto res2 = std::vector<int>({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20})
7448  % fn::transform_in_parallel([](int x) { return std::to_string(x); },
7449  [](auto job)
7450  {
7451  return std::async(std::launch::async, std::move(job));
7452  }).queue_capacity(10)
7453  .in_batches_of(2)
7454  % fn::foldl_d([](std::string out, std::string in)
7455  {
7456  return std::move(out) + "," + in;
7457  });
7458  VERIFY(res2 == ",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20");
7459 #endif
7460  }}
7461 
7462 
7463 } // run_tests()
7464 
7465 } // namespace impl
7466 } // namespace mt
7467 } // namespace rangeless
7468 
7469 #endif // RANGELESS_FN_ENABLE_RUN_TESTS
7470 
7471 #endif // RANGELESS_FN_ENABLE_PAR
7472 
7473 
7474 
7475 
7476 
7477 
7478 
7479 #if defined(_MSC_VER)
7480 # pragma warning(pop)
7481 #endif
7482 
7483 #endif // #ifndef RANGELESS_FN_HPP_
impl::async_wr to_async(size_t queue_size=16)
Wrap generating seq in an async-task.
Definition: fn.hpp:7070
impl::foldl_d< Op > foldl_d(Op binary_op)
Fold-Left-with-Default: this version uses default-initialized value for init.
Definition: fn.hpp:3757
#define RANGELESS_FN_THROW(msg)
Definition: fn.hpp:52
Optionally-bounded blocking concurrent MPMC queue.
Definition: fn.hpp:6413
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1926
std::vector< std::string > row_t
Definition: fn.hpp:4642
~scope_guard() noexcept(noexcept(fn()))
Definition: fn.hpp:3431
typename InGen::value_type value_type
Definition: fn.hpp:2539
decltype(gen()) value_type
Definition: fn.hpp:359
status try_push(value_type &&value, Duration timeout={})
In case of success, the value will be moved-from.
Definition: fn.hpp:6593
view< std::reverse_iterator< Iterator > > operator()(view< Iterator > v) const
Definition: fn.hpp:2439
std::vector< value_type > vec_t
Definition: fn.hpp:1921
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3078
auto operator()(Iterable src) &&-> seq< gen< Iterable >>
Definition: fn.hpp:3309
impl::group_adjacent_by< F > group_adjacent_by(F key_fn)
Group adjacent elements.
Definition: fn.hpp:4059
impl::where< impl::in_sorted_by< SortedForwardRange, F > > where_in_sorted_by(const SortedForwardRange &r, F key_fn)
Definition: fn.hpp:3910
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1772
std::vector< T > operator()(std::vector< T > vec) const
Definition: fn.hpp:1164
auto operator()(seq< Gen > r) const -> std::vector< typename seq< Gen >::value_type >
Definition: fn.hpp:1846
bool operator()(const A &a, const B &b) const
Definition: fn.hpp:787
impl::sort_by< F, impl::unstable_sort_tag > unstable_sort_by(F key_fn)
Definition: fn.hpp:4187
maybe< value_type > operator++(int)
Definition: fn.hpp:499
Ret operator()(Cont cont) const
Definition: fn.hpp:2275
impl::where_max_by< F > where_min_by(F key_fn)
Definition: fn.hpp:3981
impl::take_while< P > take_while(P pred)
Yield elements until pred evaluates to false.
Definition: fn.hpp:3832
impl::par_transform< F, impl::std_async > transform_in_parallel(F map_fn)
Parallelized version of fn::transform
Definition: fn.hpp:7158
std::future< void > fut
Definition: fn.hpp:6863
Definition: fn.hpp:54
push_t & operator=(value_type val)
Definition: fn.hpp:6473
impl::where< P > where(P pred)
Filter elements.
Definition: fn.hpp:3903
void operator()(Iterable &&src)
Definition: fn.hpp:1359
typename Gen::value_type value_type
Definition: fn.hpp:426
typename InGen::value_type value_type
Definition: fn.hpp:2061
impl::group_adjacent_by< impl::chunker > in_groups_of(size_t n)
Group adjacent elements into chunks of specified size.
Definition: fn.hpp:4135
decltype(fn(*it, *it)) value_type
Definition: fn.hpp:3289
impl::group_all_by< by::identity > group_all()
Definition: fn.hpp:4038
seq::value_type value_type
Definition: fn.hpp:468
typename InGen::value_type value_type
Definition: fn.hpp:1920
Cont operator()(const Cont &cont) const
Definition: fn.hpp:1978
Iterator begin() const
Definition: fn.hpp:998
typename queue_t::iterator iterator
Definition: fn.hpp:995
decltype(fn(gen_wr{ nullptr })) value_type
Definition: fn.hpp:1770
synchronized_queue(size_t cap=1024)
Definition: fn.hpp:6420
impl::where_max_by< F > where_max_by(F key_fn)
Filter elements to those having maximum value of fn.
Definition: fn.hpp:3968
std::vector< value_type > vec_t
Definition: fn.hpp:2540
auto operator()(seq< Gen > src) const -> decltype(fold_op(std::move(*src.get_gen()()), std::move(*src.get_gen()())))
Definition: fn.hpp:1483
void recycle(value_type &grbg)
Definition: fn.hpp:2697
impl::group_adjacent_by< by::identity > group_adjacent()
Definition: fn.hpp:4093
impl::reverse reverse()
Reverse the elements in the input container.
Definition: fn.hpp:4151
impl::where_max_by< by::identity > where_min()
Definition: fn.hpp:3986
auto operator()() -> maybe< value_type >
Definition: fn.hpp:2069
close_guard(synchronized_queue &queue)
Definition: fn.hpp:6710
typename std::common_type< typename Iterable1::value_type, typename Iterable2::value_type >::type value_type
Definition: fn.hpp:3210
typename Iterable::iterator iterator
Definition: fn.hpp:1114
seq< gen< Iterable > > operator()(Iterable src) const
Wrap a range (e.g. a container or a view) as seq.
Definition: fn.hpp:1152
auto operator()() -> maybe< value_type >
Definition: fn.hpp:361
auto operator()() -> maybe< value_type >
Definition: fn.hpp:6865
static void require_iterator_category_at_least(const Iterable &)
Definition: fn.hpp:70
seq & operator=(const seq &)=delete
impl::counts counts()
return map: value_type -> size_t
Definition: fn.hpp:3482
bool operator<(const gt &other) const
Definition: fn.hpp:760
impl::cartesian_product_with< Iterable, BinaryFn > cartesian_product_with(Iterable second, BinaryFn fn)
Definition: fn.hpp:4346
auto operator()() -> maybe< value_type >
Definition: fn.hpp:2007
bool operator!=(const iterator &other) const
Definition: fn.hpp:519
typename std::decay< decltype(key_fn(*gen()))>::type key_t
Definition: fn.hpp:3135
Iterable operator()(Iterable src) const
Definition: fn.hpp:2482
impl::where< impl::in_sorted_by< SortedForwardRange, F > > where_not_in_sorted_by(const SortedForwardRange &r, F key_fn)
Definition: fn.hpp:3927
bool operator()(const std::reference_wrapper< T > &a, const std::reference_wrapper< T > &b) const
Definition: fn.hpp:715
Iterator end() const
Definition: fn.hpp:999
decltype(async(value_type_callable{})) future_like_t
Definition: fn.hpp:6988
auto operator()(Iterable &&src) const -> decltype(fold_op(std::move(*src.begin()), *src.begin()))
Definition: fn.hpp:1463
auto operator()(Iterable1 src1) &&-> seq< gen< Iterable1 >>
Definition: fn.hpp:3223
status try_pop(value_type &value, Duration timeout={})
In case of success, the value will be move-assigned.
Definition: fn.hpp:6645
bool operator()(const T &a, const T &b) const
Definition: fn.hpp:709
auto operator()(const T &x) const -> const U &
Definition: fn.hpp:845
static iterator end()
Definition: fn.hpp:547
std::input_iterator_tag iterator_category
Definition: fn.hpp:466
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3249
impl::zip_adjacent< BinaryFn > zip_adjacent(BinaryFn fn)
Yield invocations of fn over pairs of adjacent inputs.
Definition: fn.hpp:4339
reference operator *() const
Definition: fn.hpp:508
auto operator()(seq< InGen > in) const -> Ret
Definition: fn.hpp:2243
void operator()(seq< Gen > src)
Definition: fn.hpp:1344
impl::lazy_sort_by< by::identity > lazy_sort()
lazy_sort_by with key_fn = by::identity
Definition: fn.hpp:4213
impl::memoizer< F > make_memoized(F fn)
Memoizing wrapper for non-recursive non-mutable unary lambdas (not synchronized).
Definition: fn.hpp:4492
auto from(std::istream &istr, char delim='\t', params params={}) -> fn::impl::seq< fn::impl::transform< tsv::split_on_delim >::gen< fn::impl::catch_end< tsv::get_next_line > > >
Read tab-separated-values from stream.
Definition: fn.hpp:4832
synchronized_queue::value_type value_type
Definition: fn.hpp:6467
maybe(maybe &&other) noexcept
Definition: fn.hpp:106
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3151
Implements insert_iterator and unary-invokable.
Definition: fn.hpp:6463
impl::take_top_n_by< F > take_top_n_by(size_t n, F key_fn)
Return top-n elements, sorted by key_fn.
Definition: fn.hpp:4226
pointer operator->() const
Definition: fn.hpp:512
impl::concat concat()
Flatten the result of group_all_by or group_adjacent_by.
Definition: fn.hpp:4291
impl::adapt< F > adapt(F fn)
Create a custom processing-stage function-object.
Definition: fn.hpp:3657
impl::where_max_by< by::identity > where_max()
Definition: fn.hpp:3973
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3000
Vec operator()(std::map< Key, Value > m) const
Definition: fn.hpp:1205
impl::sliding_window sliding_window(size_t win_size)
Definition: fn.hpp:3801
std::output_iterator_tag iterator_category
Definition: fn.hpp:6465
impl::unique_all_by< by::identity > unique_all()
Definition: fn.hpp:4275
impl::exists_where< Pred > exists_where(Pred p)
Definition: fn.hpp:3997
const impl::comp< F > comp
Definition: fn.hpp:2222
impl::sort_by< by::identity, impl::stable_sort_tag > sort()
sort_by with key_fn = by::identity
Definition: fn.hpp:4180
impl::take_last take_last(size_t n=1)
Yield last n elements.
Definition: fn.hpp:3846
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1814
impl::sort_by< F, impl::stable_sort_tag > sort_by(F key_fn)
stable-sort and return the input.
Definition: fn.hpp:4174
view(Iterator b, Iterator e)
Definition: fn.hpp:988
Ret operator()(Iterable &&src) &&
Definition: fn.hpp:1385
typename std::remove_reference< typename traits::arg >::type Arg
Definition: fn.hpp:3402
const SortedRange & r
Definition: fn.hpp:2220
A view is just a pair of interators with begin() and end() interface.
Definition: fn.hpp:981
decltype(map_fn(std::move(*gen()))) value_type
Definition: fn.hpp:6972
impl::foldl< Result, Op > foldl(Result init, Op binary_op)
Range-based version of c++20 (copy-free) std::accumulate
Definition: fn.hpp:3729
A simple timer.
Definition: fn.hpp:6303
e.g. for tuples or pairs, fn::group_adjacent_by(fn::by::get<string>{})
Definition: fn.hpp:842
bool operator()(const T &) const
Definition: fn.hpp:2038
size_t capacity() const noexcept
Definition: fn.hpp:6693
maybe & operator=(maybe &&other) noexcept
Definition: fn.hpp:119
typename InGen::value_type inp_t
Definition: fn.hpp:2680
par_transform && queue_capacity(size_t cap) &&
Definition: fn.hpp:6919
const Ret & operator()(const Arg &arg) const
Definition: fn.hpp:3411
impl::zip_with< Iterable, BinaryFn > zip_with(Iterable second, BinaryFn fn)
Yield pairs of elements, (up to end of the shorter range)
Definition: fn.hpp:4326
Iterable2::iterator it2
Definition: fn.hpp:3243
typename InGen::value_type inp_t
Definition: fn.hpp:1651
impl::take_while< impl::call_count_lt > take_first(size_t n=1)
Yield first n elements.
Definition: fn.hpp:3838
iterator(seq *p=nullptr)
Definition: fn.hpp:472
auto operator()(NullaryCallable gen) const -> std::future< decltype(gen())>
Definition: fn.hpp:6905
Utility to parse numbers.
Definition: fn.hpp:4851
std::map< typename Iterable::value_type, size_t > operator()(Iterable &&xs) const
Definition: fn.hpp:1270
std::map< Arg, Ret > Cache
Definition: fn.hpp:3404
auto operator %=(Arg &arg, F &&fn) -> decltype(void(std::forward< F >(fn)(std::move(arg))))
arg = fn::to(Arg{})(std::forward<F>(fn)(std::move(arg)));
Definition: fn.hpp:4561
auto recycle(G &gen, T &value, pr_high) -> decltype(gen.recycle(value), void())
Definition: fn.hpp:394
auto operator()(ReversibleContainer cont) const -> ReversibleContainer
Definition: fn.hpp:2431
bool operator()(const std::reference_wrapper< T > &a, const std::reference_wrapper< T > &b) const
Definition: fn.hpp:731
LINQ -like library of higher-order functions for data manipulation.
Definition: fn.hpp:58
impl::gt< T > decreasing(T x)
Wraps the passed value and exposes inverted operator<.
Definition: fn.hpp:898
impl::where< impl::in_sorted_by< SortedForwardRange, by::identity > > where_in_sorted(const SortedForwardRange &r)
Intersect with a sorted range.
Definition: fn.hpp:3920
seq< Gen > operator()(seq< Gen > seq) const
Definition: fn.hpp:1145
auto operator()(seq< Gen > r) const -> std::vector< typename seq< Gen >::value_type >
Definition: fn.hpp:2371
auto operator()(const P &ptr) const -> decltype(*ptr)
Definition: fn.hpp:816
Return fn::end_seq() from input-range generator function to signal end-of-inputs.
Definition: fn.hpp:281
impl::group_adjacent_by< fn::by::identity, BinaryPred > group_adjacent_if(BinaryPred pred2)
Group adjacent elements if binary predicate holds.
Definition: fn.hpp:4107
bool operator()(const Iterable &iterable) const
Definition: fn.hpp:1299
auto get_unique(Container &container, P &&pred) -> decltype(*container.begin())
Access unique element matching the predicate.
Definition: fn.hpp:4370
constexpr view< Iterator > cfrom(const Iterable &src) noexcept
Definition: fn.hpp:1080
close_guard close() noexcept
Return an RAII object that will close the queue in its destructor.
Definition: fn.hpp:6742
impl::seq< impl::catch_end< NullaryInvokable > > seq(NullaryInvokable gen_fn)
Adapt a generator function as InputRange.
Definition: fn.hpp:677
split_on_delim(char delim='\t', bool truncate_blanks=true)
Definition: fn.hpp:4763
impl::drop_while< impl::call_count_lt > drop_first(size_t n=1)
Drop first n elements.
Definition: fn.hpp:3859
#define RANGELESS_FN_OVERLOAD_FOR_SEQ(...)
Definition: fn.hpp:1507
auto set_unique(Container &container, P &&pred, Construct &&con) -> decltype(*container.begin())
Similar to get_unique, but end-insert an element if missing.
Definition: fn.hpp:4413
std::function< impl::maybe< value_type >)> gen
Definition: fn.hpp:383
impl::sort_by< by::identity, impl::unstable_sort_tag > unstable_sort()
Definition: fn.hpp:4192
decltype(map_fn(std::move(*gen()))) value_type
Definition: fn.hpp:1552
Cont operator()(Cont &cont) const
Definition: fn.hpp:2102
impl::seq< impl::refs_gen< Iterable > > refs(Iterable &src)
Adapt a reference to Iterable as seq yielding reference-wrappers.
Definition: fn.hpp:687
auto operator()(const T &x) const -> decltype(*&x.second)
Definition: fn.hpp:834
Vec operator()(seq< Gen > r) const
Definition: fn.hpp:1172
auto operator()(Iterable &&src) const -> decltype(fold_op(any(), *src.begin()))
Definition: fn.hpp:1427
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3212
std::string header
Definition: fn.hpp:4646
impl::scope_guard< F > make_scope_guard(F fn)
Basic scope guard - execute some code in guard`s destructor.
Definition: fn.hpp:4514
const size_t chunk_size
Definition: fn.hpp:2851
auto operator()(seq< Gen > src) const -> decltype(fold_op(any(), std::move(*src.get_gen()())))
Definition: fn.hpp:1442
auto operator()(P ptr) const -> typename std::remove_reference< decltype(std::move(*ptr))>::type
Definition: fn.hpp:939
auto operator()(Iterable src) const -> std::vector< typename Iterable::value_type >
Definition: fn.hpp:2591
auto operator()(const T &x) const -> const T &
Definition: fn.hpp:807
Ret operator()(seq< Gen > src) &&
Definition: fn.hpp:1404
bool closed() const noexcept
Definition: fn.hpp:6698
Very bare-bones version of std::optional-like with rebinding assignment semantics.
Definition: fn.hpp:78
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1659
typename InGen::value_type value_type
Definition: fn.hpp:2005
iterator begin()
Definition: fn.hpp:531
auto operator()(const std::string &line) &-> std::reference_wrapper< const tsv::row_t >
Definition: fn.hpp:4808
std::unique_ptr< queue_t > queue
Definition: fn.hpp:6862
bool operator==(const iterator &other) const
Definition: fn.hpp:514
auto operator()(T x) const -> typename T::first_type
Definition: fn.hpp:948
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3342
int compare(const T &a, const T &b)
Definition: fn.hpp:739
typename InGen::value_type inp_t
Definition: fn.hpp:1733
Iterable1::iterator it1
Definition: fn.hpp:3242
to_num(const Str &str)
Definition: fn.hpp:4863
Iterable2::iterator it2
Definition: fn.hpp:3202
bool empty() const
Definition: fn.hpp:1030
impl::to< Container > to(Container dest)
e.g. auto set_of_ints = fn::seq(...) % ... % fn::to(std::set<int>{});
Definition: fn.hpp:3476
impl::to_vector to_vector()
Move elements of an Iterable to std::vector.
Definition: fn.hpp:3459
impl::append< Iterable > append(Iterable next)
Yield elements of next after elements of arg.
Definition: fn.hpp:4307
Iterable1::iterator it1
Definition: fn.hpp:3201
impl::for_each_adjacent< F2 > for_each_adjacent(F2 fn2)
Definition: fn.hpp:3821
auto operator()(T x) const -> typename T::second_type
Definition: fn.hpp:957
impl::transform< F > transform(F map_fn)
Create a seq yielding results of applying the transform functions to input-elements.
Definition: fn.hpp:3670
auto operator %(Arg &&arg, F &&fn) -> decltype(std::forward< F >(fn)(std::forward< Arg >(arg)))
return std::forward<F>(fn)(std::forward<Arg>(arg))
Definition: fn.hpp:4548
auto operator()(const Arg &arg) const -> gt< decltype(val(arg))>
Definition: fn.hpp:773
constexpr view< Iterator > from(Iterator it_beg, Iterator it_end) noexcept
Create a range-view from a pair of iterators.
Definition: fn.hpp:1042
typename Iterable::iterator iterator
Definition: fn.hpp:1590
seq(seq< OtherGen > other)
Definition: fn.hpp:444
void operator<<=(Container &cont, typename Container::value_type el)
Definition: fn.hpp:4619
auto operator>>=(F &&sink) -> decltype((void) sink(this->pop()))
pop() the values into the provided sink-function until closed and empty.
Definition: fn.hpp:6553
auto operator()(const std::string &line, row_t ret={}) const &&-> tsv::row_t
Definition: fn.hpp:4771
typename gen_value_t::value_type value_type
Definition: fn.hpp:2983
bool operator()(const typename SortedRange::value_type &x) const
Definition: fn.hpp:2224
Vec operator()(Iterable src) const
Definition: fn.hpp:1180
impl::comp< F > make_comp(F key_fn)
Make binary comparison predicate from a key-function.
Definition: fn.hpp:927
Cont operator()(Cont &&cont) const
Definition: fn.hpp:2113
auto operator()() -> maybe< value_type >
Definition: fn.hpp:2702
auto operator()() -> impl::maybe< value_type >
Definition: fn.hpp:385
size_t operator()(const T &) const
Definition: fn.hpp:2855
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1556
auto operator()(seq< Gen > r) const -> std::vector< typename seq< Gen >::value_type >
Definition: fn.hpp:2476
decltype(cont.begin()) it
Definition: fn.hpp:633
typename gen_value_t::iterator iterator
Definition: fn.hpp:2982
auto first_or_default(const Container &c) -> typename Container::value_type
e.g. const CConstRef<CSeq_align> aln = first_or_default( get_alns_annot(...)->Get() );
Definition: fn.hpp:4450
impl::foldl_1< Op > foldl_1(Op binary_op)
Init-free version of foldl (first element is used as init); requires at least one element.
Definition: fn.hpp:3778
size_t approx_size() const noexcept
Definition: fn.hpp:6688
Cont operator()(const Cont &cont) const
Definition: fn.hpp:1896
auto operator()() -> maybe< value_type >
Definition: fn.hpp:2547
void reset(T &&val)
Definition: fn.hpp:132
std::string filename
Definition: fn.hpp:4655
typename InGen::value_type value_type
Definition: fn.hpp:6856
#define RANGELESS_FN_OVERLOAD_FOR_VIEW(...)
Definition: fn.hpp:1532
typename iterator::value_type value_type
Definition: fn.hpp:996
typename InGen::value_type value_type
Definition: fn.hpp:1812
auto operator()(Iterable inps) const -> seq< gen_c< Iterable >>
Definition: fn.hpp:1633
synchronized_queue & m_queue
Definition: fn.hpp:6528
bool operator==(const gt &other) const
Definition: fn.hpp:766
typename InGen::value_type gen_value_t
Definition: fn.hpp:2976
auto operator()() -> maybe< value_type >
Definition: fn.hpp:3291
decltype(fn(std::move(*it1), std::move(*it2))) value_type
Definition: fn.hpp:3247
const Gen & get_gen() const
Definition: fn.hpp:578
bool operator()(const T &a, const T &b) const
Definition: fn.hpp:725
any_seq_t< T > make_typerased(impl::seq< Gen > seq)
Type-erase a seq.
Definition: fn.hpp:3450
typename InGen::value_type value_type
Definition: fn.hpp:3071
void erase(Iterator b, Iterator e)
Definition: fn.hpp:1005
decltype(std::ref(*cont.begin())) value_type
Definition: fn.hpp:630
#define RANGELESS_FN_OVERLOAD_FOR_CONT(...)
Definition: fn.hpp:1519
impl::unique_adjacent_by< F > unique_adjacent_by(F key_fn)
Keep first element from every adjacently-equal run of elements.
Definition: fn.hpp:4251
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1599
auto operator()(Cont cont) const -> decltype(group_adjacent_by_t
Definition: fn.hpp:2903
auto operator()() -> maybe< value_type >
Definition: fn.hpp:635
impl::take_top_n_by< by::identity > take_top_n(size_t n)
Return top-n elements, sorted by identity.
Definition: fn.hpp:4232
Container operator()(Iterable src) &&
Definition: fn.hpp:1250
std::deque< future_like_t > queue_t
Definition: fn.hpp:6989
auto operator()(std::vector< seq< Gen >> vec_of_seqs) const -> seq< gen< to_seq::gen< std::vector< seq< Gen >> > >>
Definition: fn.hpp:3047
friend class seq
Definition: fn.hpp:611
auto operator()() -> maybe< value_type >
Definition: fn.hpp:6996
impl::for_each< F > for_each(F fn)
Definition: fn.hpp:3811
auto operator()() -> maybe< value_type >
Definition: fn.hpp:1120
auto operator()() -> std::reference_wrapper< const std::string >
Definition: fn.hpp:4672
typename Iterable::value_type value_type
Definition: fn.hpp:1113
auto operator()(seq< Gen > range) const -> seq< typename group_adjacent_by_t::template gen< to_seq::gen< std::vector< typename seq< Gen >::value_type >>>>
Definition: fn.hpp:2887
impl::to_seq to_seq()
Wrap an Iterable, taken by value, as seq yielding elements by-move.
Definition: fn.hpp:3469
void operator()(Iterable &&src)
Definition: fn.hpp:1321
impl::where< impl::in_sorted_by< SortedForwardRange, by::identity > > where_not_in_sorted(const SortedForwardRange &r)
Subtract a sorted range.
Definition: fn.hpp:3937
impl::unique_all_by< F > unique_all_by(F key_fn)
Uniquefy elements globally, as-if unique_adjacent_by pre-sorted by same key.
Definition: fn.hpp:4270
auto last_or_default(const Container &c) -> typename Container::value_type
Definition: fn.hpp:4463
impl::drop_while< P > drop_while(P pred)
Drop elements until pred evaluates to false.
Definition: fn.hpp:3853
auto operator()(seq< InGen > in) const -> seq< gen< InGen >>
Definition: fn.hpp:1573
Container operator()(Container src) &&
Definition: fn.hpp:1236
std::map< key_t, bool > seen_t
Definition: fn.hpp:3145
auto operator()(Iterable1 src1) &&-> seq< gen< Iterable1 >>
Definition: fn.hpp:3269
to_num(const char *str)
Definition: fn.hpp:4857
typename std::conditional< std::is_same< inp_t, char >::value, std::string, std::vector< inp_t > >::type value_type
Definition: fn.hpp:2685
auto operator()(const T &x) const -> decltype(*&x.first)
Definition: fn.hpp:825
seq & set_resumable(bool res=true)
Definition: fn.hpp:568
Iterable operator()(Iterable &&inps) const
Definition: fn.hpp:1878
impl::drop_last drop_last(size_t n=1)
Drop last n elements.
Definition: fn.hpp:3867
typename InGen::value_type value_type
Definition: fn.hpp:3133
void operator()(value_type val) noexcept(false)
Blocking push. May throw queue_closed
Definition: fn.hpp:6484
auto operator()(T x) -> std::pair< size_t, T >
Definition: fn.hpp:968
impl::group_all_by< F > group_all_by(F key_fn)
Similar to group_adjacent_by, but presorts the elements.
Definition: fn.hpp:4033
get_next_line(std::istream &istr, params p=params{})
Definition: fn.hpp:4667
impl::lazy_sort_by< F > lazy_sort_by(F key_fn)
Unstable lazy sort.
Definition: fn.hpp:4207
typename traits::ret Ret
Definition: fn.hpp:3403
Cont operator()(const Cont &cont) const
Definition: fn.hpp:2088
auto operator()(Iterable1 src1) &&-> seq< gen< Iterable1 >>
Definition: fn.hpp:3369
impl::unique_adjacent_by< by::identity > unique_adjacent()
Definition: fn.hpp:4256
exists_where operator!() &&
Definition: fn.hpp:1288