Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:35:23

0001 #ifndef _DATE_TIME_INT_ADAPTER_HPP__
0002 #define _DATE_TIME_INT_ADAPTER_HPP__
0003 
0004 /* Copyright (c) 2002,2003 CrystalClear Software, Inc.
0005  * Use, modification and distribution is subject to the 
0006  * Boost Software License, Version 1.0. (See accompanying
0007  * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
0008  * Author: Jeff Garland, Bart Garst
0009  * $Date$
0010  */
0011 
0012 
0013 #include "boost/config.hpp"
0014 #include "boost/limits.hpp" //work around compilers without limits
0015 #include "boost/date_time/special_defs.hpp"
0016 #include "boost/date_time/locale_config.hpp"
0017 #ifndef BOOST_DATE_TIME_NO_LOCALE
0018 #  include <ostream>
0019 #endif
0020 
0021 #if defined(BOOST_MSVC)
0022 #pragma warning(push)
0023 // conditional expression is constant
0024 #pragma warning(disable: 4127)
0025 #endif
0026 
0027 namespace boost {
0028 namespace date_time {
0029 
0030 
0031 //! Adapter to create integer types with +-infinity, and not a value
0032 /*! This class is used internally in counted date/time representations.
0033  *  It adds the floating point like features of infinities and
0034  *  not a number. It also provides mathmatical operations with
0035  *  consideration to special values following these rules:
0036  *@code
0037  *  +infinity  -  infinity  == Not A Number (NAN)
0038  *   infinity  *  non-zero  == infinity
0039  *   infinity  *  zero      == NAN
0040  *  +infinity  * -integer   == -infinity
0041  *   infinity  /  infinity  == NAN
0042  *   infinity  *  infinity  == infinity 
0043  *@endcode 
0044  */
0045 template<typename int_type_>
0046 class int_adapter {
0047 public:
0048   typedef int_type_ int_type;
0049   BOOST_CXX14_CONSTEXPR int_adapter(int_type v) :
0050     value_(v)
0051   {}
0052   static BOOST_CONSTEXPR bool has_infinity()
0053   {
0054     return  true;
0055   }
0056   static BOOST_CONSTEXPR int_adapter  pos_infinity()
0057   {
0058     return (::std::numeric_limits<int_type>::max)();
0059   }
0060   static BOOST_CONSTEXPR int_adapter  neg_infinity()
0061   {
0062     return (::std::numeric_limits<int_type>::min)();
0063   }
0064   static BOOST_CONSTEXPR int_adapter  not_a_number()
0065   {
0066     return (::std::numeric_limits<int_type>::max)()-1;
0067   }
0068   static BOOST_CONSTEXPR int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION ()
0069   {
0070     return (::std::numeric_limits<int_type>::max)()-2;
0071   }
0072   static BOOST_CONSTEXPR int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION ()
0073   {
0074     return (::std::numeric_limits<int_type>::min)()+1;
0075   }
0076   static BOOST_CXX14_CONSTEXPR int_adapter from_special(special_values sv)
0077   {
0078     switch (sv) {
0079     case not_a_date_time: return not_a_number();
0080     case neg_infin:       return neg_infinity();
0081     case pos_infin:       return pos_infinity();
0082     case max_date_time:   return (max)();
0083     case min_date_time:   return (min)();
0084     default:              return not_a_number();
0085     }
0086   }
0087   static BOOST_CONSTEXPR bool is_inf(int_type v)
0088   {
0089     return (v == neg_infinity().as_number() ||
0090             v == pos_infinity().as_number());
0091   }
0092   static BOOST_CXX14_CONSTEXPR bool is_neg_inf(int_type v)
0093   {
0094     return (v == neg_infinity().as_number());
0095   }
0096   static BOOST_CXX14_CONSTEXPR bool is_pos_inf(int_type v)
0097   {
0098     return (v == pos_infinity().as_number());
0099   }
0100   static BOOST_CXX14_CONSTEXPR bool is_not_a_number(int_type v)
0101   {
0102     return (v == not_a_number().as_number());
0103   }
0104   //! Returns either special value type or is_not_special
0105   static BOOST_CXX14_CONSTEXPR special_values to_special(int_type v)
0106   {
0107     if (is_not_a_number(v)) return not_a_date_time;
0108     if (is_neg_inf(v)) return neg_infin;
0109     if (is_pos_inf(v)) return pos_infin;
0110     return not_special;
0111   }
0112 
0113   //-3 leaves room for representations of infinity and not a date
0114   static BOOST_CONSTEXPR int_type maxcount()
0115   {
0116     return (::std::numeric_limits<int_type>::max)()-3;
0117   }
0118   BOOST_CONSTEXPR bool is_infinity() const
0119   {
0120     return (value_ == neg_infinity().as_number() ||
0121             value_ == pos_infinity().as_number());
0122   }
0123   BOOST_CONSTEXPR bool is_pos_infinity()const
0124   {
0125     return(value_ == pos_infinity().as_number());
0126   }
0127   BOOST_CONSTEXPR bool is_neg_infinity()const
0128   {
0129     return(value_ == neg_infinity().as_number());
0130   }
0131   BOOST_CONSTEXPR bool is_nan() const
0132   {
0133     return (value_ == not_a_number().as_number());
0134   }
0135   BOOST_CONSTEXPR bool is_special() const
0136   {
0137     return(is_infinity() || is_nan()); 
0138   }
0139   BOOST_CONSTEXPR bool operator==(const int_adapter& rhs) const
0140   {
0141     return (compare(rhs) == 0);
0142   }
0143   BOOST_CXX14_CONSTEXPR bool operator==(const int& rhs) const
0144   {
0145     if(!std::numeric_limits<int_type>::is_signed)
0146     {
0147       if(is_neg_inf(value_) && rhs == 0)
0148       {
0149         return false;
0150       }
0151     }
0152     return (compare(rhs) == 0);
0153   }
0154   BOOST_CONSTEXPR bool operator!=(const int_adapter& rhs) const
0155   {
0156     return (compare(rhs) != 0);
0157   }
0158   BOOST_CXX14_CONSTEXPR bool operator!=(const int& rhs) const
0159   {
0160     if(!std::numeric_limits<int_type>::is_signed)
0161     {
0162       if(is_neg_inf(value_) && rhs == 0)
0163       {
0164         return true;
0165       }
0166     }
0167     return (compare(rhs) != 0);
0168   }
0169   BOOST_CONSTEXPR bool operator<(const int_adapter& rhs) const
0170   {
0171     return (compare(rhs) == -1);
0172   }
0173   BOOST_CXX14_CONSTEXPR bool operator<(const int& rhs) const
0174   {
0175     // quiets compiler warnings
0176     if(!std::numeric_limits<int_type>::is_signed)
0177     {
0178       if(is_neg_inf(value_) && rhs == 0)
0179       {
0180         return true;
0181       }
0182     }
0183     return (compare(rhs) == -1);
0184   }
0185   BOOST_CONSTEXPR bool operator>(const int_adapter& rhs) const
0186   {
0187     return (compare(rhs) == 1);
0188   }
0189   BOOST_CONSTEXPR int_type as_number() const
0190   {
0191     return value_;
0192   }
0193   //! Returns either special value type or is_not_special
0194   BOOST_CONSTEXPR special_values as_special() const
0195   {
0196     return int_adapter::to_special(value_);
0197   }
0198   //creates nasty ambiguities
0199 //   operator int_type() const
0200 //   {
0201 //     return value_;
0202 //   }
0203 
0204   /*! Operator allows for adding dissimilar int_adapter types.
0205    * The return type will match that of the the calling object's type */
0206   template<class rhs_type>
0207   BOOST_CXX14_CONSTEXPR
0208   int_adapter operator+(const int_adapter<rhs_type>& rhs) const
0209   {
0210     if(is_special() || rhs.is_special())
0211     {
0212       if (is_nan() || rhs.is_nan()) 
0213       {
0214         return int_adapter::not_a_number();
0215       }
0216       if((is_pos_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ||
0217       (is_neg_inf(value_) && rhs.is_pos_inf(rhs.as_number())) )
0218       {
0219         return int_adapter::not_a_number();
0220       }
0221       if (is_infinity()) 
0222       {
0223         return *this;
0224       }
0225       if (rhs.is_pos_inf(rhs.as_number())) 
0226       {
0227         return int_adapter::pos_infinity();
0228       }
0229       if (rhs.is_neg_inf(rhs.as_number())) 
0230       {
0231         return int_adapter::neg_infinity();
0232       }
0233     }
0234     return int_adapter<int_type>(value_ + static_cast<int_type>(rhs.as_number()));
0235   }
0236 
0237   BOOST_CXX14_CONSTEXPR
0238   int_adapter operator+(const int_type rhs) const
0239   {
0240     if(is_special())
0241     {
0242       if (is_nan()) 
0243       {
0244         return int_adapter<int_type>(not_a_number());
0245       }
0246       if (is_infinity()) 
0247       {
0248         return *this;
0249       }
0250     }
0251     return int_adapter<int_type>(value_ + rhs);
0252   }
0253   
0254   /*! Operator allows for subtracting dissimilar int_adapter types.
0255    * The return type will match that of the the calling object's type */
0256   template<class rhs_type>
0257   BOOST_CXX14_CONSTEXPR
0258   int_adapter operator-(const int_adapter<rhs_type>& rhs)const
0259   {
0260     if(is_special() || rhs.is_special())
0261     {
0262       if (is_nan() || rhs.is_nan()) 
0263       {
0264         return int_adapter::not_a_number();
0265       }
0266       if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) ||
0267          (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) )
0268       {
0269         return int_adapter::not_a_number();
0270       }
0271       if (is_infinity()) 
0272       {
0273         return *this;
0274       }
0275       if (rhs.is_pos_inf(rhs.as_number())) 
0276       {
0277         return int_adapter::neg_infinity();
0278       }
0279       if (rhs.is_neg_inf(rhs.as_number())) 
0280       {
0281         return int_adapter::pos_infinity();
0282       }
0283     }
0284     return int_adapter<int_type>(value_ - static_cast<int_type>(rhs.as_number()));
0285   }
0286 
0287   BOOST_CXX14_CONSTEXPR
0288   int_adapter operator-(const int_type rhs) const
0289   {
0290     if(is_special())
0291     {
0292       if (is_nan()) 
0293       {
0294         return int_adapter<int_type>(not_a_number());
0295       }
0296       if (is_infinity()) 
0297       {
0298         return *this;
0299       }
0300     }
0301     return int_adapter<int_type>(value_ - rhs);
0302   }
0303 
0304   // should templatize this to be consistant with op +-
0305   BOOST_CXX14_CONSTEXPR
0306   int_adapter operator*(const int_adapter& rhs)const
0307   {
0308     if(this->is_special() || rhs.is_special())
0309     {
0310       return mult_div_specials(rhs);
0311     }
0312     return int_adapter<int_type>(value_ * rhs.value_);
0313   }
0314 
0315   /*! Provided for cases when automatic conversion from 
0316    * 'int' to 'int_adapter' causes incorrect results. */
0317   BOOST_CXX14_CONSTEXPR
0318   int_adapter operator*(const int rhs) const
0319   {
0320     if(is_special())
0321     {
0322       return mult_div_specials(rhs);
0323     }
0324     return int_adapter<int_type>(value_ * rhs);
0325   }
0326 
0327   // should templatize this to be consistant with op +-
0328   BOOST_CXX14_CONSTEXPR
0329   int_adapter operator/(const int_adapter& rhs)const
0330   {
0331     if(this->is_special() || rhs.is_special())
0332     {
0333       if(is_infinity() && rhs.is_infinity())
0334       {
0335         return int_adapter<int_type>(not_a_number());
0336       }
0337       if(rhs != 0)
0338       {
0339         return mult_div_specials(rhs);
0340       }
0341       else { // let divide by zero blow itself up
0342         return int_adapter<int_type>(value_ / rhs.value_); //NOLINT
0343       }
0344     }
0345     return int_adapter<int_type>(value_ / rhs.value_);
0346   }
0347 
0348   /*! Provided for cases when automatic conversion from 
0349    * 'int' to 'int_adapter' causes incorrect results. */
0350   BOOST_CXX14_CONSTEXPR
0351   int_adapter operator/(const int rhs) const
0352   {
0353     if(is_special() && rhs != 0)
0354     {
0355       return mult_div_specials(rhs);
0356     }
0357     // let divide by zero blow itself up like int
0358     return int_adapter<int_type>(value_ / rhs); //NOLINT
0359   }
0360 
0361   // should templatize this to be consistant with op +-
0362   BOOST_CXX14_CONSTEXPR
0363   int_adapter operator%(const int_adapter& rhs)const
0364   {
0365     if(this->is_special() || rhs.is_special())
0366     {
0367       if(is_infinity() && rhs.is_infinity())
0368       {
0369         return int_adapter<int_type>(not_a_number());
0370       }
0371       if(rhs != 0)
0372       {
0373         return mult_div_specials(rhs);
0374       }
0375       else { // let divide by zero blow itself up
0376         return int_adapter<int_type>(value_ % rhs.value_); //NOLINT
0377       }
0378     }
0379     return int_adapter<int_type>(value_ % rhs.value_);
0380   }
0381 
0382   /*! Provided for cases when automatic conversion from 
0383    * 'int' to 'int_adapter' causes incorrect results. */
0384   BOOST_CXX14_CONSTEXPR
0385   int_adapter operator%(const int rhs) const
0386   {
0387     if(is_special() && rhs != 0)
0388     {
0389       return mult_div_specials(rhs);
0390     }
0391     // let divide by zero blow itself up
0392     return int_adapter<int_type>(value_ % rhs); //NOLINT
0393   }
0394 
0395 private:
0396   int_type value_;
0397   
0398   //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs
0399   BOOST_CXX14_CONSTEXPR
0400   int compare( const int_adapter& rhs ) const
0401   {
0402     if(this->is_special() || rhs.is_special())
0403     {
0404       if(this->is_nan() || rhs.is_nan()) {
0405         if(this->is_nan() && rhs.is_nan()) {
0406           return 0; // equal
0407         }
0408         else {
0409           return 2; // nan
0410         }
0411       }
0412       if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) ||
0413          (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) )
0414         {
0415           return -1; // less than
0416         }
0417       if((is_pos_inf(value_) && !is_pos_inf(rhs.value_)) ||
0418          (is_neg_inf(rhs.value_) && !is_neg_inf(value_)) ) {
0419         return 1; // greater than
0420       }
0421     }
0422     if(value_ < rhs.value_) return -1;
0423     if(value_ > rhs.value_) return 1;
0424     // implied-> if(value_ == rhs.value_) 
0425     return 0;
0426   }
0427 
0428   /* When multiplying and dividing with at least 1 special value
0429    * very simmilar rules apply. In those cases where the rules
0430    * are different, they are handled in the respective operator 
0431    * function. */
0432   //! Assumes at least 'this' or 'rhs' is a special value
0433   BOOST_CXX14_CONSTEXPR
0434   int_adapter mult_div_specials(const int_adapter& rhs) const
0435   {
0436     if(this->is_nan() || rhs.is_nan()) {
0437       return int_adapter<int_type>(not_a_number());
0438     }
0439     BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; 
0440     if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) {
0441         return int_adapter<int_type>(pos_infinity());
0442     }
0443     if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) {
0444         return int_adapter<int_type>(neg_infinity());
0445     }
0446     //implied -> if(this->value_ == 0 || rhs.value_ == 0)
0447     return int_adapter<int_type>(not_a_number());
0448   }
0449 
0450   /* Overloaded function necessary because of special
0451    * situation where int_adapter is instantiated with 
0452    * 'unsigned' and func is called with negative int.
0453    * It would produce incorrect results since 'unsigned'
0454    * wraps around when initialized with a negative value */
0455   //! Assumes 'this' is a special value
0456   BOOST_CXX14_CONSTEXPR
0457   int_adapter mult_div_specials(const int& rhs) const
0458   {
0459     if(this->is_nan()) {
0460       return int_adapter<int_type>(not_a_number());
0461     }
0462     BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; 
0463     if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) {
0464         return int_adapter<int_type>(pos_infinity());
0465     }
0466     if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) {
0467         return int_adapter<int_type>(neg_infinity());
0468     }
0469     //implied -> if(this->value_ == 0 || rhs.value_ == 0)
0470     return int_adapter<int_type>(not_a_number());
0471   }
0472 
0473 };
0474 
0475 #ifndef BOOST_DATE_TIME_NO_LOCALE
0476   /*! Expected output is either a numeric representation 
0477    * or a special values representation.<BR> 
0478    * Ex. "12", "+infinity", "not-a-number", etc. */
0479   //template<class charT = char, class traits = std::traits<charT>, typename int_type>
0480   template<class charT, class traits, typename int_type>
0481   inline
0482   std::basic_ostream<charT, traits>& 
0483   operator<<(std::basic_ostream<charT, traits>& os, const int_adapter<int_type>& ia)
0484   {
0485     if(ia.is_special()) {
0486       // switch copied from date_names_put.hpp
0487       switch(ia.as_special())
0488         {
0489       case not_a_date_time:
0490         os << "not-a-number";
0491         break;
0492       case pos_infin:
0493         os << "+infinity";
0494         break;
0495       case neg_infin:
0496         os << "-infinity";
0497         break;
0498       default:
0499         os << "";
0500       }
0501     }
0502     else {
0503       os << ia.as_number(); 
0504     }
0505     return os;
0506   }
0507 #endif
0508 
0509 
0510 } } //namespace date_time
0511 
0512 #if defined(BOOST_MSVC)
0513 #pragma warning(pop)
0514 #endif
0515 
0516 #endif