Home | History | Annotate | Download | only in cpplinq
      1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
      2 
      3 #if !defined(CPPLINQ_LINQ_UTIL_HPP)
      4 #define CPPLINQ_LINQ_UTIL_HPP
      5 #pragma once
      6 
      7 namespace cpplinq { namespace util {
      8 
      9     template <class Container>
     10     struct container_traits {
     11         typedef typename Container::iterator iterator;
     12         typedef typename std::iterator_traits<iterator>::value_type value_type;
     13         typedef typename std::iterator_traits<iterator>::iterator_category iterator_category;
     14 
     15         // TODO: conservative definition for now.
     16         enum { is_writable_iterator =
     17                    std::is_reference<typename std::iterator_traits<iterator>::reference>::value
     18                    && std::is_same<typename std::remove_cv<value_type>::type,
     19                                    typename std::remove_cv<typename std::remove_reference<typename std::iterator_traits<iterator>::reference>::type>::type>::value
     20         };
     21     };
     22 
     23     template <>
     24     struct container_traits<int>;
     25 
     26     template <class Container>
     27     struct container_traits<Container&>
     28         : container_traits<Container>
     29     {};
     30     template <class Container>
     31     struct container_traits<const Container>
     32         : container_traits<Container>
     33     {
     34         typedef typename Container::const_iterator iterator;
     35     };
     36 
     37     // Note: returns false if no partial order exists between two
     38     // particular iterator categories, such as with some of the boost categories
     39     template <class Cat1, class Cat2>
     40     struct less_or_equal_iterator_category
     41     {
     42     private:
     43         typedef char yes;
     44         typedef struct { char c1,c2; } no;
     45         static yes invoke(Cat1);
     46         static no invoke(...);
     47     public:
     48         enum { value = (sizeof(invoke(Cat2())) == sizeof(yes)) };
     49     };
     50 
     51     // Return the weaker of the two iterator categories. Make sure
     52     //   a non-standard category is in the second argument position, as
     53     //   this metafunction will default to the first value if the order is undefined
     54     template <class Cat1, class Cat2>
     55     struct min_iterator_category
     56         : std::conditional<
     57             less_or_equal_iterator_category<Cat2, Cat1>::value,
     58             Cat2,
     59             Cat1>
     60     {
     61     };
     62 
     63 #if 0
     64 #define CppLinq_GET_ITERATOR_TYPE(TContainer) \
     65     decltype(begin(static_cast<TContainer*>(0)))
     66 #define CppLinq_GET_CONST_ITERATOR_TYPE(TContainer) \
     67     decltype(begin(static_cast<const TContainer*>(0)))
     68 #else
     69 #define CppLinq_GET_ITERATOR_TYPE(TContainer) \
     70     typename ::cpplinq::util::container_traits<TContainer>::iterator
     71 #define CppLinq_GET_CONST_ITERATOR_TYPE(TContainer) \
     72     typename ::cpplinq::util::container_traits<TContainer>::const_iterator
     73 #endif
     74 
     75     // VC10's std::tr1::result_of is busted with lambdas. use decltype instead on vc10 and later
     76 #if defined(_MSC_VER) && _MSC_VER >= 1600
     77     namespace detail {
     78         template <class T> T instance();
     79     };
     80     template <class Fn> struct result_of;
     81     template <class Fn>
     82     struct result_of<Fn()> {
     83         typedef decltype(detail::instance<Fn>()()) type;
     84     };
     85     template <class Fn, class A0>
     86     struct result_of<Fn(A0)> {
     87         typedef decltype(detail::instance<Fn>()(detail::instance<A0>())) type;
     88     };
     89     template <class Fn, class A0, class A1>
     90     struct result_of<Fn(A0,A1)> {
     91         typedef decltype(detail::instance<Fn>()(detail::instance<A0>(),
     92                                                 detail::instance<A1>())) type;
     93     };
     94     template <class Fn, class A0, class A1, class A2>
     95     struct result_of<Fn(A0,A1,A2)> {
     96         typedef decltype(detail::instance<Fn>()(detail::instance<A0>(),
     97                                                 detail::instance<A1>(),
     98                                                 detail::instance<A2>())) type;
     99     };
    100     template <class Fn, class A0, class A1, class A2, class A3>
    101     struct result_of<Fn(A0,A1,A2,A3)> {
    102         typedef decltype(detail::instance<Fn>()(detail::instance<A0>(),
    103                                                 detail::instance<A1>(),
    104                                                 detail::instance<A2>(),
    105                                                 detail::instance<A3>())) type;
    106     };
    107 #elif defined(_MSC_VER)
    108     template <class T>
    109     struct result_of<T> : std::tr1::result_of<T> {};
    110 #else
    111     using std::result_of;
    112 #endif
    113 
    114     template<class Type>
    115     struct identity
    116     {
    117         typedef Type type;
    118         Type operator()(const Type& left) const {return left;}
    119     };
    120 
    121     // faux pointer proxy for iterators that dereference to a value rather than reference, such as selectors
    122     template <class T>
    123     struct value_ptr
    124     {
    125         T value;
    126         value_ptr(const T& value) : value(value)
    127         {}
    128         value_ptr(const T* pvalue) : value(*pvalue)
    129         {}
    130         const T* operator->()
    131         {
    132             return &value;
    133         }
    134     };
    135 
    136 
    137     template <class T>
    138     class maybe
    139     {
    140         bool is_set;
    141         typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type
    142             storage;
    143     public:
    144         maybe()
    145         : is_set(false)
    146         {
    147         }
    148 
    149         maybe(T value)
    150         : is_set(false)
    151         {
    152             new (reinterpret_cast<T*>(&storage)) T(value);
    153             is_set = true;
    154         }
    155 
    156         maybe(const maybe& other)
    157         : is_set(false)
    158         {
    159             if (other.is_set) {
    160                 new (reinterpret_cast<T*>(&storage)) T(*other.get());
    161                 is_set = true;
    162             }
    163         }
    164         maybe(maybe&& other)
    165         : is_set(false)
    166         {
    167             if (other.is_set) {
    168                 new (reinterpret_cast<T*>(&storage)) T(std::move(*other.get()));
    169                 is_set = true;
    170                 other.reset();
    171             }
    172         }
    173 
    174         ~maybe()
    175         {
    176             reset();
    177         }
    178 
    179         void reset()
    180         {
    181             if (is_set) {
    182                 is_set = false;
    183                 reinterpret_cast<T*>(&storage)->~T();
    184             }
    185         }
    186 
    187         T* get() {
    188             return is_set ? reinterpret_cast<T*>(&storage) : 0;
    189         }
    190 
    191         const T* get() const {
    192             return is_set ? reinterpret_cast<const T*>(&storage) : 0;
    193         }
    194 
    195         void set(T value) {
    196             if (is_set) {
    197                 *reinterpret_cast<T*>(&storage) = std::move(value);
    198             } else {
    199                 new (reinterpret_cast<T*>(&storage)) T(std::move(value));
    200                 is_set = true;
    201             }
    202         }
    203 
    204         T& operator*() { return *get(); }
    205         const T& operator*() const { return *get(); }
    206         T* operator->() { return get(); }
    207         const T* operator->() const { return get(); }
    208 
    209         maybe& operator=(const T& other) {
    210             set(other);
    211         }
    212         maybe& operator=(const maybe& other) {
    213             if (const T* pother = other.get()) {
    214                 set(*pother);
    215             } else {
    216                 reset();
    217             }
    218             return *this;
    219         }
    220 
    221         // boolean-like operators
    222         operator T*() { return get(); }
    223         operator const T*() const { return get(); }
    224 
    225     private:
    226 
    227     };
    228 }}
    229 
    230 
    231 #endif //CPPLINQ_UTIL_HPP
    232 
    233