File indexing completed on 2024-06-02 04:26:09
0001 /* 0002 0003 Copyright (c) 2014-2018 Jonathan B. Coe 0004 0005 Permission is hereby granted, free of charge, to any person obtaining a copy of 0006 this software and associated documentation files (the "Software"), to deal in 0007 the Software without restriction, including without limitation the rights to 0008 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 0009 the Software, and to permit persons to whom the Software is furnished to do so, 0010 subject to the following conditions: 0011 0012 The above copyright notice and this permission notice shall be included in all 0013 copies or substantial portions of the Software. 0014 0015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 0017 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 0018 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 0019 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 0020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0021 0022 */ 0023 0024 #ifndef JBCOE_PROPAGATE_CONST_INCLUDED 0025 #define JBCOE_PROPAGATE_CONST_INCLUDED 0026 0027 #include <functional> 0028 #include <memory> 0029 #include <type_traits> 0030 #include <utility> 0031 0032 #ifndef _MSC_VER 0033 #define PROPAGATE_CONST_CONSTEXPR constexpr 0034 #else 0035 #if _MSC_VER <= 1900 // MSVS 2015 and earlier 0036 #define PROPAGATE_CONST_CONSTEXPR 0037 #define PROPAGATE_CONST_HAS_NO_EXPRESSION_SFINAE 0038 #else 0039 #define PROPAGATE_CONST_CONSTEXPR constexpr 0040 #endif 0041 #endif 0042 0043 namespace std { 0044 namespace experimental { 0045 inline namespace fundamentals_v2 { 0046 template <class T> 0047 class propagate_const { 0048 public: 0049 using element_type = typename std::pointer_traits<T>::element_type; 0050 0051 private: 0052 template <class U> 0053 static element_type* get_pointer(U* u) { 0054 return u; 0055 } 0056 0057 template <class U> 0058 static element_type* get_pointer(U& u) { 0059 return get_pointer(u.get()); 0060 } 0061 0062 template <class U> 0063 static const element_type* get_pointer(const U* u) { 0064 return u; 0065 } 0066 0067 template <class U> 0068 static const element_type* get_pointer(const U& u) { 0069 return get_pointer(u.get()); 0070 } 0071 0072 template <class U> 0073 struct is_propagate_const : false_type {}; 0074 0075 template <class U> 0076 struct is_propagate_const<propagate_const<U>> : true_type {}; 0077 0078 public: 0079 // [propagate_const.ctor], constructors 0080 PROPAGATE_CONST_CONSTEXPR propagate_const() = default; 0081 0082 propagate_const(const propagate_const& p) = delete; 0083 0084 PROPAGATE_CONST_CONSTEXPR propagate_const(propagate_const&& p) = default; 0085 0086 #ifdef PROPAGATE_CONST_HAS_NO_EXPRESSION_SFINAE 0087 // 0088 // Make converting constructors explicit as we cannot use SFINAE to check. 0089 // 0090 template <class U, class = enable_if_t<is_constructible<T, U&&>::value>> 0091 explicit PROPAGATE_CONST_CONSTEXPR propagate_const(propagate_const<U>&& pu) 0092 : t_(std::move(pu.t_)) 0093 { 0094 } 0095 0096 template <class U, 0097 class = enable_if_t<is_constructible<T, U&&>::value && 0098 !is_propagate_const<decay_t<U>>::value>> 0099 explicit PROPAGATE_CONST_CONSTEXPR propagate_const(U&& u) 0100 : t_(std::forward<U>(u)) 0101 { 0102 } 0103 #else 0104 // 0105 // Use SFINAE to check if converting constructor should be explicit. 0106 // 0107 template <class U, enable_if_t<!is_convertible<U&&, T>::value && 0108 is_constructible<T, U&&>::value, 0109 bool> = true> 0110 explicit PROPAGATE_CONST_CONSTEXPR propagate_const(propagate_const<U>&& pu) 0111 : t_(std::move(pu.t_)) {} 0112 0113 template <class U, enable_if_t<is_convertible<U&&, T>::value && 0114 is_constructible<T, U&&>::value, 0115 bool> = false> 0116 PROPAGATE_CONST_CONSTEXPR propagate_const(propagate_const<U>&& pu) : t_(std::move(pu.t_)) {} 0117 0118 template <class U, enable_if_t<!is_convertible<U&&, T>::value && 0119 is_constructible<T, U&&>::value && 0120 !is_propagate_const<decay_t<U>>::value, 0121 bool> = true> 0122 explicit PROPAGATE_CONST_CONSTEXPR propagate_const(U&& u) : t_(std::forward<U>(u)) {} 0123 0124 template <class U, enable_if_t<is_convertible<U&&, T>::value && 0125 is_constructible<T, U&&>::value && 0126 !is_propagate_const<decay_t<U>>::value, 0127 bool> = false> 0128 PROPAGATE_CONST_CONSTEXPR propagate_const(U&& u) : t_(std::forward<U>(u)) {} 0129 #endif 0130 0131 // [propagate_const.assignment], assignment 0132 propagate_const& operator=(const propagate_const& p) = delete; 0133 0134 PROPAGATE_CONST_CONSTEXPR propagate_const& operator=(propagate_const&& p) = default; 0135 0136 template <class U> 0137 PROPAGATE_CONST_CONSTEXPR propagate_const& operator=(propagate_const<U>&& pu) { 0138 t_ = std::move(pu.t_); 0139 return *this; 0140 } 0141 0142 template <class U, 0143 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0144 PROPAGATE_CONST_CONSTEXPR propagate_const& operator=(U&& u) { 0145 t_ = std::move(u); 0146 return *this; 0147 } 0148 0149 // [propagate_const.const_observers], const observers 0150 explicit PROPAGATE_CONST_CONSTEXPR operator bool() const { return get() != nullptr; } 0151 PROPAGATE_CONST_CONSTEXPR const element_type* operator->() const { return get(); } 0152 0153 template <class T_ = T, class U = enable_if_t<is_convertible< 0154 const T_, const element_type*>::value>> 0155 PROPAGATE_CONST_CONSTEXPR operator const element_type*() const // Not always defined 0156 { 0157 return get(); 0158 } 0159 0160 PROPAGATE_CONST_CONSTEXPR const element_type& operator*() const { return *get(); } 0161 0162 PROPAGATE_CONST_CONSTEXPR const element_type* get() const { return get_pointer(t_); } 0163 0164 // [propagate_const.non_const_observers], non-const observers 0165 PROPAGATE_CONST_CONSTEXPR element_type* operator->() { return get(); } 0166 0167 template <class T_ = T, 0168 class U = enable_if_t<is_convertible<T_, element_type*>::value>> 0169 PROPAGATE_CONST_CONSTEXPR operator element_type*() // Not always defined 0170 { 0171 return get(); 0172 } 0173 0174 PROPAGATE_CONST_CONSTEXPR element_type& operator*() { return *get(); } 0175 0176 PROPAGATE_CONST_CONSTEXPR element_type* get() { return get_pointer(t_); } 0177 0178 // [propagate_const.modifiers], modifiers 0179 PROPAGATE_CONST_CONSTEXPR void swap(propagate_const& pt) noexcept( 0180 noexcept(swap(declval<T&>(), declval<T&>()))) { 0181 swap(t_, pt.t_); 0182 } 0183 0184 private: 0185 T t_; 0186 0187 friend struct std::hash<propagate_const<T>>; 0188 friend struct std::equal_to<propagate_const<T>>; 0189 friend struct std::not_equal_to<propagate_const<T>>; 0190 friend struct std::greater<propagate_const<T>>; 0191 friend struct std::less<propagate_const<T>>; 0192 friend struct std::greater_equal<propagate_const<T>>; 0193 friend struct std::less_equal<propagate_const<T>>; 0194 0195 // [propagate_const.relational], relational operators 0196 friend PROPAGATE_CONST_CONSTEXPR bool operator==(const propagate_const& pt, nullptr_t) { 0197 return pt.t_ == nullptr; 0198 } 0199 0200 friend PROPAGATE_CONST_CONSTEXPR bool operator==(nullptr_t, const propagate_const& pu) { 0201 return nullptr == pu.t_; 0202 } 0203 0204 friend PROPAGATE_CONST_CONSTEXPR bool operator!=(const propagate_const& pt, nullptr_t) { 0205 return pt.t_ != nullptr; 0206 } 0207 0208 friend PROPAGATE_CONST_CONSTEXPR bool operator!=(nullptr_t, const propagate_const& pu) { 0209 return nullptr != pu.t_; 0210 } 0211 0212 template <class U> 0213 friend PROPAGATE_CONST_CONSTEXPR bool operator==(const propagate_const& pt, 0214 const propagate_const<U>& pu) { 0215 return pt.t_ == pu.t_; 0216 } 0217 0218 template <class U> 0219 friend PROPAGATE_CONST_CONSTEXPR bool operator!=(const propagate_const& pt, 0220 const propagate_const<U>& pu) { 0221 return pt.t_ != pu.t_; 0222 } 0223 0224 template <class U> 0225 friend PROPAGATE_CONST_CONSTEXPR bool operator<(const propagate_const& pt, 0226 const propagate_const<U>& pu) { 0227 return pt.t_ < pu.t_; 0228 } 0229 0230 template <class U> 0231 friend PROPAGATE_CONST_CONSTEXPR bool operator>(const propagate_const& pt, 0232 const propagate_const<U>& pu) { 0233 return pt.t_ > pu.t_; 0234 } 0235 0236 template <class U> 0237 friend PROPAGATE_CONST_CONSTEXPR bool operator<=(const propagate_const& pt, 0238 const propagate_const<U>& pu) { 0239 return pt.t_ <= pu.t_; 0240 } 0241 0242 template <class U> 0243 friend PROPAGATE_CONST_CONSTEXPR bool operator>=(const propagate_const& pt, 0244 const propagate_const<U>& pu) { 0245 return pt.t_ >= pu.t_; 0246 } 0247 0248 template <class U, 0249 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0250 friend PROPAGATE_CONST_CONSTEXPR bool operator==(const propagate_const& pt, const U& u) { 0251 return pt.t_ == u; 0252 } 0253 0254 template <class U, 0255 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0256 friend PROPAGATE_CONST_CONSTEXPR bool operator!=(const propagate_const& pt, const U& u) { 0257 return pt.t_ != u; 0258 } 0259 0260 template <class U, 0261 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0262 friend PROPAGATE_CONST_CONSTEXPR bool operator<(const propagate_const& pt, const U& u) { 0263 return pt.t_ < u; 0264 } 0265 0266 template <class U, 0267 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0268 friend PROPAGATE_CONST_CONSTEXPR bool operator>(const propagate_const& pt, const U& u) { 0269 return pt.t_ > u; 0270 } 0271 0272 template <class U, 0273 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0274 friend PROPAGATE_CONST_CONSTEXPR bool operator<=(const propagate_const& pt, const U& u) { 0275 return pt.t_ <= u; 0276 } 0277 0278 template <class U, 0279 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0280 friend PROPAGATE_CONST_CONSTEXPR bool operator>=(const propagate_const& pt, const U& u) { 0281 return pt.t_ >= u; 0282 } 0283 0284 template <class U, 0285 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0286 friend PROPAGATE_CONST_CONSTEXPR bool operator==(const U& u, const propagate_const& pu) { 0287 return u == pu.t_; 0288 } 0289 0290 template <class U, 0291 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0292 friend PROPAGATE_CONST_CONSTEXPR bool operator!=(const U& u, const propagate_const& pu) { 0293 return u != pu.t_; 0294 } 0295 0296 template <class U, 0297 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0298 friend PROPAGATE_CONST_CONSTEXPR bool operator<(const U& u, const propagate_const& pu) { 0299 return u < pu.t_; 0300 } 0301 0302 template <class U, 0303 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0304 friend PROPAGATE_CONST_CONSTEXPR bool operator>(const U& u, const propagate_const& pu) { 0305 return u > pu.t_; 0306 } 0307 0308 template <class U, 0309 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0310 friend PROPAGATE_CONST_CONSTEXPR bool operator<=(const U& u, const propagate_const& pu) { 0311 return u <= pu.t_; 0312 } 0313 0314 template <class U, 0315 class = enable_if_t<!is_propagate_const<decay_t<U>>::value>> 0316 friend PROPAGATE_CONST_CONSTEXPR bool operator>=(const U& u, const propagate_const& pu) { 0317 return u >= pu.t_; 0318 } 0319 }; 0320 0321 0322 // [propagate_const.algorithms], specialized algorithms 0323 template <class T> 0324 PROPAGATE_CONST_CONSTEXPR void swap(propagate_const<T>& pt, propagate_const<T>& pu) noexcept( 0325 noexcept(swap(declval<T&>(), declval<T&>()))) 0326 { 0327 swap(pt.underlying_ptr(), pu.underlying_ptr()); 0328 } 0329 0330 } // end namespace fundamentals_v2 0331 } // end namespace experimental 0332 0333 // [propagate_const.hash], hash support 0334 template <class T> 0335 struct hash<experimental::fundamentals_v2::propagate_const<T>> { 0336 typedef size_t result_type; 0337 typedef experimental::fundamentals_v2::propagate_const<T> argument_type; 0338 0339 bool operator()( 0340 const experimental::fundamentals_v2::propagate_const<T>& pc) const { 0341 return std::hash<T>()(pc.t_); 0342 } 0343 }; 0344 0345 // [propagate_const.comparison_function_objects], comparison function objects 0346 template <class T> 0347 struct equal_to<experimental::fundamentals_v2::propagate_const<T>> { 0348 typedef experimental::fundamentals_v2::propagate_const<T> first_argument_type; 0349 typedef experimental::fundamentals_v2::propagate_const<T> 0350 second_argument_type; 0351 0352 bool operator()( 0353 const experimental::fundamentals_v2::propagate_const<T>& pc1, 0354 const experimental::fundamentals_v2::propagate_const<T>& pc2) const { 0355 return std::equal_to<T>()(pc1.t_, pc2.t_); 0356 } 0357 }; 0358 0359 template <class T> 0360 struct not_equal_to<experimental::fundamentals_v2::propagate_const<T>> { 0361 typedef experimental::fundamentals_v2::propagate_const<T> first_argument_type; 0362 typedef experimental::fundamentals_v2::propagate_const<T> 0363 second_argument_type; 0364 0365 bool operator()( 0366 const experimental::fundamentals_v2::propagate_const<T>& pc1, 0367 const experimental::fundamentals_v2::propagate_const<T>& pc2) const { 0368 return std::not_equal_to<T>()(pc1.t_, pc2.t_); 0369 } 0370 }; 0371 0372 template <class T> 0373 struct less<experimental::fundamentals_v2::propagate_const<T>> { 0374 typedef experimental::fundamentals_v2::propagate_const<T> first_argument_type; 0375 typedef experimental::fundamentals_v2::propagate_const<T> 0376 second_argument_type; 0377 0378 bool operator()( 0379 const experimental::fundamentals_v2::propagate_const<T>& pc1, 0380 const experimental::fundamentals_v2::propagate_const<T>& pc2) const { 0381 return std::less<T>()(pc1.t_, pc2.t_); 0382 } 0383 }; 0384 0385 template <class T> 0386 struct greater<experimental::fundamentals_v2::propagate_const<T>> { 0387 typedef experimental::fundamentals_v2::propagate_const<T> first_argument_type; 0388 typedef experimental::fundamentals_v2::propagate_const<T> 0389 second_argument_type; 0390 0391 bool operator()( 0392 const experimental::fundamentals_v2::propagate_const<T>& pc1, 0393 const experimental::fundamentals_v2::propagate_const<T>& pc2) const { 0394 return std::greater<T>()(pc1.t_, pc2.t_); 0395 } 0396 }; 0397 0398 template <class T> 0399 struct less_equal<experimental::fundamentals_v2::propagate_const<T>> { 0400 typedef experimental::fundamentals_v2::propagate_const<T> first_argument_type; 0401 typedef experimental::fundamentals_v2::propagate_const<T> 0402 second_argument_type; 0403 0404 bool operator()( 0405 const experimental::fundamentals_v2::propagate_const<T>& pc1, 0406 const experimental::fundamentals_v2::propagate_const<T>& pc2) const { 0407 return std::less_equal<T>()(pc1.t_, pc2.t_); 0408 } 0409 }; 0410 0411 template <class T> 0412 struct greater_equal<experimental::fundamentals_v2::propagate_const<T>> { 0413 typedef experimental::fundamentals_v2::propagate_const<T> first_argument_type; 0414 typedef experimental::fundamentals_v2::propagate_const<T> 0415 second_argument_type; 0416 0417 bool operator()( 0418 const experimental::fundamentals_v2::propagate_const<T>& pc1, 0419 const experimental::fundamentals_v2::propagate_const<T>& pc2) const { 0420 return std::greater_equal<T>()(pc1.t_, pc2.t_); 0421 } 0422 }; 0423 0424 } // end namespace std 0425 0426 #undef PROPAGATE_CONST_CONSTEXPR 0427 #endif // JBCOE_PROPAGATE_CONST_INCLUDED