summaryrefslogtreecommitdiff
path: root/Ix/CPP/src
diff options
context:
space:
mode:
authorScott Blomquist <sblom@microsoft.com>2013-01-17 17:48:09 -0800
committerScott Blomquist <sblom@microsoft.com>2013-01-17 17:48:09 -0800
commita0f2bbe9acce9483163de730341cf89ec0331d2b (patch)
treead38c78a7f0e916051edce90374586961dcdfee4 /Ix/CPP/src
parent6aa4590ea5952d3ba5e1f99b6ede76d856f88617 (diff)
downloadRxCpp-a0f2bbe9acce9483163de730341cf89ec0331d2b.tar.gz
New directory structure.
Diffstat (limited to 'Ix/CPP/src')
-rw-r--r--Ix/CPP/src/cpplinq/linq.hpp531
-rw-r--r--Ix/CPP/src/cpplinq/linq_cursor.hpp340
-rw-r--r--Ix/CPP/src/cpplinq/linq_groupby.hpp195
-rw-r--r--Ix/CPP/src/cpplinq/linq_iterators.hpp194
-rw-r--r--Ix/CPP/src/cpplinq/linq_last.hpp85
-rw-r--r--Ix/CPP/src/cpplinq/linq_select.hpp52
-rw-r--r--Ix/CPP/src/cpplinq/linq_selectmany.hpp107
-rw-r--r--Ix/CPP/src/cpplinq/linq_skip.hpp35
-rw-r--r--Ix/CPP/src/cpplinq/linq_take.hpp96
-rw-r--r--Ix/CPP/src/cpplinq/linq_where.hpp69
-rw-r--r--Ix/CPP/src/cpplinq/util.hpp223
11 files changed, 1927 insertions, 0 deletions
diff --git a/Ix/CPP/src/cpplinq/linq.hpp b/Ix/CPP/src/cpplinq/linq.hpp
new file mode 100644
index 0000000..1070331
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq.hpp
@@ -0,0 +1,531 @@
+// 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: 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
+
+#include <functional>
+#include <iterator>
+#include <list>
+#include <map>
+#include <memory>
+#include <utility>
+#include <type_traits>
+#include <vector>
+
+
+
+// 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
+
+
+// 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 typename 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 { return !empty(cur); }
+
+ 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
+
+ template <class U>
+ auto cast()
+ -> decltype(static_cast<linq_driver*>(0)->select(detail::cast_to<U>()))
+ {
+ return this->select(detail::cast_to<U>());
+ }
+
+ // TODO: concat
+
+ bool contains(const typename Collection::cursor::element_type& value) const {
+ return std::find(begin(), end(), value) != end();
+ }
+
+ typename std::iterator_traits<iterator>::distance_type count() const {
+ return std::distance(begin(), end());
+ }
+
+ template <class Predicate>
+ typename std::iterator_traits<iterator>::distance_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(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(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(size_t n) const {
+ return linq_skip<Collection>(c, n);
+ }
+
+ // TODO: skip_while(pred)
+
+ // TODO: sum
+
+ linq_driver<linq_take<Collection>> take(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());
+ }
+
+ // -------------------- 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[](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>(begin(c), end(c));
+ return std::move(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);
+}
+
+}
+
+#endif // defined(CPPLINQ_LINQ_HPP)
+
diff --git a/Ix/CPP/src/cpplinq/linq_cursor.hpp b/Ix/CPP/src/cpplinq/linq_cursor.hpp
new file mode 100644
index 0000000..827c488
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_cursor.hpp
@@ -0,0 +1,340 @@
+// 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
+
+/// 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 <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 <size_t>
+ struct iter_to_cursor_category_;
+
+ template <class Iter>
+ struct iter_to_cursor_category
+ {
+ static const 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(ptrdiff_t n) { current += n; }
+ size_t size() { return fin-start; }
+ void position() { return current-start; }
+ void truncate(size_t n) {
+ if (n > fin-current) {
+ fin = current + n;
+ }
+ }
+
+
+ iter_cursor(Iterator start, Iterator fin)
+ : start(start)
+ , fin(std::move(fin))
+ , current(start)
+ {
+ }
+
+ iter_cursor(Iterator start, Iterator fin, Iterator current)
+ : start(std::move(start))
+ , fin(std::move(fin))
+ , current(std::move(current))
+ {
+ }
+
+ 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
new file mode 100644
index 0000000..c521e5e
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_groupby.hpp
@@ -0,0 +1,195 @@
+// 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
new file mode 100644
index 0000000..ed267ec
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_iterators.hpp
@@ -0,0 +1,194 @@
+// 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
+
+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 detail::deref_iterator(it, std::identity<typename std::iterator_traits<Iter>::reference>());
+ }
+
+ template <class Iter, class T>
+ T* deref_iterator(const Iter& it, std::identity<T&>) {
+ return &*it;
+ }
+
+ template <class Iter, class T>
+ util::value_ptr<T> deref_iterator(const Iter& it, std::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,
+ 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();
+ }
+
+ pointer operator->() const {
+ auto& v = **this;
+ return &v;
+ }
+
+ cursor_iterator& operator++() {
+ cur->inc();
+
+ if (cur->empty()) { cur.reset(); }
+ return *this;
+ }
+
+ cursor_iterator& operator+=(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
new file mode 100644
index 0000000..fd08823
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_last.hpp
@@ -0,0 +1,85 @@
+// 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 std::move(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 std::move(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
new file mode 100644
index 0000000..650a1dc
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_select.hpp
@@ -0,0 +1,52 @@
+// 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
+
+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(size_t n) { cur.skip(n); }
+ size_t position() const { return cur.position(); }
+ 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
new file mode 100644
index 0000000..45f0574
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_selectmany.hpp
@@ -0,0 +1,107 @@
+// 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"
+
+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);
+ }
+ };
+ }
+
+ // 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;
+
+ 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;
+
+ private:
+ // TODO: we need to lazy eval somehow, but this feels wrong.
+ Cur1 cur1;
+ dynamic_cursor<reference_type> cur2;
+ Fn fn;
+ Fn2 fn2;
+
+ public:
+ cursor(Cur1 cur1, const Fn& fn, const Fn2& fn2)
+ : cur1(std::move(cur1)), fn(fn), fn2(fn2)
+ {
+ auto container2 = fn(cur1.get());
+ cur2 = from(container2).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;
+
+ auto container2 = fn(cur1.get());
+ cur2 = from(container2).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
new file mode 100644
index 0000000..422592a
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_skip.hpp
@@ -0,0 +1,35 @@
+// 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
+
+namespace cpplinq
+{
+ template <class Collection>
+ struct linq_skip
+ {
+ public:
+ typedef typename Collection::cursor cursor;
+
+ linq_skip(const Collection& c, size_t n) : c(c), n(n) {}
+
+ cursor get_cursor() const {
+ size_t rem = n;
+
+ auto cur = c.get_cursor();
+ while(rem-- && !cur.empty()) {
+ cur.inc();
+ }
+ cur.forget();
+ return std::move(cur);
+ }
+
+ private:
+ Collection c;
+ 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
new file mode 100644
index 0000000..63f7449
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_take.hpp
@@ -0,0 +1,96 @@
+// 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
+
+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, 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(size_t n) { cur.skip(n); rem -= n; }
+ size_t position() const { return cur.position(); }
+ size_t size() const { return cur.size(); }
+
+ private:
+ InnerCursor cur;
+ size_t rem;
+ };
+
+ namespace detail {
+ template <class Collection>
+ linq_take_cursor<typename Collection::cursor>
+ take_get_cursor_(
+ const Collection& c,
+ 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,
+ size_t n,
+ random_access_cursor_tag
+ )
+ {
+ auto cur = c.get_cursor();
+ if (cur.size() > n) {
+ cur.truncate(n);
+ }
+ return std::move(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, 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;
+ 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
new file mode 100644
index 0000000..4f66ba7
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/linq_where.hpp
@@ -0,0 +1,69 @@
+// 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 (!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
new file mode 100644
index 0000000..6fb62ff
--- /dev/null
+++ b/Ix/CPP/src/cpplinq/util.hpp
@@ -0,0 +1,223 @@
+// 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;
+ };
+#else
+ template <class T>
+ struct result_of<T> : std::tr1::result_of<T> {};
+#endif
+
+ // 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& pvalue) : 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(const T& value) {
+ if (is_set) {
+ *reinterpret_cast<T*>(&storage) = value;
+ } else {
+ new (reinterpret_cast<T*>(&storage)) T(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
+