1 | // |
2 | // immer: immutable data structures for C++ |
3 | // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente |
4 | // |
5 | // This software is distributed under the Boost Software License, Version 1.0. |
6 | // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt |
7 | // |
8 | |
9 | #pragma once |
10 | |
11 | #include <algorithm> |
12 | #include <iterator> |
13 | #include <memory> |
14 | #include <type_traits> |
15 | #include <utility> |
16 | |
17 | namespace immer { |
18 | namespace detail { |
19 | |
20 | template <typename... Ts> |
21 | struct make_void { using type = void; }; |
22 | |
23 | template <typename... Ts> |
24 | using void_t = typename make_void<Ts...>::type; |
25 | |
26 | template <typename T, typename = void> |
27 | struct is_dereferenceable : std::false_type {}; |
28 | |
29 | template <typename T> |
30 | struct is_dereferenceable<T, void_t<decltype(*(std::declval<T&>()))>> : |
31 | std::true_type {}; |
32 | |
33 | template <typename T> |
34 | constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value; |
35 | |
36 | template<typename T, typename U=T, typename = void> |
37 | struct is_equality_comparable : std::false_type {}; |
38 | |
39 | template<typename T, typename U> |
40 | struct is_equality_comparable |
41 | <T, U, std::enable_if_t |
42 | <std::is_same |
43 | <bool, decltype(std::declval<T&>() == std::declval<U&>())>::value>> : |
44 | std::true_type {}; |
45 | |
46 | template<typename T, typename U=T> |
47 | constexpr bool is_equality_comparable_v = is_equality_comparable<T, U>::value; |
48 | |
49 | template<typename T, typename U=T, typename = void> |
50 | struct is_inequality_comparable : std::false_type {}; |
51 | |
52 | template<typename T, typename U> |
53 | struct is_inequality_comparable |
54 | <T, U, std::enable_if_t |
55 | <std::is_same |
56 | <bool, decltype(std::declval<T&>() != std::declval<U&>())>::value>> : |
57 | std::true_type {}; |
58 | |
59 | template<typename T, typename U=T> |
60 | constexpr bool is_inequality_comparable_v = |
61 | is_inequality_comparable<T, U>::value; |
62 | |
63 | template <typename T, typename = void> |
64 | struct is_preincrementable : std::false_type {}; |
65 | |
66 | template <typename T> |
67 | struct is_preincrementable |
68 | <T, std::enable_if_t |
69 | <std::is_same<T&, decltype(++(std::declval<T&>()))>::value>> : |
70 | std::true_type {}; |
71 | |
72 | template <typename T> |
73 | constexpr bool is_preincrementable_v = is_preincrementable<T>::value; |
74 | |
75 | template <typename T, typename U=T, typename = void> |
76 | struct is_subtractable : std::false_type {}; |
77 | |
78 | template <typename T, typename U> |
79 | struct is_subtractable |
80 | <T, U, void_t<decltype(std::declval<T&>() - std::declval<U&>())>> : |
81 | std::true_type {}; |
82 | |
83 | template <typename T, typename U = T> |
84 | constexpr bool is_subtractable_v = is_subtractable<T, U>::value; |
85 | |
86 | namespace swappable { |
87 | |
88 | using std::swap; |
89 | |
90 | template <typename T, typename U, typename = void> |
91 | struct with : std::false_type {}; |
92 | |
93 | // Does not account for non-referenceable types |
94 | template <typename T, typename U> |
95 | struct with |
96 | <T, U, void_t<decltype(swap(std::declval<T&>(), std::declval<U&>())), |
97 | decltype(swap(std::declval<U&>(), std::declval<T&>()))>> : |
98 | std::true_type {}; |
99 | |
100 | } |
101 | |
102 | template<typename T, typename U> |
103 | using is_swappable_with = swappable::with<T, U>; |
104 | |
105 | template<typename T> |
106 | using is_swappable = is_swappable_with<T, T>; |
107 | |
108 | template <typename T> |
109 | constexpr bool is_swappable_v = is_swappable_with<T&, T&>::value; |
110 | |
111 | template <typename T, typename = void> |
112 | struct is_iterator : std::false_type {}; |
113 | |
114 | // See http://en.cppreference.com/w/cpp/concept/Iterator |
115 | template <typename T> |
116 | struct is_iterator |
117 | <T, void_t |
118 | <std::enable_if_t |
119 | <is_preincrementable_v<T> |
120 | && is_dereferenceable_v<T> |
121 | // accounts for non-referenceable types |
122 | && std::is_copy_constructible<T>::value |
123 | && std::is_copy_assignable<T>::value |
124 | && std::is_destructible<T>::value |
125 | && is_swappable_v<T>>, |
126 | typename std::iterator_traits<T>::value_type, |
127 | typename std::iterator_traits<T>::difference_type, |
128 | typename std::iterator_traits<T>::reference, |
129 | typename std::iterator_traits<T>::pointer, |
130 | typename std::iterator_traits<T>::iterator_category>> : |
131 | std::true_type {}; |
132 | |
133 | template<typename T> |
134 | constexpr bool is_iterator_v = is_iterator<T>::value; |
135 | |
136 | template<typename T, typename U, typename = void> |
137 | struct compatible_sentinel : std::false_type {}; |
138 | |
139 | template<typename T, typename U> |
140 | struct compatible_sentinel |
141 | <T, U, std::enable_if_t |
142 | <is_iterator_v<T> |
143 | && is_equality_comparable_v<T, U> |
144 | && is_inequality_comparable_v<T, U>>> : |
145 | std::true_type {}; |
146 | |
147 | template<typename T, typename U> |
148 | constexpr bool compatible_sentinel_v = compatible_sentinel<T,U>::value; |
149 | |
150 | template<typename T, typename = void> |
151 | struct is_forward_iterator : std::false_type {}; |
152 | |
153 | template<typename T> |
154 | struct is_forward_iterator |
155 | <T, std::enable_if_t |
156 | <is_iterator_v<T> && |
157 | std::is_base_of |
158 | <std::forward_iterator_tag, |
159 | typename std::iterator_traits<T>::iterator_category>::value>> : |
160 | std::true_type {}; |
161 | |
162 | template<typename T> |
163 | constexpr bool is_forward_iterator_v = is_forward_iterator<T>::value; |
164 | |
165 | template<typename T, typename U, typename = void> |
166 | struct std_distance_supports : std::false_type {}; |
167 | |
168 | template<typename T, typename U> |
169 | struct std_distance_supports |
170 | <T, U, void_t<decltype(std::distance(std::declval<T>(), std::declval<U>()))>> : |
171 | std::true_type {}; |
172 | |
173 | template<typename T, typename U> |
174 | constexpr bool std_distance_supports_v = std_distance_supports<T, U>::value; |
175 | |
176 | template<typename T, typename U, typename V, typename = void> |
177 | struct std_uninitialized_copy_supports : std::false_type {}; |
178 | |
179 | template<typename T, typename U, typename V> |
180 | struct std_uninitialized_copy_supports |
181 | <T, U, V, void_t<decltype(std::uninitialized_copy(std::declval<T>(), |
182 | std::declval<U>(), |
183 | std::declval<V>()))>> : |
184 | std::true_type {}; |
185 | |
186 | template<typename T, typename U, typename V> |
187 | constexpr bool std_uninitialized_copy_supports_v = |
188 | std_uninitialized_copy_supports<T, U, V>::value; |
189 | |
190 | } |
191 | } |
192 | |