diff options
Diffstat (limited to 'Ix/CPP/src/cpplinq/linq.hpp')
-rw-r--r-- | Ix/CPP/src/cpplinq/linq.hpp | 584 |
1 files changed, 0 insertions, 584 deletions
diff --git a/Ix/CPP/src/cpplinq/linq.hpp b/Ix/CPP/src/cpplinq/linq.hpp deleted file mode 100644 index 6552f79..0000000 --- a/Ix/CPP/src/cpplinq/linq.hpp +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -/// -/// namespace cpplinq -/// ----------------- -/// -/// Defines a number of range-based composable operators for enumerating and modifying collections -/// -/// The general design philosophy is to -/// (1) emulate the composable query patterns introduced in C# Linq -/// (2) preserve iterator category and writability where possible -/// For instance, like C# Linq we have a select operator to project one sequence into a new one. -/// Unlike Linq, invoking Select on a random access sequence will yield you a _random_ access sequence. -/// -/// The general workflow begins with 'from()' which normally only takes a reference -/// the the collection in question. However, from that point on, all operators function -/// by value, so that the range can store any necessary state, rather than duplicating it -/// onto iterator pairs. -/// -/// In subsequent documentation, "powers" lists which powers that the operator attempts to preserve if -/// available on on the input sequence. Some iterator powers may be skipped - in such a case, round down -/// to the next supported power (e.g. if 'fwd' and 'rnd', an input of 'bidi' will round down to a 'fwd' result). -/// -/// -/// -/// class linq_query -/// ---------------- -/// -/// from(container&) -/// ================ -/// - Result: Query -/// -/// Construct a new query, from an lvalue reference to a collection. Does not copy the collection -/// -/// -/// -/// from(iter, iter) -/// ================ -/// - Result: Query -/// -/// Construct a new query, from an iterator pair. -/// -/// -/// -/// query.select(map) -/// ========================== -/// - Result: Query -/// - Powers: input, forward, bidirectional, random access -/// -/// For each element `x` in the input sequences, computes `map(x)` for the result sequence. -/// -/// -/// -/// query.where(pred) -> query -/// ========================== -/// - Result: Query -/// - Powers: input, forward, bidirectional -/// -/// Each element `x` in the input appears in the output if `pred(x)` is true. -/// -/// The expression `pred(x)` is evaluated only when moving iterators (op++, op--). -/// Dereferencing (op*) does not invoke the predicate. -/// -/// -/// -/// query.groupby(keymap [, keyequal]) -/// ==================================== -/// Result: Query of groups. Each group has a 'key' field, and is a query of elements from the input. -/// Powers: forward -/// -/// -/// -/// query.any([pred]) -/// ================= -/// - Result: bool -/// -/// (No argument) Returns true if sequence is non-empty. Equivalent to `query.begin()!=query.end()` -/// -/// (One argument) Returns true if the sequence contains any elements for which `pred(element)` is true. -/// Equivalent to `query.where(pred).any()`. -/// -/// -/// -/// query.all(pred) -/// =============== -/// - Result: bool -/// -/// Returns true if `pred` holds for all elements in the sequence. Equivalent to `!query.any(std::not1(pred))` -/// -/// -/// -/// query.take(n) -/// ============= -/// - Result: query -/// - Powers: input, forward, random access (not bidirectional) -/// -/// Returns a sequence that contains up to `n` items from the original sequence. -/// -/// -/// -/// query.skip(n) -/// ============= -/// - Result: query -/// - Powers: input, forward, random access (not bidirectional) -/// -/// Returns a sequence that skips the first `n` items from the original sequence, or an empty sequence if -/// fewer than `n` were available on input. -/// -/// Note: begin() takes O(n) time when input iteration power is weaker than random access. -/// -/// -/// -/// query.count([pred]) -/// =================== -/// - Result: std::size_t -/// -/// _TODO: should use inner container's iterator distance type instead._ -/// -/// (Zero-argument) Returns the number of elements in the range. -/// Equivalent to `std::distance(query.begin(), query.end())` -/// -/// (One-argument) Returns the number of elements for whicht `pred(element)` is true. -/// Equivalent to `query.where(pred).count()` -/// - - - -#if !defined(CPPLINQ_LINQ_HPP) -#define CPPLINQ_LINQ_HPP -#pragma once - -#pragma push_macro("min") -#pragma push_macro("max") -#undef min -#undef max - -#include <functional> -#include <iterator> -#include <algorithm> -#include <numeric> -#include <list> -#include <map> -#include <set> -#include <memory> -#include <utility> -#include <type_traits> -#include <vector> -#include <cstddef> - - - -// some configuration macros -#if _MSC_VER > 1600 || __cplusplus > 199711L -#define LINQ_USE_RVALUEREF 1 -#endif - -#if (defined(_MSC_VER) && _CPPRTTI) || !defined(_MSC_VER) -#define LINQ_USE_RTTI 1 -#endif - -#if defined(__clang__) -#if __has_feature(cxx_rvalue_references) -#define LINQ_USE_RVALUEREF 1 -#endif -#if __has_feature(cxx_rtti) -#define LINQ_USE_RTTI 1 -#endif -#endif - - -// individual features -#include "util.hpp" -#include "linq_cursor.hpp" -#include "linq_iterators.hpp" -#include "linq_select.hpp" -#include "linq_take.hpp" -#include "linq_skip.hpp" -#include "linq_groupby.hpp" -#include "linq_where.hpp" -#include "linq_last.hpp" -#include "linq_selectmany.hpp" - - - - -namespace cpplinq -{ - -namespace detail -{ - template<class Pred> - struct not1_{ - Pred pred; - not1_(Pred p) : pred(p) - {} - template<class T> - bool operator()(const T& value) - { - return !pred(value); - } - }; - // note: VC2010's std::not1 doesn't support lambda expressions. provide our own. - template<class Pred> - not1_<Pred> not1(Pred p) { return not1_<Pred>(p); } -} - -namespace detail { - template <class U> - struct cast_to { - template <class T> - U operator()(const T& value) const { - return static_cast<U>(value); - } - }; -} - -template <class Collection> -class linq_driver -{ - typedef typename Collection::cursor::element_type - element_type; - typedef typename Collection::cursor::reference_type - reference_type; -public: - typedef cursor_iterator<typename Collection::cursor> - iterator; - - linq_driver(Collection c) : c(c) {} - - - // -------------------- linq core methods -------------------- - - template <class KeyFn> - linq_driver< linq_groupby<Collection, KeyFn> > groupby(KeyFn fn) - { - return linq_groupby<Collection, KeyFn>(c, std::move(fn) ); - } - - // TODO: groupby(keyfn, eq) - - // TODO: join... - - template <class Selector> - linq_driver< linq_select<Collection, Selector> > select(Selector sel) const { - return linq_select<Collection, Selector>(c, std::move(sel) ); - } - - template <class Fn> - linq_driver< linq_select_many<Collection, Fn, detail::default_select_many_selector> > - select_many(Fn fn) const - { - return linq_select_many<Collection, Fn, detail::default_select_many_selector>(c, fn, detail::default_select_many_selector()); - } - - template <class Fn, class Fn2> - linq_driver< linq_select_many<Collection, Fn, Fn2> > select_many(Fn fn, Fn2 fn2) const - { - return linq_select_many<Collection, Fn, Fn2>(c, fn, fn2); - } - - template <class Predicate> - linq_driver< linq_where<Collection, Predicate> > where(Predicate p) const { - return linq_where<Collection, Predicate>(c, std::move(p) ); - } - - - // -------------------- linq peripheral methods -------------------- - - template <class Fn> - element_type aggregate(Fn fn) const - { - auto it = begin(); - if (it == end()) { - return element_type(); - } - - reference_type first = *it; - return std::accumulate(++it, end(), first, fn); - } - - template <class T, class Fn> - T aggregate(T initialValue, Fn fn) const - { - return std::accumulate(begin(), end(), initialValue, fn); - } - - bool any() const { auto cur = c.get_cursor(); return !cur.empty(); } - - template <class Predicate> - bool any(Predicate p) const { - auto it = std::find_if(begin(), end(), p); - return it != end(); - } - - template <class Predicate> - bool all(Predicate p) const { - auto it = std::find_if(begin(), end(), detail::not1(p)); - return it == end(); - } - - // TODO: average - -#if !defined(__clang__) - // Clang complains that linq_driver is not complete until the closing brace - // so (linq_driver*)->select() cannot be resolved. - template <class U> - auto cast() - -> decltype(static_cast<linq_driver*>(0)->select(detail::cast_to<U>())) - { - return this->select(detail::cast_to<U>()); - } -#endif - - // TODO: concat - - bool contains(const typename Collection::cursor::element_type& value) const { - return std::find(begin(), end(), value) != end(); - } - - typename std::iterator_traits<iterator>::difference_type count() const { - return std::distance(begin(), end()); - } - - template <class Predicate> - typename std::iterator_traits<iterator>::difference_type count(Predicate p) const { - auto filtered = this->where(p); - return std::distance(begin(filtered), end(filtered)); - } - - // TODO: default_if_empty - - // TODO: distinct() - // TODO: distinct(cmp) - - reference_type element_at(std::size_t ix) const { - auto cur = c.get_cursor(); - while(ix && !cur.empty()) { - cur.inc(); - --ix; - } - if (cur.empty()) { throw std::logic_error("index out of bounds"); } - else { return cur.get(); } - } - - element_type element_at_or_default(std::size_t ix) const { - auto cur = c.get_cursor(); - while(ix && !cur.empty()) { - cur.inc(); - -- ix; - } - if (cur.empty()) { return element_type(); } - else { return cur.get(); } - } - - bool empty() const { - return !this->any(); - } - - // TODO: except(second) - // TODO: except(second, eq) - - reference_type first() const { - auto cur = c.get_cursor(); - if (cur.empty()) { throw std::logic_error("index out of bounds"); } - else { return cur.get(); } - } - - template <class Predicate> - reference_type first(Predicate pred) const { - auto cur = c.get_cursor(); - while (!cur.empty() && !pred(cur.get())) { - cur.inc(); - } - if (cur.empty()) { throw std::logic_error("index out of bounds"); } - else { return cur.get(); } - } - - element_type first_or_default() const { - auto cur = c.get_cursor(); - if (cur.empty()) { return element_type(); } - else { return cur.get(); } - } - - template <class Predicate> - element_type first_or_default(Predicate pred) const { - auto cur = c.get_cursor(); - while (!cur.empty() && !pred(cur.get())) { - cur.inc(); - } - if (cur.empty()) { return element_type(); } - else { return cur.get(); } - } - - // TODO: intersect(second) - // TODO: intersect(second, eq) - - // note: forward cursors and beyond can provide a clone, so we can refer to the element directly - typename std::conditional< - std::is_convertible< - typename Collection::cursor::cursor_category, - forward_cursor_tag>::value, - reference_type, - element_type>::type - last() const - { - return linq_last_(c.get_cursor(), typename Collection::cursor::cursor_category()); - } - - template <class Predicate> - reference_type last(Predicate pred) const - { - auto cur = c.where(pred).get_cursor(); - return linq_last_(cur, typename decltype(cur)::cursor_category()); - } - - element_type last_or_default() const - { - return linq_last_or_default_(c.get_cursor(), typename Collection::cursor::cursor_category()); - } - - template <class Predicate> - element_type last_or_default(Predicate pred) const - { - auto cur = c.where(pred).get_cursor(); - return linq_last_or_default_(cur, typename decltype(cur)::cursor_category()); - } - - reference_type max() const - { - return max(std::less<element_type>()); - } - - template <class Compare> - reference_type max(Compare less) const - { - auto it = std::max_element(begin(), end(), less); - if (it == end()) - throw std::logic_error("max performed on empty range"); - - return *it; - } - - reference_type min() const - { - return min(std::less<element_type>()); - } - - template <class Compare> - reference_type min(Compare less) const - { - auto it = std::min_element(begin(), end(), less); - if (it == end()) - throw std::logic_error("max performed on empty range"); - - return *it; - } - - // TODO: order_by(sel) - // TODO: order_by(sel, less) - // TODO: order_by_descending(sel) - // TODO: order_by_descending(sel, less) - - // TODO: sequence_equal(second) - // TODO: sequence_equal(second, eq) - - // TODO: single / single_or_default - - linq_driver<linq_skip<Collection>> skip(std::size_t n) const { - return linq_skip<Collection>(c, n); - } - - // TODO: skip_while(pred) - - template<typename ITEM = element_type> - typename std::enable_if<std::is_default_constructible<ITEM>::value, ITEM>::type sum() const { - ITEM seed{}; - return sum(seed); - } - - element_type sum(element_type seed) const { - return std::accumulate(begin(), end(), seed); - } - - template <typename Selector, typename Result = typename std::result_of<Selector(element_type)>::type> - typename std::enable_if<std::is_default_constructible<Result>::value, Result>::type sum(Selector sel) const { - return from(begin(), end()).select(sel).sum(); - } - - template <typename Selector, typename Result = typename std::result_of<Selector(element_type)>::type> - Result sum(Selector sel, Result seed) const { - return from(begin(), end()).select(sel).sum(seed); - } - - linq_driver<linq_take<Collection>> take(std::size_t n) const { - return linq_take<Collection>(c, n); - } - - // TODO: take_while - - // TODO: then_by / then_by_descending ? - - // TODO: to_... - - // TODO: union(second) - // TODO: union(eq) - - // TODO: zip - - // -------------------- conversion methods -------------------- - - std::vector<typename Collection::cursor::element_type> to_vector() const - { - return std::vector<typename Collection::cursor::element_type>(begin(), end()); - } - - std::list<typename Collection::cursor::element_type> to_list() const - { - return std::list<typename Collection::cursor::element_type>(begin(), end()); - } - - std::set<typename Collection::cursor::element_type> to_set() const - { - return std::set<typename Collection::cursor::element_type>(begin(), end()); - } - - // -------------------- container/range methods -------------------- - - iterator begin() const { auto cur = c.get_cursor(); return !cur.empty() ? iterator(cur) : iterator(); } - iterator end() const { return iterator(); } - linq_driver& operator=(const linq_driver& other) { c = other.c; return *this; } - template <class TC2> - linq_driver& operator=(const linq_driver<TC2>& other) { c = other.c; return *this; } - - typename std::iterator_traits<iterator>::reference - operator[](std::size_t ix) const { - return *(begin()+=ix); - } - - // -------------------- collection methods (leaky abstraction) -------------------- - - typedef typename Collection::cursor cursor; - cursor get_cursor() { return c.get_cursor(); } - - linq_driver< dynamic_collection<typename Collection::cursor::reference_type> > - late_bind() const - { - return dynamic_collection<typename Collection::cursor::reference_type>(c); - } - -private: - Collection c; -}; - -// TODO: should probably use reference-wrapper instead? -template <class TContainer> -linq_driver<iter_cursor<typename util::container_traits<TContainer>::iterator>> from(TContainer& c) -{ - auto cur = iter_cursor<typename util::container_traits<TContainer>::iterator>(std::begin(c), std::end(c)); - return cur; -} -template <class T> -const linq_driver<T>& from(const linq_driver<T>& c) -{ - return c; -} -template <class Iter> -linq_driver<iter_cursor<Iter>> from(Iter start, Iter finish) -{ - return iter_cursor<Iter>(start, finish); -} - -template <class TContainer> -linq_driver<TContainer> from_value(const TContainer& c) -{ - return linq_driver<TContainer>(c); -} - -} - -#pragma pop_macro("min") -#pragma pop_macro("max") - -#endif // defined(CPPLINQ_LINQ_HPP) - |