summaryrefslogtreecommitdiff
path: root/Ix/CPP/src/cpplinq/util.hpp
blob: ee3d7ebd410963e1a8b43a118bd3c8e4c79d47ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// 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