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