233 lines
7.0 KiB
C++
233 lines
7.0 KiB
C++
|
// 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
|
||
|
|