diff options
Diffstat (limited to 'Ix/CPP/src/cpplinq')
-rw-r--r-- | Ix/CPP/src/cpplinq/linq.hpp | 584 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_cursor.hpp | 342 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_groupby.hpp | 195 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_iterators.hpp | 196 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_last.hpp | 85 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_select.hpp | 54 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_selectmany.hpp | 164 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_skip.hpp | 37 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_take.hpp | 98 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/linq_where.hpp | 69 | ||||
-rw-r--r-- | Ix/CPP/src/cpplinq/util.hpp | 232 |
11 files changed, 0 insertions, 2056 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) - diff --git a/Ix/CPP/src/cpplinq/linq_cursor.hpp b/Ix/CPP/src/cpplinq/linq_cursor.hpp deleted file mode 100644 index 4c5f5b5..0000000 --- a/Ix/CPP/src/cpplinq/linq_cursor.hpp +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_CURSOR_HPP) -#define CPPLINQ_LINQ_CURSOR_HPP -#pragma once - -#include <cstddef> - -/// cursors -/// ---------- -/// It should be noted that CppLinq uses a slightly different iterator concept, one where iterators -/// know their extents. This sacrificed some generality, but it adds convenience and improves -/// some performance in some cases. Notably, captures need only be stored once instead of twice in -/// most use cases. -/// -/// Cursors and Ranges are always classes. -/// -/// To get a cursor from a range: -/// -/// get_cursor(range) -> cur -/// -/// Unlike boost ranges, CppLinq cursors are mutated directly, and may "shed state" as they are -/// mutated. For example, a GroupBy range will drop references to earlier groups, possibly -/// permitting freeing them. -/// -/// Onepass cursor -/// =========== -/// - empty(cur) -> bool : at end of sequence -/// - inc(cur) -/// - get(cur) -> T -/// - copy ctor : duplicate reference to seek position -/// -/// Forward cursor -/// ============= -/// - copy ctor : true duplicate of seek position -/// -/// Bidirectional cursor -/// ==================== -/// - forget() : notes the current element as the new 'begin' point -/// - atbegin(cur) -> bool -/// - dec(cur) -/// -/// Random access cursor -/// ==================== -/// - skip(cur, n) -/// - position(cur) -> n -/// - size(cur) -> n -/// - truncate(n) : keep only n more elements -/// -/// As well, cursors must define the appropriate type/typedefs: -/// - cursor_category :: { onepass_cursor_tag, forward_cursor_tag, bidirectional_cursor_tag, random_access_cursor_tag } -/// - element_type -/// - reference_type : if writable, element_type& or such. else, == element_type -/// - - - - -namespace cpplinq { - - // used to identify cursor-based collections - struct collection_tag {}; - - struct onepass_cursor_tag {}; - struct forward_cursor_tag : onepass_cursor_tag {}; - struct bidirectional_cursor_tag : forward_cursor_tag {}; - struct random_access_cursor_tag : bidirectional_cursor_tag {}; - - struct noread_cursor_tag {}; // TODO: remove if not used - struct readonly_cursor_tag : noread_cursor_tag {}; - struct readwrite_cursor_tag : readonly_cursor_tag {}; - - - - // standard cursor adaptors - - namespace util - { - namespace detail - { - template <std::size_t n> struct type_to_size { char value[n]; }; - - type_to_size<1> get_category_from_iterator(std::input_iterator_tag); - type_to_size<2> get_category_from_iterator(std::forward_iterator_tag); - type_to_size<3> get_category_from_iterator(std::bidirectional_iterator_tag); - type_to_size<4> get_category_from_iterator(std::random_access_iterator_tag); - } - - template <std::size_t> - struct iter_to_cursor_category_; - - template <class Iter> - struct iter_to_cursor_category - { - static const std::size_t catIx = sizeof(detail::get_category_from_iterator(typename std::iterator_traits<Iter>::iterator_category()) /*.value*/ ); - typedef typename iter_to_cursor_category_<catIx>::type type; - }; - - template <> struct iter_to_cursor_category_<1> { typedef onepass_cursor_tag type; }; - template <> struct iter_to_cursor_category_<2> { typedef forward_cursor_tag type; }; - template <> struct iter_to_cursor_category_<3> { typedef bidirectional_cursor_tag type; }; - template <> struct iter_to_cursor_category_<4> { typedef random_access_cursor_tag type; }; - - - // Note: returns false if no partial order exists between two - // particular iterator categories, such as with some of the boost categories - template <class Cat1, class Cat2> - struct less_or_equal_cursor_category - { - private: - typedef char yes; - typedef struct { char c1,c2; } no; - static yes invoke(Cat1); - static no invoke(...); - public: - enum { value = (sizeof(invoke(Cat2())) == sizeof(yes)) }; - }; - - // Return the weaker of the two iterator categories. Make sure - // a non-standard category is in the second argument position, as - // this metafunction will default to the first value if the order is undefined - template <class Cat1, class Cat2, class Cat3 = void> - struct min_cursor_category : min_cursor_category<typename min_cursor_category<Cat1, Cat2>::type, Cat3> - { - }; - - template <class Cat1, class Cat2> - struct min_cursor_category<Cat1, Cat2> - : std::conditional< - less_or_equal_cursor_category<Cat2, Cat1>::value, - Cat2, - Cat1> - { - }; - - template <class Collection> - struct cursor_type { - typedef decltype(cursor(*static_cast<Collection*>(0))) type; - }; - } - - // simultaniously models a cursor and a cursor-collection - template <class Iterator> - class iter_cursor : collection_tag { - public: - - typedef iter_cursor cursor; - - typedef typename std::remove_reference<typename std::iterator_traits<Iterator>::value_type>::type - element_type; - typedef typename std::iterator_traits<Iterator>::reference - reference_type; - typedef typename util::iter_to_cursor_category<Iterator>::type - cursor_category; - - void forget() { start = current; } - bool empty() const { return current == fin; } - void inc() { - if (current == fin) - throw std::logic_error("inc past end"); - ++current; - } - typename std::iterator_traits<Iterator>::reference get() const { return *current; } - - bool atbegin() const { return current == start; } - void dec() { - if (current == start) - throw std::logic_error("dec past begin"); - --current; - } - - void skip(std::ptrdiff_t n) { current += n; } - std::size_t size() { return fin-start; } - void position() { return current-start; } - void truncate(std::size_t n) { - if (n > fin-current) { - fin = current + n; - } - } - - - iter_cursor(Iterator start, Iterator fin) - : current(start) - , start(start) - , fin(std::move(fin)) - { - } - - iter_cursor(Iterator start, Iterator fin, Iterator current) - : current(std::move(current)) - , start(std::move(start)) - , fin(std::move(fin)) - { - } - - iter_cursor get_cursor() const { return *this; } - - private: - Iterator current; - Iterator start, fin; - }; - - - template <class T> - struct cursor_interface - { - virtual bool empty() const = 0; - virtual void inc() = 0; - virtual cursor_interface* copy() const = 0; - - virtual T get() const = 0; - - virtual ~cursor_interface() {} - }; - - template <class T> - class dynamic_cursor : collection_tag - { - template <class Cur> - struct instance : cursor_interface<T> - { - Cur innerCursor; - - instance(Cur cursor) : innerCursor(std::move(cursor)) - { - } - virtual bool empty() const - { - return innerCursor.empty(); - } - virtual void inc() - { - innerCursor.inc(); - } - virtual T get() const - { - return innerCursor.get(); - } - virtual cursor_interface<T>* copy() const - { - return new instance(*this); - } - }; - - std::unique_ptr<cursor_interface<T>> myCur; - - public: - typedef forward_cursor_tag cursor_category; // TODO: not strictly true! - typedef typename std::remove_reference<T>::type element_type; - typedef T reference_type; - - dynamic_cursor() {} - - dynamic_cursor(const dynamic_cursor& other) - : myCur(other.myCur ? other.myCur->copy() : nullptr) - { - } - - dynamic_cursor(dynamic_cursor&& other) - : myCur(other.myCur.release()) - { - } - - template <class Cursor> - dynamic_cursor(Cursor cursor) - : myCur(new instance<Cursor>(std::move(cursor))) - { - } - - template <class Iterator> - dynamic_cursor(Iterator start, Iterator end) - { - *this = iter_cursor<Iterator>(start, end); - } - - bool empty() const { return !myCur || myCur->empty(); } - void inc() { myCur->inc(); } - T get() const { return myCur->get(); } - - dynamic_cursor& operator=(dynamic_cursor other) - { - std::swap(myCur, other.myCur); - return *this; - } - }; - - template <class T> - struct container_interface - { - virtual dynamic_cursor<T> get_cursor() const = 0; - }; - - template <class T> - class dynamic_collection - { - std::shared_ptr< container_interface<T> > container; - - template <class Container> - struct instance : container_interface<T> - { - Container c; - - instance(Container c) : c(c) - { - } - - dynamic_cursor<T> get_cursor() const - { - return c.get_cursor(); - } - }; - - public: - typedef dynamic_cursor<T> cursor; - - dynamic_collection() {} - - dynamic_collection(const dynamic_collection& other) - : container(other.container) - { - } - - // container or query - template <class Container> - dynamic_collection(Container c) - : container(new instance<Container>(c)) - { - } - - // container or query - template <class Iterator> - dynamic_collection(Iterator begin, Iterator end) - : container(new instance< iter_cursor<Iterator> >(iter_cursor<Iterator>(begin, end))) - { - } - - dynamic_cursor<T> get_cursor() const { - return container ? container->get_cursor() : dynamic_cursor<T>(); - } - }; -} - -#endif // !defined(CPPLINQ_LINQ_CURSOR_HPP diff --git a/Ix/CPP/src/cpplinq/linq_groupby.hpp b/Ix/CPP/src/cpplinq/linq_groupby.hpp deleted file mode 100644 index c521e5e..0000000 --- a/Ix/CPP/src/cpplinq/linq_groupby.hpp +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_GROUPBY_HPP) -#define CPPLINQ_LINQ_GROUPBY_HPP -#pragma once - -namespace cpplinq -{ - -template <class Iter, class Key> -struct group -{ - Key key; - Iter start; - Iter fin; - - typedef Iter iterator; - typedef Iter const_iterator; - - group(){} - - group(const Key& key) : key(key) - { - } - - Iter begin() const { return start; } - Iter end() const { return fin; } -}; - -struct default_equality -{ - template <class T> - bool operator()(const T& a, const T& b) const { - return a == b; - } -}; -struct default_less -{ - template<class T> - bool operator()(const T& a, const T& b) const { - return a < b; - } -}; - -// progressively constructs grouping as user iterates over groups and elements -// within each group. Performs this task by building a std::list of element -// iterators with equal elements within each group. -// -// invariants: -// - relative order of groups corresponds to relative order of each group's first -// element, as they appeared in the input sequence. -// - relative order of elements within a group correspond to relative order -// as they appeared in the input sequence. -// -// requires: -// Iter must be a forward iterator. -template <class Collection, class KeyFn, class Compare = default_less> -class linq_groupby -{ - typedef typename Collection::cursor - inner_cursor; - - typedef typename util::result_of<KeyFn(typename inner_cursor::element_type)>::type - key_type; - - typedef std::list<typename inner_cursor::element_type> - element_list_type; - - typedef group<typename element_list_type::iterator, key_type> - group_type; - - typedef std::list<group_type> - group_list_type; - -private: - struct impl_t - { - // TODO: would be faster to use a chunked list, where - // pointers are invalidated but iterators are not. Need - // benchmarks first - - element_list_type elements; - std::list<group_type> groups; - std::map<key_type, group_type*, Compare> groupIndex; - - - - KeyFn keySelector; - Compare comp; - - impl_t(inner_cursor cur, - KeyFn keySelector, - Compare comp = Compare()) - : keySelector(keySelector) - , groupIndex(comp) - { - // TODO: make lazy - insert_all(std::move(cur)); - } - - void insert_all(inner_cursor cur) - { - while(!cur.empty()) { - insert(cur.get()); - cur.inc(); - } - } - void insert(typename inner_cursor::reference_type element) - { - key_type key = keySelector(element); - auto groupPos = groupIndex.find(key); - if(groupPos == groupIndex.end()) { - // new group - bool firstGroup = groups.empty(); - - elements.push_back(element); - if(!firstGroup) { - // pop new element out of previous group - --groups.back().fin; - } - - // build new group - groups.push_back(group_type(key)); - group_type& newGroup = groups.back(); - - groupIndex.insert( std::make_pair(key, &newGroup) ); - - newGroup.fin = elements.end(); - --(newGroup.start = newGroup.fin); - } else { - // add to existing group at end - elements.insert(groupPos->second->end(), element); - } - } - }; - -public: - struct cursor { - typedef group_type - element_type; - - typedef element_type - reference_type; - - typedef forward_cursor_tag - cursor_category; - - cursor(inner_cursor cur, - KeyFn keyFn, - Compare comp = Compare()) - { - impl.reset(new impl_t(cur, keyFn, comp)); - inner = impl->groups.begin(); - fin = impl->groups.end(); - } - - void forget() { } // nop on forward-only cursors - bool empty() const { - return inner == fin; - } - void inc() { - if (inner == fin) { - throw std::logic_error("attempt to iterate past end of range"); - } - ++inner; - } - reference_type get() const { - return *inner; - } - - private: - std::shared_ptr<impl_t> impl; - typename std::list<group_type>::iterator inner; - typename std::list<group_type>::iterator fin; - }; - - linq_groupby(Collection c, - KeyFn keyFn, - Compare comp = Compare()) - : c(c), keyFn(keyFn), comp(comp) - { - } - - cursor get_cursor() const { return cursor(c.get_cursor(), keyFn, comp); } - -private: - Collection c; - KeyFn keyFn; - Compare comp; -}; - -} - -#endif // !defined(CPPLINQ_LINQ_GROUPBY_HPP) - diff --git a/Ix/CPP/src/cpplinq/linq_iterators.hpp b/Ix/CPP/src/cpplinq/linq_iterators.hpp deleted file mode 100644 index 3472281..0000000 --- a/Ix/CPP/src/cpplinq/linq_iterators.hpp +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_ITERATORS_HPP) -#define CPPLINQ_LINQ_ITERATORS_HPP -#pragma once - -#include <cstddef> - -namespace cpplinq { - - // if a member, provides the straightforward implementation of various redundant operators. For example, - // providing -> for any iterator providing *, and so forth. - struct use_default_iterator_operators {}; - - #define CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS \ - operator ::cpplinq::use_default_iterator_operators() const { return ::cpplinq::use_default_iterator_operators(); } - - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - Iter - >::type - operator+(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) { - return it += n; - } - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - Iter - >::type - operator-(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) { - return it -= n; - } - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - Iter - >::type - operator-=(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) { - return it += (-n); - } - - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - bool - >::type - operator!=(const Iter& it, const Iter& it2) { - return !(it == it2); - } - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - bool - >::type - operator>(const Iter& it, const Iter& it2) { - return it2 < it; - } - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - bool - >::type - operator<=(const Iter& it, const Iter& it2) { - return !(it2 < it); - } - template <class Iter> - typename std::enable_if< - std::is_convertible<Iter, use_default_iterator_operators>::value, - bool - >::type - operator>=(const Iter& it, const Iter& it2) { - return !(it < it2); - } - - namespace util { - template <class Iter, class T> - typename std::iterator_traits<Iter>::pointer deref_iterator(const Iter& it) { - return deref_iterator(it, util::identity<typename std::iterator_traits<Iter>::reference>()); - } - - template <class Iter, class T> - T* deref_iterator(const Iter& it, util::identity<T&>) { - return &*it; - } - - template <class Iter, class T> - util::value_ptr<T> deref_iterator(const Iter& it, util::identity<T>) { - return util::value_ptr<T>(*it); - } - } - - - template <class Iter> - class iter_range - { - Iter start, finish; - public: - - CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS - - typedef Iter iterator; - typedef typename iterator::value_type value_type; - - explicit iter_range(Iter start, Iter finish) : start(start), finish(finish) {} - iterator begin() const { return start; } - iterator end() const { return finish; } - }; - template <class Iter> - iter_range<Iter> make_range(Iter start, Iter finish) { - return iter_range<Iter>(start, finish); - } - - // decays into a onepass/forward iterator - template <class Cursor> - class cursor_iterator - : public std::iterator<std::forward_iterator_tag, - typename Cursor::element_type, - std::ptrdiff_t, - typename std::conditional<std::is_reference<typename Cursor::reference_type>::value, - typename std::add_pointer<typename Cursor::element_type>::type, - util::value_ptr<typename Cursor::element_type>>::type, - typename Cursor::reference_type> - { - public: - CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS; - - cursor_iterator(Cursor cur) : cur(cur) { - } - - cursor_iterator() : cur() { - } - - bool operator==(const cursor_iterator& other) const { - return !cur && !other.cur; - } - - typename Cursor::reference_type operator*() const { - return cur->get(); - } - - typename cursor_iterator::pointer operator->() const { - auto& v = **this; - return &v; - } - - cursor_iterator& operator++() { - cur->inc(); - - if (cur->empty()) { cur.reset(); } - return *this; - } - - cursor_iterator& operator+=(std::ptrdiff_t n) { - cur->skip(n); - - if (cur->empty()) { cur.reset(); } - return *this; - } - - - - private: - bool empty() const { - !cur || cur->empty(); - } - - util::maybe<Cursor> cur; - }; - - template <class Container> - class container_range - { - Container c; - - public: - typedef cursor_iterator<typename Container::cursor> iterator; - - container_range(Container c) : c(c) - { - } - - iterator begin() const - { - return iterator(c.get_cursor()); - } - - iterator end() const - { - return iterator(); - } - }; - -} - -#endif diff --git a/Ix/CPP/src/cpplinq/linq_last.hpp b/Ix/CPP/src/cpplinq/linq_last.hpp deleted file mode 100644 index cb2bf76..0000000 --- a/Ix/CPP/src/cpplinq/linq_last.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_LAST_HPP) -#define CPPLINQ_LINQ_LAST_HPP -#pragma once - -namespace cpplinq { - - template <class Cursor> - typename Cursor::element_type - linq_last_(Cursor c, onepass_cursor_tag) - { - if (c.empty()) { throw std::logic_error("last() out of bounds"); } - typename Cursor::element_type elem = c.get(); - for(;;) { - c.inc(); - if (c.empty()) break; - elem = c.get(); - } - return elem; - } - - // TODO: bidirectional iterator in constant time - - template <class Cursor> - typename Cursor::reference_type - linq_last_(Cursor c, forward_cursor_tag) - { - if (c.empty()) { throw std::logic_error("last() out of bounds"); } - Cursor best = c; - for(;;) { - c.inc(); - if (c.empty()) break; - best = c; - } - return best.get(); - } - - template <class Cursor> - typename Cursor::reference_type - linq_last_(Cursor c, random_access_cursor_tag) - { - if (c.empty()) { throw std::logic_error("last() out of bounds"); } - c.skip(c.size()-1); - return c.get(); - } - - template <class Cursor> - typename Cursor::element_type - linq_last_or_default_(Cursor c, onepass_cursor_tag) - { - typename Cursor::element_type elem; - while(!c.empty()) { - elem = c.get(); - c.inc(); - } - return elem; - } - - template <class Cursor> - typename Cursor::element_type - linq_last_or_default_(Cursor c, forward_cursor_tag) - { - if (c.empty()) { throw std::logic_error("last() out of bounds"); } - Cursor best = c; - for(;;) { - c.inc(); - if (c.empty()) break; - best = c; - } - return best.get(); - } - - template <class Cursor> - typename Cursor::element_type - linq_last_or_default_(Cursor c, random_access_cursor_tag) - { - if (c.empty()) { return typename Cursor::element_type(); } - c.skip(c.size()-1); - return c.get(); - } - -} - -#endif // CPPLINQ_LINQ_LAST_HPP diff --git a/Ix/CPP/src/cpplinq/linq_select.hpp b/Ix/CPP/src/cpplinq/linq_select.hpp deleted file mode 100644 index d505284..0000000 --- a/Ix/CPP/src/cpplinq/linq_select.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_SELECT_HPP) -#define CPPLINQ_LINQ_SELECT_HPP -#pragma once - -#include <cstddef> - -namespace cpplinq -{ - template <class Collection, class Selector> - class linq_select - { - typedef typename Collection::cursor - inner_cursor; - public: - struct cursor { - typedef typename util::result_of<Selector(typename inner_cursor::element_type)>::type - reference_type; - typedef typename std::remove_reference<reference_type>::type - element_type; - typedef typename inner_cursor::cursor_category - cursor_category; - - cursor(const inner_cursor& cur, Selector sel) : cur(cur), sel(std::move(sel)) {} - - void forget() { cur.forget(); } - bool empty() const { return cur.empty(); } - void inc() { cur.inc(); } - reference_type get() const { return sel(cur.get()); } - - bool atbegin() const { return cur.atbegin(); } - void dec() { cur.dec(); } - - void skip(std::size_t n) { cur.skip(n); } - std::size_t position() const { return cur.position(); } - std::size_t size() const { return cur.size(); } - private: - inner_cursor cur; - Selector sel; - }; - - linq_select(const Collection& c, Selector sel) : c(c), sel(sel) {} - - cursor get_cursor() const { return cursor(c.get_cursor(), sel); } - - private: - Collection c; - Selector sel; - }; - -} - -#endif // defined(CPPLINQ_LINQ_SELECT_HPP) diff --git a/Ix/CPP/src/cpplinq/linq_selectmany.hpp b/Ix/CPP/src/cpplinq/linq_selectmany.hpp deleted file mode 100644 index 85f0d42..0000000 --- a/Ix/CPP/src/cpplinq/linq_selectmany.hpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#pragma once - -#include "util.hpp" -#include "linq_cursor.hpp" - -#include <type_traits> - -namespace cpplinq -{ - namespace detail - { - struct default_select_many_selector - { - template <class T1, class T2> - auto operator()(T1&& t1, T2&& t2) const - -> decltype(std::forward<T2>(t2)) - { - return std::forward<T2>(t2); - } - }; - } - - namespace detail - { - template <typename Fn, typename Arg> - struct resolve_select_many_fn_return_type - { - typedef decltype(std::declval<Fn>()(std::declval<Arg>())) value; - }; - - template <typename TCol> - struct value_collection_adapter - { - value_collection_adapter(const TCol& col) - : _collection(col){} - - value_collection_adapter(const value_collection_adapter& src) - : _collection(src._collection) {} - - value_collection_adapter(value_collection_adapter && src) - : _collection(std::move(src._collection)) {} - - const TCol& get() const - { - return _collection; - } - - TCol& get() - { - return _collection; - } - - private: - TCol _collection; - }; - - template<typename TCol> - struct collection_store_type - { - typedef typename std::remove_reference<TCol>::type collection_type; - typedef std::reference_wrapper<collection_type> reference_store_type; - typedef value_collection_adapter<collection_type> value_store_type; - - typedef typename std::conditional<std::is_reference<TCol>::value, reference_store_type, value_store_type>::type store; - }; - } - - // cur<T> -> (T -> cur<element_type>) -> cur<element_type> - template <class Container1, class Fn, class Fn2> - class linq_select_many - { - template <class T> static T instance(); // for type inference - - Container1 c1; - Fn fn; - Fn2 fn2; - - typedef typename Container1::cursor Cur1; - typedef decltype(from(instance<Fn>()(instance<Cur1>().get()))) Container2; - typedef typename Container2::cursor Cur2; - - typedef typename detail::resolve_select_many_fn_return_type<Fn, typename Cur1::element_type>::value inner_collection; - - public: - class cursor - { - public: - typedef typename util::min_cursor_category<typename Cur1::cursor_category, - typename Cur2::cursor_category, - forward_cursor_tag>::type - cursor_category; - typedef typename Cur2::reference_type reference_type; - typedef typename Cur2::element_type element_type; - - typedef detail::collection_store_type<inner_collection> collection_store_type; - typedef typename collection_store_type::store collection_store; - typedef std::shared_ptr<collection_store> collection_store_ptr; - - private: - // TODO: we need to lazy eval somehow, but this feels wrong. - Cur1 cur1; - dynamic_cursor<reference_type> cur2; - Fn fn; - Fn2 fn2; - collection_store_ptr store; - - public: - cursor(Cur1 cur1, const Fn& fn, const Fn2& fn2) - : cur1(std::move(cur1)), fn(fn), fn2(fn2) - { - if (!cur1.empty()) - { - store = std::make_shared<collection_store>(fn(cur1.get())); - cur2 = from(store->get()).get_cursor(); - } - } - - bool empty() const - { - return cur2.empty(); - } - - void inc() - { - cur2.inc(); - thunk(); - } - - reference_type get() const - { - return fn2(cur1.get(), cur2.get()); - } - - private: - void thunk() - { - // refill cur2 - while (cur2.empty() && !cur1.empty()) { - cur1.inc(); - if (cur1.empty()) - break; - - store = std::make_shared<collection_store>(fn(cur1.get())); - cur2 = from(store->get()).get_cursor(); - } - } - }; - - linq_select_many(Container1 c1, Fn fn, Fn2 fn2) - : c1(std::move(c1)), fn(std::move(fn)), fn2(std::move(fn2)) - { - } - - cursor get_cursor() const - { - return cursor(c1.get_cursor(), fn, fn2); - } - }; -} - - - diff --git a/Ix/CPP/src/cpplinq/linq_skip.hpp b/Ix/CPP/src/cpplinq/linq_skip.hpp deleted file mode 100644 index 5b1624f..0000000 --- a/Ix/CPP/src/cpplinq/linq_skip.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_SKIP_HPP) -#define CPPLINQ_LINQ_SKIP_HPP -#pragma once - -#include <cstddef> - -namespace cpplinq -{ - template <class Collection> - struct linq_skip - { - public: - typedef typename Collection::cursor cursor; - - linq_skip(const Collection& c, std::size_t n) : c(c), n(n) {} - - cursor get_cursor() const { - std::size_t rem = n; - - auto cur = c.get_cursor(); - while(rem-- && !cur.empty()) { - cur.inc(); - } - cur.forget(); - return cur; - } - - private: - Collection c; - std::size_t n; - }; -} -#endif // !defined(CPPLINQ_LINQ_SKIP_HPP) - - diff --git a/Ix/CPP/src/cpplinq/linq_take.hpp b/Ix/CPP/src/cpplinq/linq_take.hpp deleted file mode 100644 index a7093ef..0000000 --- a/Ix/CPP/src/cpplinq/linq_take.hpp +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_TAKE_HPP) -#define CPPLINQ_LINQ_TAKE_HPP -#pragma once - -#include <cstddef> - -namespace cpplinq -{ - template <class InnerCursor> - struct linq_take_cursor - { - typedef typename InnerCursor::element_type element_type; - typedef typename InnerCursor::reference_type reference_type; - typedef typename InnerCursor::cursor_category cursor_category; - - linq_take_cursor(const InnerCursor& cur, std::size_t rem) : cur(cur), rem(rem) {} - - void forget() { cur.forget(); } - bool empty() const { return cur.empty() || rem == 0; } - void inc() { cur.inc(); --rem; } - reference_type get() const { return cur.get(); } - - bool atbegin() const { return cur.atbegin(); } - void dec() { cur.dec(); --rem; } - - void skip(std::size_t n) { cur.skip(n); rem -= n; } - std::size_t position() const { return cur.position(); } - std::size_t size() const { return cur.size(); } - - private: - InnerCursor cur; - std::size_t rem; - }; - - namespace detail { - template <class Collection> - linq_take_cursor<typename Collection::cursor> - take_get_cursor_( - const Collection& c, - std::size_t n, - onepass_cursor_tag - ) - { - return linq_take_cursor<typename Collection::cursor>(c.get_cursor(), n); - } - - template <class Collection> - typename Collection::cursor - take_get_cursor_( - const Collection& c, - std::size_t n, - random_access_cursor_tag - ) - { - auto cur = c.get_cursor(); - if (cur.size() > n) { - cur.truncate(n); - } - return cur; - } - } - - template <class Collection> - struct linq_take - { - typedef typename std::conditional< - util::less_or_equal_cursor_category< - random_access_cursor_tag, - typename Collection::cursor::cursor_category>::value, - typename Collection::cursor, - linq_take_cursor<typename Collection::cursor>>::type - cursor; - - linq_take(const Collection& c, std::size_t n) : c(c), n(n) {} - - cursor get_cursor() const { - return detail::take_get_cursor_(c, n, typename Collection::cursor::cursor_category()); - } - - Collection c; - std::size_t n; - }; - - template <class Collection> - auto get_cursor( - const linq_take<Collection>& take - ) - -> decltype(get_cursor_(take, typename Collection::cursor::cursor_category())) - { - return get_cursor_(take, typename Collection::cursor::cursor_category()); - } - - -} -#endif // !defined(CPPLINQ_LINQ_TAKE_HPP) - diff --git a/Ix/CPP/src/cpplinq/linq_where.hpp b/Ix/CPP/src/cpplinq/linq_where.hpp deleted file mode 100644 index 9b3d936..0000000 --- a/Ix/CPP/src/cpplinq/linq_where.hpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_WHERE_HPP) -#define CPPLINQ_LINQ_WHERE_HPP -#pragma once - -namespace cpplinq -{ - template <class Collection, class Predicate> - class linq_where - { - typedef typename Collection::cursor - inner_cursor; - public: - struct cursor { - typedef typename util::min_iterator_category< - bidirectional_cursor_tag, - typename inner_cursor::cursor_category>::type - cursor_category; - typedef typename inner_cursor::element_type - element_type; - typedef typename inner_cursor::reference_type - reference_type; - - cursor(const inner_cursor& cur, const Predicate& p) : cur(cur), pred(p) - { - if (!cur.empty() && !pred(cur.get())) { - this->inc(); - } - } - - void forget() { cur.forget(); } - bool empty() const { return cur.empty(); } - void inc() { - for (;;) { - cur.inc(); - if (cur.empty() || pred(cur.get())) break; - } - } - reference_type get() const { - return cur.get(); - } - - bool atbegin() const { return atbegin(cur); } - void dec() { - for (;;) { - cur.dec(); - if (pred(cur.get())) break; - } - } - private: - inner_cursor cur; - Predicate pred; - }; - - linq_where(const Collection& c, Predicate pred) : c(c), pred(pred) {} - - cursor get_cursor() const { - return cursor(c.get_cursor(), pred); - } - - private: - Collection c; - Predicate pred; - }; -} - -#endif // !defined(CPPLINQ_LINQ_WHERE_HPP) - diff --git a/Ix/CPP/src/cpplinq/util.hpp b/Ix/CPP/src/cpplinq/util.hpp deleted file mode 100644 index ee3d7eb..0000000 --- a/Ix/CPP/src/cpplinq/util.hpp +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -#if !defined(CPPLINQ_LINQ_UTIL_HPP) -#define CPPLINQ_LINQ_UTIL_HPP -#pragma once - -namespace cpplinq { namespace util { - - template <class Container> - struct container_traits { - typedef typename Container::iterator iterator; - typedef typename std::iterator_traits<iterator>::value_type value_type; - typedef typename std::iterator_traits<iterator>::iterator_category iterator_category; - - // TODO: conservative definition for now. - enum { is_writable_iterator = - std::is_reference<typename std::iterator_traits<iterator>::reference>::value - && std::is_same<typename std::remove_cv<value_type>::type, - typename std::remove_cv<typename std::remove_reference<typename std::iterator_traits<iterator>::reference>::type>::type>::value - }; - }; - - template <> - struct container_traits<int>; - - template <class Container> - struct container_traits<Container&> - : container_traits<Container> - {}; - template <class Container> - struct container_traits<const Container> - : container_traits<Container> - { - typedef typename Container::const_iterator iterator; - }; - - // Note: returns false if no partial order exists between two - // particular iterator categories, such as with some of the boost categories - template <class Cat1, class Cat2> - struct less_or_equal_iterator_category - { - private: - typedef char yes; - typedef struct { char c1,c2; } no; - static yes invoke(Cat1); - static no invoke(...); - public: - enum { value = (sizeof(invoke(Cat2())) == sizeof(yes)) }; - }; - - // Return the weaker of the two iterator categories. Make sure - // a non-standard category is in the second argument position, as - // this metafunction will default to the first value if the order is undefined - template <class Cat1, class Cat2> - struct min_iterator_category - : std::conditional< - less_or_equal_iterator_category<Cat2, Cat1>::value, - Cat2, - Cat1> - { - }; - -#if 0 -#define CppLinq_GET_ITERATOR_TYPE(TContainer) \ - decltype(begin(static_cast<TContainer*>(0))) -#define CppLinq_GET_CONST_ITERATOR_TYPE(TContainer) \ - decltype(begin(static_cast<const TContainer*>(0))) -#else -#define CppLinq_GET_ITERATOR_TYPE(TContainer) \ - typename ::cpplinq::util::container_traits<TContainer>::iterator -#define CppLinq_GET_CONST_ITERATOR_TYPE(TContainer) \ - typename ::cpplinq::util::container_traits<TContainer>::const_iterator -#endif - - // VC10's std::tr1::result_of is busted with lambdas. use decltype instead on vc10 and later -#if defined(_MSC_VER) && _MSC_VER >= 1600 - namespace detail { - template <class T> T instance(); - }; - template <class Fn> struct result_of; - template <class Fn> - struct result_of<Fn()> { - typedef decltype(detail::instance<Fn>()()) type; - }; - template <class Fn, class A0> - struct result_of<Fn(A0)> { - typedef decltype(detail::instance<Fn>()(detail::instance<A0>())) type; - }; - template <class Fn, class A0, class A1> - struct result_of<Fn(A0,A1)> { - typedef decltype(detail::instance<Fn>()(detail::instance<A0>(), - detail::instance<A1>())) type; - }; - template <class Fn, class A0, class A1, class A2> - struct result_of<Fn(A0,A1,A2)> { - typedef decltype(detail::instance<Fn>()(detail::instance<A0>(), - detail::instance<A1>(), - detail::instance<A2>())) type; - }; - template <class Fn, class A0, class A1, class A2, class A3> - struct result_of<Fn(A0,A1,A2,A3)> { - typedef decltype(detail::instance<Fn>()(detail::instance<A0>(), - detail::instance<A1>(), - detail::instance<A2>(), - detail::instance<A3>())) type; - }; -#elif defined(_MSC_VER) - template <class T> - struct result_of<T> : std::tr1::result_of<T> {}; -#else - using std::result_of; -#endif - - template<class Type> - struct identity - { - typedef Type type; - Type operator()(const Type& left) const {return left;} - }; - - // faux pointer proxy for iterators that dereference to a value rather than reference, such as selectors - template <class T> - struct value_ptr - { - T value; - value_ptr(const T& value) : value(value) - {} - value_ptr(const T* pvalue) : value(*pvalue) - {} - const T* operator->() - { - return &value; - } - }; - - - template <class T> - class maybe - { - bool is_set; - typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type - storage; - public: - maybe() - : is_set(false) - { - } - - maybe(T value) - : is_set(false) - { - new (reinterpret_cast<T*>(&storage)) T(value); - is_set = true; - } - - maybe(const maybe& other) - : is_set(false) - { - if (other.is_set) { - new (reinterpret_cast<T*>(&storage)) T(*other.get()); - is_set = true; - } - } - maybe(maybe&& other) - : is_set(false) - { - if (other.is_set) { - new (reinterpret_cast<T*>(&storage)) T(std::move(*other.get())); - is_set = true; - other.reset(); - } - } - - ~maybe() - { - reset(); - } - - void reset() - { - if (is_set) { - is_set = false; - reinterpret_cast<T*>(&storage)->~T(); - } - } - - T* get() { - return is_set ? reinterpret_cast<T*>(&storage) : 0; - } - - const T* get() const { - return is_set ? reinterpret_cast<const T*>(&storage) : 0; - } - - void set(T value) { - if (is_set) { - *reinterpret_cast<T*>(&storage) = std::move(value); - } else { - new (reinterpret_cast<T*>(&storage)) T(std::move(value)); - is_set = true; - } - } - - T& operator*() { return *get(); } - const T& operator*() const { return *get(); } - T* operator->() { return get(); } - const T* operator->() const { return get(); } - - maybe& operator=(const T& other) { - set(other); - } - maybe& operator=(const maybe& other) { - if (const T* pother = other.get()) { - set(*pother); - } else { - reset(); - } - return *this; - } - - // boolean-like operators - operator T*() { return get(); } - operator const T*() const { return get(); } - - private: - - }; -}} - - -#endif //CPPLINQ_UTIL_HPP - |