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);
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_);
134 constexpr element_type* get() {
135 return get_(pointer_);
138 constexpr element_type const* get() const {
139 return get_(pointer_);
142 constexpr explicit operator bool() const {
143 return static_cast<bool>(pointer_);
146 constexpr element_type& operator*() {
150 constexpr element_type const& operator*() const {
154 constexpr element_type* operator->() {
158 constexpr element_type const* operator->() const {
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*() {
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 {
181 friend Pointer& get_underlying<>(propagate_const&);
182 friend Pointer const& get_underlying<>(propagate_const const&);
184 template <typename T>
185 static T* get_(T* t) {
188 template <typename T>
189 static auto get_(T& t) -> decltype(t.get()) {
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))) {
203 template <typename Pointer>
204 constexpr bool operator==(propagate_const<Pointer> const& a, std::nullptr_t) {
205 return get_underlying(a) == nullptr;
208 template <typename Pointer>
209 constexpr bool operator==(std::nullptr_t, propagate_const<Pointer> const& a) {
210 return nullptr == get_underlying(a);
213 template <typename Pointer>
214 constexpr bool operator!=(propagate_const<Pointer> const& a, std::nullptr_t) {
215 return get_underlying(a) != nullptr;
218 template <typename Pointer>
219 constexpr bool operator!=(std::nullptr_t, propagate_const<Pointer> const& a) {
220 return nullptr != get_underlying(a);
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);
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);
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);
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);
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);
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);
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.
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;
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;
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;
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;
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;
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;
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);
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);
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);
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);
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);
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);
346 template <typename Pointer>
347 struct hash<folly::propagate_const<Pointer>> : private hash<Pointer> {
348 using hash<Pointer>::hash;
350 size_t operator()(folly::propagate_const<Pointer> const& obj) const {
351 return hash<Pointer>::operator()(folly::get_underlying(obj));
355 template <typename Pointer>
356 struct equal_to<folly::propagate_const<Pointer>> : private equal_to<Pointer> {
357 using equal_to<Pointer>::equal_to;
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));
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;
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));
380 template <typename Pointer>
381 struct less<folly::propagate_const<Pointer>> : private less<Pointer> {
382 using less<Pointer>::less;
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));
392 template <typename Pointer>
393 struct greater<folly::propagate_const<Pointer>> : private greater<Pointer> {
394 using greater<Pointer>::greater;
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));
404 template <typename Pointer>
405 struct less_equal<folly::propagate_const<Pointer>>
406 : private less_equal<Pointer> {
407 using less_equal<Pointer>::less_equal;
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));
417 template <typename Pointer>
418 struct greater_equal<folly::propagate_const<Pointer>>
419 : private greater_equal<Pointer> {
420 using greater_equal<Pointer>::greater_equal;
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));