// 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 struct container_traits { typedef typename Container::iterator iterator; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::iterator_category iterator_category; // TODO: conservative definition for now. enum { is_writable_iterator = std::is_reference::reference>::value && std::is_same::type, typename std::remove_cv::reference>::type>::type>::value }; }; template <> struct container_traits; template struct container_traits : container_traits {}; template struct container_traits : container_traits { 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 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 struct min_iterator_category : std::conditional< less_or_equal_iterator_category::value, Cat2, Cat1> { }; #if 0 #define CppLinq_GET_ITERATOR_TYPE(TContainer) \ decltype(begin(static_cast(0))) #define CppLinq_GET_CONST_ITERATOR_TYPE(TContainer) \ decltype(begin(static_cast(0))) #else #define CppLinq_GET_ITERATOR_TYPE(TContainer) \ typename ::cpplinq::util::container_traits::iterator #define CppLinq_GET_CONST_ITERATOR_TYPE(TContainer) \ typename ::cpplinq::util::container_traits::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 T instance(); }; template struct result_of; template struct result_of { typedef decltype(detail::instance()()) type; }; template struct result_of { typedef decltype(detail::instance()(detail::instance())) type; }; template struct result_of { typedef decltype(detail::instance()(detail::instance(), detail::instance())) type; }; template struct result_of { typedef decltype(detail::instance()(detail::instance(), detail::instance(), detail::instance())) type; }; template struct result_of { typedef decltype(detail::instance()(detail::instance(), detail::instance(), detail::instance(), detail::instance())) type; }; #elif defined(_MSC_VER) template struct result_of : std::tr1::result_of {}; #else using std::result_of; #endif template 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 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 maybe { bool is_set; typename std::aligned_storage::value>::type storage; public: maybe() : is_set(false) { } maybe(T value) : is_set(false) { new (reinterpret_cast(&storage)) T(value); is_set = true; } maybe(const maybe& other) : is_set(false) { if (other.is_set) { new (reinterpret_cast(&storage)) T(*other.get()); is_set = true; } } maybe(maybe&& other) : is_set(false) { if (other.is_set) { new (reinterpret_cast(&storage)) T(std::move(*other.get())); is_set = true; other.reset(); } } ~maybe() { reset(); } void reset() { if (is_set) { is_set = false; reinterpret_cast(&storage)->~T(); } } T* get() { return is_set ? reinterpret_cast(&storage) : 0; } const T* get() const { return is_set ? reinterpret_cast(&storage) : 0; } void set(T value) { if (is_set) { *reinterpret_cast(&storage) = std::move(value); } else { new (reinterpret_cast(&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