• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
operator ()cpplinq::util::identity118         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;
value_ptrcpplinq::util::value_ptr126         value_ptr(const T& value) : value(value)
127         {}
value_ptrcpplinq::util::value_ptr128         value_ptr(const T* pvalue) : value(*pvalue)
129         {}
operator ->cpplinq::util::value_ptr130         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:
maybe()144         maybe()
145         : is_set(false)
146         {
147         }
148 
maybe(T value)149         maybe(T value)
150         : is_set(false)
151         {
152             new (reinterpret_cast<T*>(&storage)) T(value);
153             is_set = true;
154         }
155 
maybe(const maybe & other)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         }
maybe(maybe && other)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 
~maybe()174         ~maybe()
175         {
176             reset();
177         }
178 
reset()179         void reset()
180         {
181             if (is_set) {
182                 is_set = false;
183                 reinterpret_cast<T*>(&storage)->~T();
184             }
185         }
186 
get()187         T* get() {
188             return is_set ? reinterpret_cast<T*>(&storage) : 0;
189         }
190 
get() const191         const T* get() const {
192             return is_set ? reinterpret_cast<const T*>(&storage) : 0;
193         }
194 
set(T value)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 
operator *()204         T& operator*() { return *get(); }
operator *() const205         const T& operator*() const { return *get(); }
operator ->()206         T* operator->() { return get(); }
operator ->() const207         const T* operator->() const { return get(); }
208 
operator =(const T & other)209         maybe& operator=(const T& other) {
210             set(other);
211         }
operator =(const maybe & other)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
operator T*()222         operator T*() { return get(); }
operator const T*() const223         operator const T*() const { return get(); }
224 
225     private:
226 
227     };
228 }}
229 
230 
231 #endif //CPPLINQ_UTIL_HPP
232 
233