RxCpp
The Reactive Extensions for Native (RxCpp) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators in both C and C++.
linq.hpp
Go to the documentation of this file.
1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2 
125 
126 
127 
128 #if !defined(CPPLINQ_LINQ_HPP)
129 #define CPPLINQ_LINQ_HPP
130 #pragma once
131 
132 #pragma push_macro("min")
133 #pragma push_macro("max")
134 #undef min
135 #undef max
136 
137 #include <functional>
138 #include <iterator>
139 #include <algorithm>
140 #include <numeric>
141 #include <list>
142 #include <map>
143 #include <set>
144 #include <memory>
145 #include <utility>
146 #include <type_traits>
147 #include <vector>
148 #include <cstddef>
149 
150 
151 
152 // some configuration macros
153 #if _MSC_VER > 1600 || __cplusplus > 199711L
154 #define LINQ_USE_RVALUEREF 1
155 #endif
156 
157 #if (defined(_MSC_VER) && _CPPRTTI) || !defined(_MSC_VER)
158 #define LINQ_USE_RTTI 1
159 #endif
160 
161 #if defined(__clang__)
162 #if __has_feature(cxx_rvalue_references)
163 #define LINQ_USE_RVALUEREF 1
164 #endif
165 #if __has_feature(cxx_rtti)
166 #define LINQ_USE_RTTI 1
167 #endif
168 #endif
169 
170 
171 // individual features
172 #include "util.hpp"
173 #include "linq_cursor.hpp"
174 #include "linq_iterators.hpp"
175 #include "linq_select.hpp"
176 #include "linq_take.hpp"
177 #include "linq_skip.hpp"
178 #include "linq_groupby.hpp"
179 #include "linq_where.hpp"
180 #include "linq_last.hpp"
181 #include "linq_selectmany.hpp"
182 
183 
184 
185 
186 namespace cpplinq
187 {
188 
189 namespace detail
190 {
191  template<class Pred>
192  struct not1_{
193  Pred pred;
194  not1_(Pred p) : pred(p)
195  {}
196  template<class T>
197  bool operator()(const T& value)
198  {
199  return !pred(value);
200  }
201  };
202  // note: VC2010's std::not1 doesn't support lambda expressions. provide our own.
203  template<class Pred>
204  not1_<Pred> not1(Pred p) { return not1_<Pred>(p); }
205 }
206 
207 namespace detail {
208  template <class U>
209  struct cast_to {
210  template <class T>
211  U operator()(const T& value) const {
212  return static_cast<U>(value);
213  }
214  };
215 }
216 
217 template <class Collection>
219 {
220  typedef typename Collection::cursor::element_type
221  element_type;
222  typedef typename Collection::cursor::reference_type
223  reference_type;
224 public:
227 
228  linq_driver(Collection c) : c(c) {}
229 
230 
231  // -------------------- linq core methods --------------------
232 
233  template <class KeyFn>
235  {
236  return linq_groupby<Collection, KeyFn>(c, std::move(fn) );
237  }
238 
239  // TODO: groupby(keyfn, eq)
240 
241  // TODO: join...
242 
243  template <class Selector>
245  return linq_select<Collection, Selector>(c, std::move(sel) );
246  }
247 
248  template <class Fn>
250  select_many(Fn fn) const
251  {
252  return linq_select_many<Collection, Fn, detail::default_select_many_selector>(c, fn, detail::default_select_many_selector());
253  }
254 
255  template <class Fn, class Fn2>
257  {
258  return linq_select_many<Collection, Fn, Fn2>(c, fn, fn2);
259  }
260 
261  template <class Predicate>
263  return linq_where<Collection, Predicate>(c, std::move(p) );
264  }
265 
266 
267  // -------------------- linq peripheral methods --------------------
268 
269  template <class Fn>
270  element_type aggregate(Fn fn) const
271  {
272  auto it = begin();
273  if (it == end()) {
274  return element_type();
275  }
276 
277  reference_type first = *it;
278  return std::accumulate(++it, end(), first, fn);
279  }
280 
281  template <class T, class Fn>
282  T aggregate(T initialValue, Fn fn) const
283  {
284  return std::accumulate(begin(), end(), initialValue, fn);
285  }
286 
287  bool any() const { auto cur = c.get_cursor(); return !cur.empty(); }
288 
289  template <class Predicate>
290  bool any(Predicate p) const {
291  auto it = std::find_if(begin(), end(), p);
292  return it != end();
293  }
294 
295  template <class Predicate>
296  bool all(Predicate p) const {
297  auto it = std::find_if(begin(), end(), detail::not1(p));
298  return it == end();
299  }
300 
301  // TODO: average
302 
303 #if !defined(__clang__)
304  // Clang complains that linq_driver is not complete until the closing brace
305  // so (linq_driver*)->select() cannot be resolved.
306  template <class U>
307  auto cast()
308  -> decltype(static_cast<linq_driver*>(0)->select(detail::cast_to<U>()))
309  {
310  return this->select(detail::cast_to<U>());
311  }
312 #endif
313 
314  // TODO: concat
315 
316  bool contains(const typename Collection::cursor::element_type& value) const {
317  return std::find(begin(), end(), value) != end();
318  }
319 
320  typename std::iterator_traits<iterator>::difference_type count() const {
321  return std::distance(begin(), end());
322  }
323 
324  template <class Predicate>
325  typename std::iterator_traits<iterator>::difference_type count(Predicate p) const {
326  auto filtered = this->where(p);
327  return std::distance(begin(filtered), end(filtered));
328  }
329 
330  // TODO: default_if_empty
331 
332  // TODO: distinct()
333  // TODO: distinct(cmp)
334 
335  reference_type element_at(std::size_t ix) const {
336  auto cur = c.get_cursor();
337  while(ix && !cur.empty()) {
338  cur.inc();
339  --ix;
340  }
341  if (cur.empty()) { throw std::logic_error("index out of bounds"); }
342  else { return cur.get(); }
343  }
344 
345  element_type element_at_or_default(std::size_t ix) const {
346  auto cur = c.get_cursor();
347  while(ix && !cur.empty()) {
348  cur.inc();
349  -- ix;
350  }
351  if (cur.empty()) { return element_type(); }
352  else { return cur.get(); }
353  }
354 
355  bool empty() const {
356  return !this->any();
357  }
358 
359  // TODO: except(second)
360  // TODO: except(second, eq)
361 
362  reference_type first() const {
363  auto cur = c.get_cursor();
364  if (cur.empty()) { throw std::logic_error("index out of bounds"); }
365  else { return cur.get(); }
366  }
367 
368  template <class Predicate>
369  reference_type first(Predicate pred) const {
370  auto cur = c.get_cursor();
371  while (!cur.empty() && !pred(cur.get())) {
372  cur.inc();
373  }
374  if (cur.empty()) { throw std::logic_error("index out of bounds"); }
375  else { return cur.get(); }
376  }
377 
378  element_type first_or_default() const {
379  auto cur = c.get_cursor();
380  if (cur.empty()) { return element_type(); }
381  else { return cur.get(); }
382  }
383 
384  template <class Predicate>
385  element_type first_or_default(Predicate pred) const {
386  auto cur = c.get_cursor();
387  while (!cur.empty() && !pred(cur.get())) {
388  cur.inc();
389  }
390  if (cur.empty()) { return element_type(); }
391  else { return cur.get(); }
392  }
393 
394  // TODO: intersect(second)
395  // TODO: intersect(second, eq)
396 
397  // note: forward cursors and beyond can provide a clone, so we can refer to the element directly
398  typename std::conditional<
399  std::is_convertible<
400  typename Collection::cursor::cursor_category,
401  forward_cursor_tag>::value,
402  reference_type,
403  element_type>::type
404  last() const
405  {
406  return linq_last_(c.get_cursor(), typename Collection::cursor::cursor_category());
407  }
408 
409  template <class Predicate>
410  reference_type last(Predicate pred) const
411  {
412  auto cur = c.where(pred).get_cursor();
413  return linq_last_(cur, typename decltype(cur)::cursor_category());
414  }
415 
416  element_type last_or_default() const
417  {
418  return linq_last_or_default_(c.get_cursor(), typename Collection::cursor::cursor_category());
419  }
420 
421  template <class Predicate>
422  element_type last_or_default(Predicate pred) const
423  {
424  auto cur = c.where(pred).get_cursor();
425  return linq_last_or_default_(cur, typename decltype(cur)::cursor_category());
426  }
427 
428  reference_type max() const
429  {
430  return max(std::less<element_type>());
431  }
432 
433  template <class Compare>
434  reference_type max(Compare less) const
435  {
436  auto it = std::max_element(begin(), end(), less);
437  if (it == end())
438  throw std::logic_error("max performed on empty range");
439 
440  return *it;
441  }
442 
443  reference_type min() const
444  {
445  return min(std::less<element_type>());
446  }
447 
448  template <class Compare>
449  reference_type min(Compare less) const
450  {
451  auto it = std::min_element(begin(), end(), less);
452  if (it == end())
453  throw std::logic_error("max performed on empty range");
454 
455  return *it;
456  }
457 
458  // TODO: order_by(sel)
459  // TODO: order_by(sel, less)
460  // TODO: order_by_descending(sel)
461  // TODO: order_by_descending(sel, less)
462 
463  // TODO: sequence_equal(second)
464  // TODO: sequence_equal(second, eq)
465 
466  // TODO: single / single_or_default
467 
468  linq_driver<linq_skip<Collection>> skip(std::size_t n) const {
469  return linq_skip<Collection>(c, n);
470  }
471 
472  // TODO: skip_while(pred)
473 
474  template<typename ITEM = typename element_type>
475  typename std::enable_if<std::is_default_constructible<ITEM>::value, ITEM>::type sum() const {
476  ITEM seed{};
477  return sum(seed);
478  }
479 
480  typename element_type sum(typename element_type seed) const {
481  return std::accumulate(begin(), end(), seed);
482  }
483 
484  template <typename Selector, typename Result = std::result_of<Selector(typename element_type)>::type>
485  typename std::enable_if<std::is_default_constructible<Result>::value, Result>::type sum(Selector sel) const {
486  return from(begin(), end()).select(sel).sum();
487  }
488 
489  template <typename Selector, typename Result = std::result_of<Selector(typename element_type)>::type>
490  Result sum(Selector sel, Result seed) const {
491  return from(begin(), end()).select(sel).sum(seed);
492  }
493 
494  linq_driver<linq_take<Collection>> take(std::size_t n) const {
495  return linq_take<Collection>(c, n);
496  }
497 
498  // TODO: take_while
499 
500  // TODO: then_by / then_by_descending ?
501 
502  // TODO: to_...
503 
504  // TODO: union(second)
505  // TODO: union(eq)
506 
507  // TODO: zip
508 
509  // -------------------- conversion methods --------------------
510 
511  std::vector<typename Collection::cursor::element_type> to_vector() const
512  {
513  return std::vector<typename Collection::cursor::element_type>(begin(), end());
514  }
515 
516  std::list<typename Collection::cursor::element_type> to_list() const
517  {
518  return std::list<typename Collection::cursor::element_type>(begin(), end());
519  }
520 
521  std::set<typename Collection::cursor::element_type> to_set() const
522  {
523  return std::set<typename Collection::cursor::element_type>(begin(), end());
524  }
525 
526  // -------------------- container/range methods --------------------
527 
528  iterator begin() const { auto cur = c.get_cursor(); return !cur.empty() ? iterator(cur) : iterator(); }
529  iterator end() const { return iterator(); }
530  linq_driver& operator=(const linq_driver& other) { c = other.c; return *this; }
531  template <class TC2>
532  linq_driver& operator=(const linq_driver<TC2>& other) { c = other.c; return *this; }
533 
534  typename std::iterator_traits<iterator>::reference
535  operator[](std::size_t ix) const {
536  return *(begin()+=ix);
537  }
538 
539  // -------------------- collection methods (leaky abstraction) --------------------
540 
541  typedef typename Collection::cursor cursor;
542  cursor get_cursor() { return c.get_cursor(); }
543 
545  late_bind() const
546  {
548  }
549 
550 private:
551  Collection c;
552 };
553 
554 // TODO: should probably use reference-wrapper instead?
555 template <class TContainer>
557 {
558  auto cur = iter_cursor<typename util::container_traits<TContainer>::iterator>(std::begin(c), std::end(c));
559  return cur;
560 }
561 template <class T>
563 {
564  return c;
565 }
566 template <class Iter>
567 linq_driver<iter_cursor<Iter>> from(Iter start, Iter finish)
568 {
569  return iter_cursor<Iter>(start, finish);
570 }
571 
572 template <class TContainer>
574 {
575  return linq_driver<TContainer>(c);
576 }
577 
578 }
579 
580 #pragma pop_macro("min")
581 #pragma pop_macro("max")
582 
583 #endif // defined(CPPLINQ_LINQ_HPP)
584 
reference_type max() const
Definition: linq.hpp:428
Definition: linq_select.hpp:12
linq_driver< linq_select_many< Collection, Fn, detail::default_select_many_selector > > select_many(Fn fn) const
Definition: linq.hpp:250
reference_type max(Compare less) const
Definition: linq.hpp:434
auto any(AN &&...an) -> operator_factory< any_tag, AN... >
Returns an Observable that emits true if any item emitted by the source Observable satisfies a specif...
Definition: rx-any.hpp:121
Definition: linq_iterators.hpp:116
linq_driver< linq_take< Collection > > take(std::size_t n) const
Definition: linq.hpp:494
cursor_iterator< typename Collection::cursor > iterator
Definition: linq.hpp:226
iterator begin() const
Definition: linq.hpp:528
element_type last_or_default() const
Definition: linq.hpp:416
std::set< typename Collection::cursor::element_type > to_set() const
Definition: linq.hpp:521
Definition: linq_selectmany.hpp:72
auto max() -> operator_factory< max_tag >
For each item from this observable reduce it by taking the max value of the previous items...
Definition: rx-reduce.hpp:496
linq_driver< linq_groupby< Collection, KeyFn > > groupby(KeyFn fn)
Definition: linq.hpp:234
reference_type last(Predicate pred) const
Definition: linq.hpp:410
bool contains(const typename Collection::cursor::element_type &value) const
Definition: linq.hpp:316
Definition: linq_cursor.hpp:143
std::vector< typename Collection::cursor::element_type > to_vector() const
Definition: linq.hpp:511
bool empty() const
Definition: linq.hpp:355
Definition: linq_take.hpp:66
T aggregate(T initialValue, Fn fn) const
Definition: linq.hpp:282
linq_driver< iter_cursor< typename util::container_traits< TContainer >::iterator > > from(TContainer &c)
Definition: linq.hpp:556
std::list< typename Collection::cursor::element_type > to_list() const
Definition: linq.hpp:516
linq_driver< linq_skip< Collection > > skip(std::size_t n) const
Definition: linq.hpp:468
linq_driver< dynamic_collection< typename Collection::cursor::reference_type > > late_bind() const
Definition: linq.hpp:545
element_type first_or_default() const
Definition: linq.hpp:378
Cursor::element_type linq_last_(Cursor c, onepass_cursor_tag)
Definition: linq_last.hpp:11
Definition: linq.hpp:186
Definition: linq_cursor.hpp:64
auto first() -> operator_factory< first_tag >
For each item from this observable reduce it by sending only the first item.
Definition: rx-reduce.hpp:378
std::iterator_traits< iterator >::reference operator[](std::size_t ix) const
Definition: linq.hpp:535
std::iterator_traits< iterator >::difference_type count(Predicate p) const
Definition: linq.hpp:325
bool any() const
Definition: linq.hpp:287
auto sum() -> operator_factory< sum_tag >
For each item from this observable reduce it by adding to the previous items.
Definition: rx-reduce.hpp:454
Definition: linq_skip.hpp:12
element_type aggregate(Fn fn) const
Definition: linq.hpp:270
Definition: linq_cursor.hpp:293
auto cast() -> decltype(static_cast< linq_driver * >(0) ->select(detail::cast_to< U >()))
Definition: linq.hpp:307
element_type last_or_default(Predicate pred) const
Definition: linq.hpp:422
auto min() -> operator_factory< min_tag >
For each item from this observable reduce it by taking the min value of the previous items...
Definition: rx-reduce.hpp:475
linq_driver< TContainer > from_value(const TContainer &c)
Definition: linq.hpp:573
element_type sum(typename element_type seed) const
Definition: linq.hpp:480
Cursor::element_type linq_last_or_default_(Cursor c, onepass_cursor_tag)
Definition: linq_last.hpp:50
reference_type min() const
Definition: linq.hpp:443
bool all(Predicate p) const
Definition: linq.hpp:296
linq_driver & operator=(const linq_driver< TC2 > &other)
Definition: linq.hpp:532
std::enable_if< std::is_default_constructible< ITEM >::value, ITEM >::type sum() const
Definition: linq.hpp:475
bool any(Predicate p) const
Definition: linq.hpp:290
reference_type element_at(std::size_t ix) const
Definition: linq.hpp:335
linq_driver< linq_where< Collection, Predicate > > where(Predicate p) const
Definition: linq.hpp:262
Result sum(Selector sel, Result seed) const
Definition: linq.hpp:490
linq_driver(Collection c)
Definition: linq.hpp:228
Definition: linq.hpp:218
cursor get_cursor()
Definition: linq.hpp:542
linq_driver< linq_select< Collection, Selector > > select(Selector sel) const
Definition: linq.hpp:244
Definition: linq_where.hpp:10
std::iterator_traits< iterator >::difference_type count() const
Definition: linq.hpp:320
reference_type first() const
Definition: linq.hpp:362
Definition: linq_groupby.hpp:58
Collection::cursor cursor
Definition: linq.hpp:541
iterator end() const
Definition: linq.hpp:529
reference_type first(Predicate pred) const
Definition: linq.hpp:369
element_type first_or_default(Predicate pred) const
Definition: linq.hpp:385
std::enable_if< std::is_default_constructible< Result >::value, Result >::type sum(Selector sel) const
Definition: linq.hpp:485
linq_driver & operator=(const linq_driver &other)
Definition: linq.hpp:530
element_type element_at_or_default(std::size_t ix) const
Definition: linq.hpp:345
auto accumulate(AN &&...an) -> operator_factory< reduce_tag, AN... >
For each item from this observable use Accumulator to combine items, when completed use ResultSelecto...
Definition: rx-reduce.hpp:361
std::conditional< std::is_convertible< typename Collection::cursor::cursor_category, forward_cursor_tag >::value, reference_type, element_type >::type last() const
Definition: linq.hpp:404
linq_driver< linq_select_many< Collection, Fn, Fn2 > > select_many(Fn fn, Fn2 fn2) const
Definition: linq.hpp:256
reference_type min(Compare less) const
Definition: linq.hpp:449