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