propagate_const
[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(noexcept(
130       detail::propagate_const_adl::adl_swap(pointer_, other.pointer_))) {
131     detail::propagate_const_adl::adl_swap(pointer_, other.pointer_);
132   }
133
134   constexpr element_type* get() {
135     return get_(pointer_);
136   }
137
138   constexpr element_type const* get() const {
139     return get_(pointer_);
140   }
141
142   constexpr explicit operator bool() const {
143     return static_cast<bool>(pointer_);
144   }
145
146   constexpr element_type& operator*() {
147     return *get();
148   }
149
150   constexpr element_type const& operator*() const {
151     return *get();
152   }
153
154   constexpr element_type* operator->() {
155     return get();
156   }
157
158   constexpr element_type const* operator->() const {
159     return get();
160   }
161
162   template <
163       typename OtherPointer = Pointer,
164       typename = _t<std::enable_if<
165           std::is_pointer<OtherPointer>::value ||
166           std::is_convertible<OtherPointer, element_type*>::value>>>
167   constexpr operator element_type*() {
168     return get();
169   }
170
171   template <
172       typename OtherPointer = Pointer,
173       typename = _t<std::enable_if<
174           std::is_pointer<OtherPointer>::value ||
175           std::is_convertible<OtherPointer, element_type const*>::value>>>
176   constexpr operator element_type const*() const {
177     return get();
178   }
179
180  private:
181   friend Pointer& get_underlying<>(propagate_const&);
182   friend Pointer const& get_underlying<>(propagate_const const&);
183
184   template <typename T>
185   static T* get_(T* t) {
186     return t;
187   }
188   template <typename T>
189   static auto get_(T& t) -> decltype(t.get()) {
190     return t.get();
191   }
192
193   Pointer pointer_;
194 };
195
196 template <typename Pointer>
197 FOLLY_CPP14_CONSTEXPR void swap(
198     propagate_const<Pointer>& a,
199     propagate_const<Pointer>& b) noexcept(noexcept(a.swap(b))) {
200   a.swap(b);
201 }
202
203 template <typename Pointer>
204 constexpr bool operator==(propagate_const<Pointer> const& a, std::nullptr_t) {
205   return get_underlying(a) == nullptr;
206 }
207
208 template <typename Pointer>
209 constexpr bool operator==(std::nullptr_t, propagate_const<Pointer> const& a) {
210   return nullptr == get_underlying(a);
211 }
212
213 template <typename Pointer>
214 constexpr bool operator!=(propagate_const<Pointer> const& a, std::nullptr_t) {
215   return get_underlying(a) != nullptr;
216 }
217
218 template <typename Pointer>
219 constexpr bool operator!=(std::nullptr_t, propagate_const<Pointer> const& a) {
220   return nullptr != get_underlying(a);
221 }
222
223 template <typename Pointer>
224 constexpr bool operator==(
225     propagate_const<Pointer> const& a,
226     propagate_const<Pointer> const& b) {
227   return get_underlying(a) == get_underlying(b);
228 }
229
230 template <typename Pointer>
231 constexpr bool operator!=(
232     propagate_const<Pointer> const& a,
233     propagate_const<Pointer> const& b) {
234   return get_underlying(a) != get_underlying(b);
235 }
236
237 template <typename Pointer>
238 constexpr bool operator<(
239     propagate_const<Pointer> const& a,
240     propagate_const<Pointer> const& b) {
241   return get_underlying(a) < get_underlying(b);
242 }
243
244 template <typename Pointer>
245 constexpr bool operator<=(
246     propagate_const<Pointer> const& a,
247     propagate_const<Pointer> const& b) {
248   return get_underlying(a) <= get_underlying(b);
249 }
250
251 template <typename Pointer>
252 constexpr bool operator>(
253     propagate_const<Pointer> const& a,
254     propagate_const<Pointer> const& b) {
255   return get_underlying(a) > get_underlying(b);
256 }
257
258 template <typename Pointer>
259 constexpr bool operator>=(
260     propagate_const<Pointer> const& a,
261     propagate_const<Pointer> const& b) {
262   return get_underlying(a) >= get_underlying(b);
263 }
264
265 //  Note: contrary to the specification, the heterogeneous comparison operators
266 //  only participate in overload resolution when the equivalent heterogeneous
267 //  comparison operators on the underlying pointers, as returned by invocation
268 //  of get_underlying, would also participate in overload resolution.
269
270 template <typename Pointer, typename Other>
271 constexpr auto operator==(propagate_const<Pointer> const& a, Other const& b)
272     -> decltype(get_underlying(a) == b, false) {
273   return get_underlying(a) == b;
274 }
275
276 template <typename Pointer, typename Other>
277 constexpr auto operator!=(propagate_const<Pointer> const& a, Other const& b)
278     -> decltype(get_underlying(a) != b, false) {
279   return get_underlying(a) != b;
280 }
281
282 template <typename Pointer, typename Other>
283 constexpr auto operator<(propagate_const<Pointer> const& a, Other const& b)
284     -> decltype(get_underlying(a) < b, false) {
285   return get_underlying(a) < b;
286 }
287
288 template <typename Pointer, typename Other>
289 constexpr auto operator<=(propagate_const<Pointer> const& a, Other const& b)
290     -> decltype(get_underlying(a) <= b, false) {
291   return get_underlying(a) <= b;
292 }
293
294 template <typename Pointer, typename Other>
295 constexpr auto operator>(propagate_const<Pointer> const& a, Other const& b)
296     -> decltype(get_underlying(a) > b, false) {
297   return get_underlying(a) > b;
298 }
299
300 template <typename Pointer, typename Other>
301 constexpr auto operator>=(propagate_const<Pointer> const& a, Other const& b)
302     -> decltype(get_underlying(a) >= b, false) {
303   return get_underlying(a) >= b;
304 }
305
306 template <typename Other, typename Pointer>
307 constexpr auto operator==(Other const& a, propagate_const<Pointer> const& b)
308     -> decltype(a == get_underlying(b), false) {
309   return a == get_underlying(b);
310 }
311
312 template <typename Other, typename Pointer>
313 constexpr auto operator!=(Other const& a, propagate_const<Pointer> const& b)
314     -> decltype(a != get_underlying(b), false) {
315   return a != get_underlying(b);
316 }
317
318 template <typename Other, typename Pointer>
319 constexpr auto operator<(Other const& a, propagate_const<Pointer> const& b)
320     -> decltype(a < get_underlying(b), false) {
321   return a < get_underlying(b);
322 }
323
324 template <typename Other, typename Pointer>
325 constexpr auto operator<=(Other const& a, propagate_const<Pointer> const& b)
326     -> decltype(a <= get_underlying(b), false) {
327   return a <= get_underlying(b);
328 }
329
330 template <typename Other, typename Pointer>
331 constexpr auto operator>(Other const& a, propagate_const<Pointer> const& b)
332     -> decltype(a > get_underlying(b), false) {
333   return a > get_underlying(b);
334 }
335
336 template <typename Other, typename Pointer>
337 constexpr auto operator>=(Other const& a, propagate_const<Pointer> const& b)
338     -> decltype(a >= get_underlying(b), false) {
339   return a >= get_underlying(b);
340 }
341
342 } // namespace folly
343
344 namespace std {
345
346 template <typename Pointer>
347 struct hash<folly::propagate_const<Pointer>> : private hash<Pointer> {
348   using hash<Pointer>::hash;
349
350   size_t operator()(folly::propagate_const<Pointer> const& obj) const {
351     return hash<Pointer>::operator()(folly::get_underlying(obj));
352   }
353 };
354
355 template <typename Pointer>
356 struct equal_to<folly::propagate_const<Pointer>> : private equal_to<Pointer> {
357   using equal_to<Pointer>::equal_to;
358
359   constexpr bool operator()(
360       folly::propagate_const<Pointer> const& a,
361       folly::propagate_const<Pointer> const& b) {
362     return equal_to<Pointer>::operator()(
363         folly::get_underlying(a), folly::get_underlying(b));
364   }
365 };
366
367 template <typename Pointer>
368 struct not_equal_to<folly::propagate_const<Pointer>>
369     : private not_equal_to<Pointer> {
370   using not_equal_to<Pointer>::not_equal_to;
371
372   constexpr bool operator()(
373       folly::propagate_const<Pointer> const& a,
374       folly::propagate_const<Pointer> const& b) {
375     return not_equal_to<Pointer>::operator()(
376         folly::get_underlying(a), folly::get_underlying(b));
377   }
378 };
379
380 template <typename Pointer>
381 struct less<folly::propagate_const<Pointer>> : private less<Pointer> {
382   using less<Pointer>::less;
383
384   constexpr bool operator()(
385       folly::propagate_const<Pointer> const& a,
386       folly::propagate_const<Pointer> const& b) {
387     return less<Pointer>::operator()(
388         folly::get_underlying(a), folly::get_underlying(b));
389   }
390 };
391
392 template <typename Pointer>
393 struct greater<folly::propagate_const<Pointer>> : private greater<Pointer> {
394   using greater<Pointer>::greater;
395
396   constexpr bool operator()(
397       folly::propagate_const<Pointer> const& a,
398       folly::propagate_const<Pointer> const& b) {
399     return greater<Pointer>::operator()(
400         folly::get_underlying(a), folly::get_underlying(b));
401   }
402 };
403
404 template <typename Pointer>
405 struct less_equal<folly::propagate_const<Pointer>>
406     : private less_equal<Pointer> {
407   using less_equal<Pointer>::less_equal;
408
409   constexpr bool operator()(
410       folly::propagate_const<Pointer> const& a,
411       folly::propagate_const<Pointer> const& b) {
412     return less_equal<Pointer>::operator()(
413         folly::get_underlying(a), folly::get_underlying(b));
414   }
415 };
416
417 template <typename Pointer>
418 struct greater_equal<folly::propagate_const<Pointer>>
419     : private greater_equal<Pointer> {
420   using greater_equal<Pointer>::greater_equal;
421
422   constexpr bool operator()(
423       folly::propagate_const<Pointer> const& a,
424       folly::propagate_const<Pointer> const& b) {
425     return greater_equal<Pointer>::operator()(
426         folly::get_underlying(a), folly::get_underlying(b));
427   }
428 };
429
430 } // namespace std