feat add rxcpp
This commit is contained in:
584
3party/cpplinq/linq.hpp
Normal file
584
3party/cpplinq/linq.hpp
Normal file
@ -0,0 +1,584 @@
|
||||
// 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)
|
||||
|
342
3party/cpplinq/linq_cursor.hpp
Normal file
342
3party/cpplinq/linq_cursor.hpp
Normal file
@ -0,0 +1,342 @@
|
||||
// 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
|
195
3party/cpplinq/linq_groupby.hpp
Normal file
195
3party/cpplinq/linq_groupby.hpp
Normal file
@ -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)
|
||||
|
196
3party/cpplinq/linq_iterators.hpp
Normal file
196
3party/cpplinq/linq_iterators.hpp
Normal file
@ -0,0 +1,196 @@
|
||||
// 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
|
85
3party/cpplinq/linq_last.hpp
Normal file
85
3party/cpplinq/linq_last.hpp
Normal file
@ -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 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
|
54
3party/cpplinq/linq_select.hpp
Normal file
54
3party/cpplinq/linq_select.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
// 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)
|
164
3party/cpplinq/linq_selectmany.hpp
Normal file
164
3party/cpplinq/linq_selectmany.hpp
Normal file
@ -0,0 +1,164 @@
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
37
3party/cpplinq/linq_skip.hpp
Normal file
37
3party/cpplinq/linq_skip.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
// 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)
|
||||
|
||||
|
98
3party/cpplinq/linq_take.hpp
Normal file
98
3party/cpplinq/linq_take.hpp
Normal file
@ -0,0 +1,98 @@
|
||||
// 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)
|
||||
|
69
3party/cpplinq/linq_where.hpp
Normal file
69
3party/cpplinq/linq_where.hpp
Normal file
@ -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 (!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)
|
||||
|
232
3party/cpplinq/util.hpp
Normal file
232
3party/cpplinq/util.hpp
Normal file
@ -0,0 +1,232 @@
|
||||
// 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
|
||||
|
Reference in New Issue
Block a user