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