Fix Build: propagate_const under GCC
[folly.git] / folly / lang / PropagateConst.h
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <functional>
20 #include <type_traits>
21 #include <utility>
22
23 #include <folly/Traits.h>
24 #include <folly/Utility.h>
25
26 namespace folly {
27
28 template <typename Pointer>
29 class propagate_const;
30
31 template <typename Pointer>
32 constexpr Pointer& get_underlying(propagate_const<Pointer>& obj) {
33   return obj.pointer_;
34 }
35
36 template <typename Pointer>
37 constexpr Pointer const& get_underlying(propagate_const<Pointer> const& obj) {
38   return obj.pointer_;
39 }
40
41 namespace detail {
42 template <typename>
43 struct is_propagate_const : std::false_type {};
44 template <typename Pointer>
45 struct is_propagate_const<propagate_const<Pointer>> : std::true_type {};
46 template <typename T>
47 using is_decay_propagate_const = is_propagate_const<_t<std::decay<T>>>;
48
49 namespace propagate_const_adl {
50 using std::swap;
51 template <typename T>
52 auto adl_swap(T& a, T& b) noexcept(noexcept(swap(a, b)))
53     -> decltype(swap(a, b)) {
54   swap(a, b);
55 }
56 } // namespace propagate_const_adl
57 } // namespace detail
58
59 //  mimic: std::experimental::propagate_const, C++ Library Fundamentals TS v2
60 template <typename Pointer>
61 class propagate_const {
62  public:
63   using element_type =
64       _t<std::remove_reference<decltype(*std::declval<Pointer&>())>>;
65
66   constexpr propagate_const() = default;
67   constexpr propagate_const(propagate_const&&) = default;
68   constexpr propagate_const(propagate_const const&) = delete;
69
70   template <
71       typename OtherPointer,
72       _t<std::enable_if<
73           std::is_constructible<Pointer, OtherPointer&&>::value &&
74               !std::is_convertible<OtherPointer&&, Pointer>::value,
75           int>> = 0>
76   constexpr explicit propagate_const(propagate_const<OtherPointer>&& other)
77       : pointer_(static_cast<OtherPointer&&>(other.pointer_)) {}
78
79   template <
80       typename OtherPointer,
81       _t<std::enable_if<
82           std::is_constructible<Pointer, OtherPointer&&>::value &&
83               std::is_convertible<OtherPointer&&, Pointer>::value,
84           int>> = 0>
85   constexpr propagate_const(propagate_const<OtherPointer>&& other)
86       : pointer_(static_cast<OtherPointer&&>(other.pointer_)) {}
87
88   template <
89       typename OtherPointer,
90       _t<std::enable_if<
91           !detail::is_decay_propagate_const<OtherPointer>::value &&
92               std::is_constructible<Pointer, OtherPointer&&>::value &&
93               !std::is_convertible<OtherPointer&&, Pointer>::value,
94           int>> = 0>
95   constexpr explicit propagate_const(OtherPointer&& other)
96       : pointer_(static_cast<OtherPointer&&>(other)) {}
97
98   template <
99       typename OtherPointer,
100       _t<std::enable_if<
101           !detail::is_decay_propagate_const<OtherPointer>::value &&
102               std::is_constructible<Pointer, OtherPointer&&>::value &&
103               std::is_convertible<OtherPointer&&, Pointer>::value,
104           int>> = 0>
105   constexpr propagate_const(OtherPointer&& other)
106       : pointer_(static_cast<OtherPointer&&>(other)) {}
107
108   constexpr propagate_const& operator=(propagate_const&&) = default;
109   constexpr propagate_const& operator=(propagate_const const&) = delete;
110
111   template <
112       typename OtherPointer,
113       typename = _t<
114           std::enable_if<std::is_convertible<OtherPointer&&, Pointer>::value>>>
115   FOLLY_CPP14_CONSTEXPR propagate_const& operator=(
116       propagate_const<OtherPointer>&& other) {
117     pointer_ = static_cast<OtherPointer&&>(other.pointer_);
118   }
119
120   template <
121       typename OtherPointer,
122       typename = _t<std::enable_if<
123           !detail::is_decay_propagate_const<OtherPointer>::value &&
124           std::is_convertible<OtherPointer&&, Pointer>::value>>>
125   FOLLY_CPP14_CONSTEXPR propagate_const& operator=(OtherPointer&& other) {
126     pointer_ = static_cast<OtherPointer&&>(other);
127   }
128
129   FOLLY_CPP14_CONSTEXPR void swap(propagate_const& other) noexcept(
130       noexcept(detail::propagate_const_adl::adl_swap(
131           std::declval<Pointer&>(),
132           other.pointer_))) {
133     detail::propagate_const_adl::adl_swap(pointer_, other.pointer_);
134   }
135
136   constexpr element_type* get() {
137     return get_(pointer_);
138   }
139
140   constexpr element_type const* get() const {
141     return get_(pointer_);
142   }
143
144   constexpr explicit operator bool() const {
145     return static_cast<bool>(pointer_);
146   }
147
148   constexpr element_type& operator*() {
149     return *get();
150   }
151
152   constexpr element_type const& operator*() const {
153     return *get();
154   }
155
156   constexpr element_type* operator->() {
157     return get();
158   }
159
160   constexpr element_type const* operator->() const {
161     return get();
162   }
163
164   template <
165       typename OtherPointer = Pointer,
166       typename = _t<std::enable_if<
167           std::is_pointer<OtherPointer>::value ||
168           std::is_convertible<OtherPointer, element_type*>::value>>>
169   constexpr operator element_type*() {
170     return get();
171   }
172
173   template <
174       typename OtherPointer = Pointer,
175       typename = _t<std::enable_if<
176           std::is_pointer<OtherPointer>::value ||
177           std::is_convertible<OtherPointer, element_type const*>::value>>>
178   constexpr operator element_type const*() const {
179     return get();
180   }
181
182  private:
183   friend Pointer& get_underlying<>(propagate_const&);
184   friend Pointer const& get_underlying<>(propagate_const const&);
185
186   template <typename T>
187   static T* get_(T* t) {
188     return t;
189   }
190   template <typename T>
191   static auto get_(T& t) -> decltype(t.get()) {
192     return t.get();
193   }
194
195   Pointer pointer_;
196 };
197
198 template <typename Pointer>
199 FOLLY_CPP14_CONSTEXPR void swap(
200     propagate_const<Pointer>& a,
201     propagate_const<Pointer>& b) noexcept(noexcept(a.swap(b))) {
202   a.swap(b);
203 }
204
205 template <typename Pointer>
206 constexpr bool operator==(propagate_const<Pointer> const& a, std::nullptr_t) {
207   return get_underlying(a) == nullptr;
208 }
209
210 template <typename Pointer>
211 constexpr bool operator==(std::nullptr_t, propagate_const<Pointer> const& a) {
212   return nullptr == get_underlying(a);
213 }
214
215 template <typename Pointer>
216 constexpr bool operator!=(propagate_const<Pointer> const& a, std::nullptr_t) {
217   return get_underlying(a) != nullptr;
218 }
219
220 template <typename Pointer>
221 constexpr bool operator!=(std::nullptr_t, propagate_const<Pointer> const& a) {
222   return nullptr != get_underlying(a);
223 }
224
225 template <typename Pointer>
226 constexpr bool operator==(
227     propagate_const<Pointer> const& a,
228     propagate_const<Pointer> const& b) {
229   return get_underlying(a) == get_underlying(b);
230 }
231
232 template <typename Pointer>
233 constexpr bool operator!=(
234     propagate_const<Pointer> const& a,
235     propagate_const<Pointer> const& b) {
236   return get_underlying(a) != get_underlying(b);
237 }
238
239 template <typename Pointer>
240 constexpr bool operator<(
241     propagate_const<Pointer> const& a,
242     propagate_const<Pointer> const& b) {
243   return get_underlying(a) < get_underlying(b);
244 }
245
246 template <typename Pointer>
247 constexpr bool operator<=(
248     propagate_const<Pointer> const& a,
249     propagate_const<Pointer> const& b) {
250   return get_underlying(a) <= get_underlying(b);
251 }
252
253 template <typename Pointer>
254 constexpr bool operator>(
255     propagate_const<Pointer> const& a,
256     propagate_const<Pointer> const& b) {
257   return get_underlying(a) > get_underlying(b);
258 }
259
260 template <typename Pointer>
261 constexpr bool operator>=(
262     propagate_const<Pointer> const& a,
263     propagate_const<Pointer> const& b) {
264   return get_underlying(a) >= get_underlying(b);
265 }
266
267 //  Note: contrary to the specification, the heterogeneous comparison operators
268 //  only participate in overload resolution when the equivalent heterogeneous
269 //  comparison operators on the underlying pointers, as returned by invocation
270 //  of get_underlying, would also participate in overload resolution.
271
272 template <typename Pointer, typename Other>
273 constexpr auto operator==(propagate_const<Pointer> const& a, Other const& b)
274     -> decltype(get_underlying(a) == b, false) {
275   return get_underlying(a) == b;
276 }
277
278 template <typename Pointer, typename Other>
279 constexpr auto operator!=(propagate_const<Pointer> const& a, Other const& b)
280     -> decltype(get_underlying(a) != b, false) {
281   return get_underlying(a) != b;
282 }
283
284 template <typename Pointer, typename Other>
285 constexpr auto operator<(propagate_const<Pointer> const& a, Other const& b)
286     -> decltype(get_underlying(a) < b, false) {
287   return get_underlying(a) < b;
288 }
289
290 template <typename Pointer, typename Other>
291 constexpr auto operator<=(propagate_const<Pointer> const& a, Other const& b)
292     -> decltype(get_underlying(a) <= b, false) {
293   return get_underlying(a) <= b;
294 }
295
296 template <typename Pointer, typename Other>
297 constexpr auto operator>(propagate_const<Pointer> const& a, Other const& b)
298     -> decltype(get_underlying(a) > b, false) {
299   return get_underlying(a) > b;
300 }
301
302 template <typename Pointer, typename Other>
303 constexpr auto operator>=(propagate_const<Pointer> const& a, Other const& b)
304     -> decltype(get_underlying(a) >= b, false) {
305   return get_underlying(a) >= b;
306 }
307
308 template <typename Other, typename Pointer>
309 constexpr auto operator==(Other const& a, propagate_const<Pointer> const& b)
310     -> decltype(a == get_underlying(b), false) {
311   return a == get_underlying(b);
312 }
313
314 template <typename Other, typename Pointer>
315 constexpr auto operator!=(Other const& a, propagate_const<Pointer> const& b)
316     -> decltype(a != get_underlying(b), false) {
317   return a != get_underlying(b);
318 }
319
320 template <typename Other, typename Pointer>
321 constexpr auto operator<(Other const& a, propagate_const<Pointer> const& b)
322     -> decltype(a < get_underlying(b), false) {
323   return a < get_underlying(b);
324 }
325
326 template <typename Other, typename Pointer>
327 constexpr auto operator<=(Other const& a, propagate_const<Pointer> const& b)
328     -> decltype(a <= get_underlying(b), false) {
329   return a <= get_underlying(b);
330 }
331
332 template <typename Other, typename Pointer>
333 constexpr auto operator>(Other const& a, propagate_const<Pointer> const& b)
334     -> decltype(a > get_underlying(b), false) {
335   return a > get_underlying(b);
336 }
337
338 template <typename Other, typename Pointer>
339 constexpr auto operator>=(Other const& a, propagate_const<Pointer> const& b)
340     -> decltype(a >= get_underlying(b), false) {
341   return a >= get_underlying(b);
342 }
343
344 } // namespace folly
345
346 namespace std {
347
348 template <typename Pointer>
349 struct hash<folly::propagate_const<Pointer>> : private hash<Pointer> {
350   using hash<Pointer>::hash;
351
352   size_t operator()(folly::propagate_const<Pointer> const& obj) const {
353     return hash<Pointer>::operator()(folly::get_underlying(obj));
354   }
355 };
356
357 template <typename Pointer>
358 struct equal_to<folly::propagate_const<Pointer>> : private equal_to<Pointer> {
359   using equal_to<Pointer>::equal_to;
360
361   constexpr bool operator()(
362       folly::propagate_const<Pointer> const& a,
363       folly::propagate_const<Pointer> const& b) {
364     return equal_to<Pointer>::operator()(
365         folly::get_underlying(a), folly::get_underlying(b));
366   }
367 };
368
369 template <typename Pointer>
370 struct not_equal_to<folly::propagate_const<Pointer>>
371     : private not_equal_to<Pointer> {
372   using not_equal_to<Pointer>::not_equal_to;
373
374   constexpr bool operator()(
375       folly::propagate_const<Pointer> const& a,
376       folly::propagate_const<Pointer> const& b) {
377     return not_equal_to<Pointer>::operator()(
378         folly::get_underlying(a), folly::get_underlying(b));
379   }
380 };
381
382 template <typename Pointer>
383 struct less<folly::propagate_const<Pointer>> : private less<Pointer> {
384   using less<Pointer>::less;
385
386   constexpr bool operator()(
387       folly::propagate_const<Pointer> const& a,
388       folly::propagate_const<Pointer> const& b) {
389     return less<Pointer>::operator()(
390         folly::get_underlying(a), folly::get_underlying(b));
391   }
392 };
393
394 template <typename Pointer>
395 struct greater<folly::propagate_const<Pointer>> : private greater<Pointer> {
396   using greater<Pointer>::greater;
397
398   constexpr bool operator()(
399       folly::propagate_const<Pointer> const& a,
400       folly::propagate_const<Pointer> const& b) {
401     return greater<Pointer>::operator()(
402         folly::get_underlying(a), folly::get_underlying(b));
403   }
404 };
405
406 template <typename Pointer>
407 struct less_equal<folly::propagate_const<Pointer>>
408     : private less_equal<Pointer> {
409   using less_equal<Pointer>::less_equal;
410
411   constexpr bool operator()(
412       folly::propagate_const<Pointer> const& a,
413       folly::propagate_const<Pointer> const& b) {
414     return less_equal<Pointer>::operator()(
415         folly::get_underlying(a), folly::get_underlying(b));
416   }
417 };
418
419 template <typename Pointer>
420 struct greater_equal<folly::propagate_const<Pointer>>
421     : private greater_equal<Pointer> {
422   using greater_equal<Pointer>::greater_equal;
423
424   constexpr bool operator()(
425       folly::propagate_const<Pointer> const& a,
426       folly::propagate_const<Pointer> const& b) {
427     return greater_equal<Pointer>::operator()(
428         folly::get_underlying(a), folly::get_underlying(b));
429   }
430 };
431
432 } // namespace std