2 * Copyright 2017-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <type_traits>
23 #include <folly/Traits.h>
24 #include <folly/Utility.h>
28 template <typename Pointer>
29 class propagate_const;
31 template <typename Pointer>
32 constexpr Pointer& get_underlying(propagate_const<Pointer>& obj) {
36 template <typename Pointer>
37 constexpr Pointer const& get_underlying(propagate_const<Pointer> const& obj) {
43 struct is_propagate_const : std::false_type {};
44 template <typename Pointer>
45 struct is_propagate_const<propagate_const<Pointer>> : std::true_type {};
47 using is_decay_propagate_const = is_propagate_const<_t<std::decay<T>>>;
49 namespace propagate_const_adl {
52 auto adl_swap(T& a, T& b) noexcept(noexcept(swap(a, b)))
53 -> decltype(swap(a, b)) {
56 } // namespace propagate_const_adl
59 // mimic: std::experimental::propagate_const, C++ Library Fundamentals TS v2
60 template <typename Pointer>
61 class propagate_const {
64 _t<std::remove_reference<decltype(*std::declval<Pointer&>())>>;
66 constexpr propagate_const() = default;
67 constexpr propagate_const(propagate_const&&) = default;
68 constexpr propagate_const(propagate_const const&) = delete;
71 typename OtherPointer,
73 std::is_constructible<Pointer, OtherPointer&&>::value &&
74 !std::is_convertible<OtherPointer&&, Pointer>::value,
76 constexpr explicit propagate_const(propagate_const<OtherPointer>&& other)
77 : pointer_(static_cast<OtherPointer&&>(other.pointer_)) {}
80 typename OtherPointer,
82 std::is_constructible<Pointer, OtherPointer&&>::value &&
83 std::is_convertible<OtherPointer&&, Pointer>::value,
85 constexpr propagate_const(propagate_const<OtherPointer>&& other)
86 : pointer_(static_cast<OtherPointer&&>(other.pointer_)) {}
89 typename OtherPointer,
91 !detail::is_decay_propagate_const<OtherPointer>::value &&
92 std::is_constructible<Pointer, OtherPointer&&>::value &&
93 !std::is_convertible<OtherPointer&&, Pointer>::value,
95 constexpr explicit propagate_const(OtherPointer&& other)
96 : pointer_(static_cast<OtherPointer&&>(other)) {}
99 typename OtherPointer,
101 !detail::is_decay_propagate_const<OtherPointer>::value &&
102 std::is_constructible<Pointer, OtherPointer&&>::value &&
103 std::is_convertible<OtherPointer&&, Pointer>::value,
105 constexpr propagate_const(OtherPointer&& other)
106 : pointer_(static_cast<OtherPointer&&>(other)) {}
108 constexpr propagate_const& operator=(propagate_const&&) = default;
109 constexpr propagate_const& operator=(propagate_const const&) = delete;
112 typename OtherPointer,
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_);
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);
130 FOLLY_CPP14_CONSTEXPR void swap(propagate_const& other) noexcept(
131 noexcept(detail::propagate_const_adl::adl_swap(
132 std::declval<Pointer&>(),
134 detail::propagate_const_adl::adl_swap(pointer_, other.pointer_);
137 constexpr element_type* get() {
138 return get_(pointer_);
141 constexpr element_type const* get() const {
142 return get_(pointer_);
145 constexpr explicit operator bool() const {
146 return static_cast<bool>(pointer_);
149 constexpr element_type& operator*() {
153 constexpr element_type const& operator*() const {
157 constexpr element_type* operator->() {
161 constexpr element_type const* operator->() const {
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*() {
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 {
184 friend Pointer& get_underlying<>(propagate_const&);
185 friend Pointer const& get_underlying<>(propagate_const const&);
187 template <typename T>
188 static T* get_(T* t) {
191 template <typename T>
192 static auto get_(T& t) -> decltype(t.get()) {
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))) {
206 template <typename Pointer>
207 constexpr bool operator==(propagate_const<Pointer> const& a, std::nullptr_t) {
208 return get_underlying(a) == nullptr;
211 template <typename Pointer>
212 constexpr bool operator==(std::nullptr_t, propagate_const<Pointer> const& a) {
213 return nullptr == get_underlying(a);
216 template <typename Pointer>
217 constexpr bool operator!=(propagate_const<Pointer> const& a, std::nullptr_t) {
218 return get_underlying(a) != nullptr;
221 template <typename Pointer>
222 constexpr bool operator!=(std::nullptr_t, propagate_const<Pointer> const& a) {
223 return nullptr != get_underlying(a);
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);
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);
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);
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);
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);
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);
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.
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;
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;
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;
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;
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;
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;
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);
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);
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);
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);
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);
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);
349 template <typename Pointer>
350 struct hash<folly::propagate_const<Pointer>> : private hash<Pointer> {
351 using hash<Pointer>::hash;
353 size_t operator()(folly::propagate_const<Pointer> const& obj) const {
354 return hash<Pointer>::operator()(folly::get_underlying(obj));
358 template <typename Pointer>
359 struct equal_to<folly::propagate_const<Pointer>> : private equal_to<Pointer> {
360 using equal_to<Pointer>::equal_to;
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));
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;
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));
383 template <typename Pointer>
384 struct less<folly::propagate_const<Pointer>> : private less<Pointer> {
385 using less<Pointer>::less;
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));
395 template <typename Pointer>
396 struct greater<folly::propagate_const<Pointer>> : private greater<Pointer> {
397 using greater<Pointer>::greater;
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));
407 template <typename Pointer>
408 struct less_equal<folly::propagate_const<Pointer>>
409 : private less_equal<Pointer> {
410 using less_equal<Pointer>::less_equal;
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));
420 template <typename Pointer>
421 struct greater_equal<folly::propagate_const<Pointer>>
422 : private greater_equal<Pointer> {
423 using greater_equal<Pointer>::greater_equal;
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));