LCOV - code coverage report
Current view: top level - opt/homebrew/include/boost/date_time - int_adapter.hpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 32 87 36.8 %
Date: 2026-06-25 07:23:43 Functions: 21 48 43.8 %

          Line data    Source code
       1             : #ifndef _DATE_TIME_INT_ADAPTER_HPP__
       2             : #define _DATE_TIME_INT_ADAPTER_HPP__
       3             : 
       4             : /* Copyright (c) 2002,2003 CrystalClear Software, Inc.
       5             :  * Use, modification and distribution is subject to the 
       6             :  * Boost Software License, Version 1.0. (See accompanying
       7             :  * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
       8             :  * Author: Jeff Garland, Bart Garst
       9             :  * $Date$
      10             :  */
      11             : 
      12             : 
      13             : #include "boost/config.hpp"
      14             : #include "boost/limits.hpp" //work around compilers without limits
      15             : #include "boost/date_time/special_defs.hpp"
      16             : #include "boost/date_time/locale_config.hpp"
      17             : #ifndef BOOST_DATE_TIME_NO_LOCALE
      18             : #  include <ostream>
      19             : #endif
      20             : 
      21             : #if defined(BOOST_MSVC)
      22             : #pragma warning(push)
      23             : // conditional expression is constant
      24             : #pragma warning(disable: 4127)
      25             : #endif
      26             : 
      27             : namespace boost {
      28             : namespace date_time {
      29             : 
      30             : 
      31             : //! Adapter to create integer types with +-infinity, and not a value
      32             : /*! This class is used internally in counted date/time representations.
      33             :  *  It adds the floating point like features of infinities and
      34             :  *  not a number. It also provides mathmatical operations with
      35             :  *  consideration to special values following these rules:
      36             :  *@code
      37             :  *  +infinity  -  infinity  == Not A Number (NAN)
      38             :  *   infinity  *  non-zero  == infinity
      39             :  *   infinity  *  zero      == NAN
      40             :  *  +infinity  * -integer   == -infinity
      41             :  *   infinity  /  infinity  == NAN
      42             :  *   infinity  *  infinity  == infinity 
      43             :  *@endcode 
      44             :  */
      45             : template<typename int_type_>
      46             : class int_adapter {
      47             : public:
      48             :   typedef int_type_ int_type;
      49      150618 :   BOOST_CXX14_CONSTEXPR int_adapter(int_type v) :
      50       75309 :     value_(v)
      51      150618 :   {}
      52             :   static BOOST_CONSTEXPR bool has_infinity()
      53             :   {
      54             :     return  true;
      55             :   }
      56       15066 :   static BOOST_CONSTEXPR int_adapter  pos_infinity()
      57             :   {
      58       15066 :     return (::std::numeric_limits<int_type>::max)();
      59             :   }
      60       15066 :   static BOOST_CONSTEXPR int_adapter  neg_infinity()
      61             :   {
      62       15066 :     return (::std::numeric_limits<int_type>::min)();
      63             :   }
      64       30096 :   static BOOST_CONSTEXPR int_adapter  not_a_number()
      65             :   {
      66       30096 :     return (::std::numeric_limits<int_type>::max)()-1;
      67             :   }
      68           0 :   static BOOST_CONSTEXPR int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION ()
      69             :   {
      70           0 :     return (::std::numeric_limits<int_type>::max)()-2;
      71             :   }
      72           0 :   static BOOST_CONSTEXPR int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION ()
      73             :   {
      74           0 :     return (::std::numeric_limits<int_type>::min)()+1;
      75             :   }
      76        7512 :   static BOOST_CXX14_CONSTEXPR int_adapter from_special(special_values sv)
      77             :   {
      78        7512 :     switch (sv) {
      79        7512 :     case not_a_date_time: return not_a_number();
      80           0 :     case neg_infin:       return neg_infinity();
      81           0 :     case pos_infin:       return pos_infinity();
      82           0 :     case max_date_time:   return (max)();
      83           0 :     case min_date_time:   return (min)();
      84           0 :     default:              return not_a_number();
      85             :     }
      86        7512 :   }
      87        5020 :   static BOOST_CONSTEXPR bool is_inf(int_type v)
      88             :   {
      89        5020 :     return (v == neg_infinity().as_number() ||
      90        5020 :             v == pos_infinity().as_number());
      91             :   }
      92           0 :   static BOOST_CXX14_CONSTEXPR bool is_neg_inf(int_type v)
      93             :   {
      94           0 :     return (v == neg_infinity().as_number());
      95             :   }
      96           0 :   static BOOST_CXX14_CONSTEXPR bool is_pos_inf(int_type v)
      97             :   {
      98           0 :     return (v == pos_infinity().as_number());
      99             :   }
     100        7526 :   static BOOST_CXX14_CONSTEXPR bool is_not_a_number(int_type v)
     101             :   {
     102        7526 :     return (v == not_a_number().as_number());
     103             :   }
     104             :   //! Returns either special value type or is_not_special
     105           0 :   static BOOST_CXX14_CONSTEXPR special_values to_special(int_type v)
     106             :   {
     107           0 :     if (is_not_a_number(v)) return not_a_date_time;
     108           0 :     if (is_neg_inf(v)) return neg_infin;
     109           0 :     if (is_pos_inf(v)) return pos_infin;
     110           0 :     return not_special;
     111           0 :   }
     112             : 
     113             :   //-3 leaves room for representations of infinity and not a date
     114             :   static BOOST_CONSTEXPR int_type maxcount()
     115             :   {
     116             :     return (::std::numeric_limits<int_type>::max)()-3;
     117             :   }
     118       10046 :   BOOST_CONSTEXPR bool is_infinity() const
     119             :   {
     120       10046 :     return (value_ == neg_infinity().as_number() ||
     121       10046 :             value_ == pos_infinity().as_number());
     122             :   }
     123             :   BOOST_CONSTEXPR bool is_pos_infinity()const
     124             :   {
     125             :     return(value_ == pos_infinity().as_number());
     126             :   }
     127             :   BOOST_CONSTEXPR bool is_neg_infinity()const
     128             :   {
     129             :     return(value_ == neg_infinity().as_number());
     130             :   }
     131       12552 :   BOOST_CONSTEXPR bool is_nan() const
     132             :   {
     133       12552 :     return (value_ == not_a_number().as_number());
     134             :   }
     135       10046 :   BOOST_CONSTEXPR bool is_special() const
     136             :   {
     137       10046 :     return(is_infinity() || is_nan()); 
     138             :   }
     139             :   BOOST_CONSTEXPR bool operator==(const int_adapter& rhs) const
     140             :   {
     141             :     return (compare(rhs) == 0);
     142             :   }
     143             :   BOOST_CXX14_CONSTEXPR bool operator==(const int& rhs) const
     144             :   {
     145             :     if(!std::numeric_limits<int_type>::is_signed)
     146             :     {
     147             :       if(is_neg_inf(value_) && rhs == 0)
     148             :       {
     149             :         return false;
     150             :       }
     151             :     }
     152             :     return (compare(rhs) == 0);
     153             :   }
     154             :   BOOST_CONSTEXPR bool operator!=(const int_adapter& rhs) const
     155             :   {
     156             :     return (compare(rhs) != 0);
     157             :   }
     158             :   BOOST_CXX14_CONSTEXPR bool operator!=(const int& rhs) const
     159             :   {
     160             :     if(!std::numeric_limits<int_type>::is_signed)
     161             :     {
     162             :       if(is_neg_inf(value_) && rhs == 0)
     163             :       {
     164             :         return true;
     165             :       }
     166             :     }
     167             :     return (compare(rhs) != 0);
     168             :   }
     169             :   BOOST_CONSTEXPR bool operator<(const int_adapter& rhs) const
     170             :   {
     171             :     return (compare(rhs) == -1);
     172             :   }
     173             :   BOOST_CXX14_CONSTEXPR bool operator<(const int& rhs) const
     174             :   {
     175             :     // quiets compiler warnings
     176             :     if(!std::numeric_limits<int_type>::is_signed)
     177             :     {
     178             :       if(is_neg_inf(value_) && rhs == 0)
     179             :       {
     180             :         return true;
     181             :       }
     182             :     }
     183             :     return (compare(rhs) == -1);
     184             :   }
     185             :   BOOST_CONSTEXPR bool operator>(const int_adapter& rhs) const
     186             :   {
     187             :     return (compare(rhs) == 1);
     188             :   }
     189       72761 :   BOOST_CONSTEXPR int_type as_number() const
     190             :   {
     191       72761 :     return value_;
     192             :   }
     193             :   //! Returns either special value type or is_not_special
     194             :   BOOST_CONSTEXPR special_values as_special() const
     195             :   {
     196             :     return int_adapter::to_special(value_);
     197             :   }
     198             :   //creates nasty ambiguities
     199             : //   operator int_type() const
     200             : //   {
     201             : //     return value_;
     202             : //   }
     203             : 
     204             :   /*! Operator allows for adding dissimilar int_adapter types.
     205             :    * The return type will match that of the the calling object's type */
     206             :   template<class rhs_type>
     207             :   BOOST_CXX14_CONSTEXPR
     208        2506 :   int_adapter operator+(const int_adapter<rhs_type>& rhs) const
     209             :   {
     210        2506 :     if(is_special() || rhs.is_special())
     211             :     {
     212        2506 :       if (is_nan() || rhs.is_nan()) 
     213             :       {
     214        2506 :         return int_adapter::not_a_number();
     215             :       }
     216           0 :       if((is_pos_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ||
     217           0 :       (is_neg_inf(value_) && rhs.is_pos_inf(rhs.as_number())) )
     218             :       {
     219           0 :         return int_adapter::not_a_number();
     220             :       }
     221           0 :       if (is_infinity()) 
     222             :       {
     223           0 :         return *this;
     224             :       }
     225           0 :       if (rhs.is_pos_inf(rhs.as_number())) 
     226             :       {
     227           0 :         return int_adapter::pos_infinity();
     228             :       }
     229           0 :       if (rhs.is_neg_inf(rhs.as_number())) 
     230             :       {
     231           0 :         return int_adapter::neg_infinity();
     232             :       }
     233           0 :     }
     234           0 :     return int_adapter<int_type>(value_ + static_cast<int_type>(rhs.as_number()));
     235        2506 :   }
     236             : 
     237             :   BOOST_CXX14_CONSTEXPR
     238           0 :   int_adapter operator+(const int_type rhs) const
     239             :   {
     240           0 :     if(is_special())
     241             :     {
     242           0 :       if (is_nan()) 
     243             :       {
     244           0 :         return int_adapter<int_type>(not_a_number());
     245             :       }
     246           0 :       if (is_infinity()) 
     247             :       {
     248           0 :         return *this;
     249             :       }
     250           0 :     }
     251           0 :     return int_adapter<int_type>(value_ + rhs);
     252           0 :   }
     253             :   
     254             :   /*! Operator allows for subtracting dissimilar int_adapter types.
     255             :    * The return type will match that of the the calling object's type */
     256             :   template<class rhs_type>
     257             :   BOOST_CXX14_CONSTEXPR
     258           0 :   int_adapter operator-(const int_adapter<rhs_type>& rhs)const
     259             :   {
     260           0 :     if(is_special() || rhs.is_special())
     261             :     {
     262           0 :       if (is_nan() || rhs.is_nan()) 
     263             :       {
     264           0 :         return int_adapter::not_a_number();
     265             :       }
     266           0 :       if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) ||
     267           0 :          (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) )
     268             :       {
     269           0 :         return int_adapter::not_a_number();
     270             :       }
     271           0 :       if (is_infinity()) 
     272             :       {
     273           0 :         return *this;
     274             :       }
     275           0 :       if (rhs.is_pos_inf(rhs.as_number())) 
     276             :       {
     277           0 :         return int_adapter::neg_infinity();
     278             :       }
     279           0 :       if (rhs.is_neg_inf(rhs.as_number())) 
     280             :       {
     281           0 :         return int_adapter::pos_infinity();
     282             :       }
     283           0 :     }
     284           0 :     return int_adapter<int_type>(value_ - static_cast<int_type>(rhs.as_number()));
     285           0 :   }
     286             : 
     287             :   BOOST_CXX14_CONSTEXPR
     288             :   int_adapter operator-(const int_type rhs) const
     289             :   {
     290             :     if(is_special())
     291             :     {
     292             :       if (is_nan()) 
     293             :       {
     294             :         return int_adapter<int_type>(not_a_number());
     295             :       }
     296             :       if (is_infinity()) 
     297             :       {
     298             :         return *this;
     299             :       }
     300             :     }
     301             :     return int_adapter<int_type>(value_ - rhs);
     302             :   }
     303             : 
     304             :   // should templatize this to be consistant with op +-
     305             :   BOOST_CXX14_CONSTEXPR
     306             :   int_adapter operator*(const int_adapter& rhs)const
     307             :   {
     308             :     if(this->is_special() || rhs.is_special())
     309             :     {
     310             :       return mult_div_specials(rhs);
     311             :     }
     312             :     return int_adapter<int_type>(value_ * rhs.value_);
     313             :   }
     314             : 
     315             :   /*! Provided for cases when automatic conversion from 
     316             :    * 'int' to 'int_adapter' causes incorrect results. */
     317             :   BOOST_CXX14_CONSTEXPR
     318             :   int_adapter operator*(const int rhs) const
     319             :   {
     320             :     if(is_special())
     321             :     {
     322             :       return mult_div_specials(rhs);
     323             :     }
     324             :     return int_adapter<int_type>(value_ * rhs);
     325             :   }
     326             : 
     327             :   // should templatize this to be consistant with op +-
     328             :   BOOST_CXX14_CONSTEXPR
     329             :   int_adapter operator/(const int_adapter& rhs)const
     330             :   {
     331             :     if(this->is_special() || rhs.is_special())
     332             :     {
     333             :       if(is_infinity() && rhs.is_infinity())
     334             :       {
     335             :         return int_adapter<int_type>(not_a_number());
     336             :       }
     337             :       if(rhs != 0)
     338             :       {
     339             :         return mult_div_specials(rhs);
     340             :       }
     341             :       else { // let divide by zero blow itself up
     342             :         return int_adapter<int_type>(value_ / rhs.value_); //NOLINT
     343             :       }
     344             :     }
     345             :     return int_adapter<int_type>(value_ / rhs.value_);
     346             :   }
     347             : 
     348             :   /*! Provided for cases when automatic conversion from 
     349             :    * 'int' to 'int_adapter' causes incorrect results. */
     350             :   BOOST_CXX14_CONSTEXPR
     351             :   int_adapter operator/(const int rhs) const
     352             :   {
     353             :     if(is_special() && rhs != 0)
     354             :     {
     355             :       return mult_div_specials(rhs);
     356             :     }
     357             :     // let divide by zero blow itself up like int
     358             :     return int_adapter<int_type>(value_ / rhs); //NOLINT
     359             :   }
     360             : 
     361             :   // should templatize this to be consistant with op +-
     362             :   BOOST_CXX14_CONSTEXPR
     363             :   int_adapter operator%(const int_adapter& rhs)const
     364             :   {
     365             :     if(this->is_special() || rhs.is_special())
     366             :     {
     367             :       if(is_infinity() && rhs.is_infinity())
     368             :       {
     369             :         return int_adapter<int_type>(not_a_number());
     370             :       }
     371             :       if(rhs != 0)
     372             :       {
     373             :         return mult_div_specials(rhs);
     374             :       }
     375             :       else { // let divide by zero blow itself up
     376             :         return int_adapter<int_type>(value_ % rhs.value_); //NOLINT
     377             :       }
     378             :     }
     379             :     return int_adapter<int_type>(value_ % rhs.value_);
     380             :   }
     381             : 
     382             :   /*! Provided for cases when automatic conversion from 
     383             :    * 'int' to 'int_adapter' causes incorrect results. */
     384             :   BOOST_CXX14_CONSTEXPR
     385             :   int_adapter operator%(const int rhs) const
     386             :   {
     387             :     if(is_special() && rhs != 0)
     388             :     {
     389             :       return mult_div_specials(rhs);
     390             :     }
     391             :     // let divide by zero blow itself up
     392             :     return int_adapter<int_type>(value_ % rhs); //NOLINT
     393             :   }
     394             : 
     395             : private:
     396             :   int_type value_;
     397             :   
     398             :   //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs
     399             :   BOOST_CXX14_CONSTEXPR
     400             :   int compare( const int_adapter& rhs ) const
     401             :   {
     402             :     if(this->is_special() || rhs.is_special())
     403             :     {
     404             :       if(this->is_nan() || rhs.is_nan()) {
     405             :         if(this->is_nan() && rhs.is_nan()) {
     406             :           return 0; // equal
     407             :         }
     408             :         else {
     409             :           return 2; // nan
     410             :         }
     411             :       }
     412             :       if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) ||
     413             :          (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) )
     414             :         {
     415             :           return -1; // less than
     416             :         }
     417             :       if((is_pos_inf(value_) && !is_pos_inf(rhs.value_)) ||
     418             :          (is_neg_inf(rhs.value_) && !is_neg_inf(value_)) ) {
     419             :         return 1; // greater than
     420             :       }
     421             :     }
     422             :     if(value_ < rhs.value_) return -1;
     423             :     if(value_ > rhs.value_) return 1;
     424             :     // implied-> if(value_ == rhs.value_) 
     425             :     return 0;
     426             :   }
     427             : 
     428             :   /* When multiplying and dividing with at least 1 special value
     429             :    * very simmilar rules apply. In those cases where the rules
     430             :    * are different, they are handled in the respective operator 
     431             :    * function. */
     432             :   //! Assumes at least 'this' or 'rhs' is a special value
     433             :   BOOST_CXX14_CONSTEXPR
     434             :   int_adapter mult_div_specials(const int_adapter& rhs) const
     435             :   {
     436             :     if(this->is_nan() || rhs.is_nan()) {
     437             :       return int_adapter<int_type>(not_a_number());
     438             :     }
     439             :     BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; 
     440             :     if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) {
     441             :         return int_adapter<int_type>(pos_infinity());
     442             :     }
     443             :     if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) {
     444             :         return int_adapter<int_type>(neg_infinity());
     445             :     }
     446             :     //implied -> if(this->value_ == 0 || rhs.value_ == 0)
     447             :     return int_adapter<int_type>(not_a_number());
     448             :   }
     449             : 
     450             :   /* Overloaded function necessary because of special
     451             :    * situation where int_adapter is instantiated with 
     452             :    * 'unsigned' and func is called with negative int.
     453             :    * It would produce incorrect results since 'unsigned'
     454             :    * wraps around when initialized with a negative value */
     455             :   //! Assumes 'this' is a special value
     456             :   BOOST_CXX14_CONSTEXPR
     457             :   int_adapter mult_div_specials(const int& rhs) const
     458             :   {
     459             :     if(this->is_nan()) {
     460             :       return int_adapter<int_type>(not_a_number());
     461             :     }
     462             :     BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; 
     463             :     if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) {
     464             :         return int_adapter<int_type>(pos_infinity());
     465             :     }
     466             :     if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) {
     467             :         return int_adapter<int_type>(neg_infinity());
     468             :     }
     469             :     //implied -> if(this->value_ == 0 || rhs.value_ == 0)
     470             :     return int_adapter<int_type>(not_a_number());
     471             :   }
     472             : 
     473             : };
     474             : 
     475             : #ifndef BOOST_DATE_TIME_NO_LOCALE
     476             :   /*! Expected output is either a numeric representation 
     477             :    * or a special values representation.<BR> 
     478             :    * Ex. "12", "+infinity", "not-a-number", etc. */
     479             :   //template<class charT = char, class traits = std::traits<charT>, typename int_type>
     480             :   template<class charT, class traits, typename int_type>
     481             :   inline
     482             :   std::basic_ostream<charT, traits>& 
     483             :   operator<<(std::basic_ostream<charT, traits>& os, const int_adapter<int_type>& ia)
     484             :   {
     485             :     if(ia.is_special()) {
     486             :       // switch copied from date_names_put.hpp
     487             :       switch(ia.as_special())
     488             :         {
     489             :       case not_a_date_time:
     490             :         os << "not-a-number";
     491             :         break;
     492             :       case pos_infin:
     493             :         os << "+infinity";
     494             :         break;
     495             :       case neg_infin:
     496             :         os << "-infinity";
     497             :         break;
     498             :       default:
     499             :         os << "";
     500             :       }
     501             :     }
     502             :     else {
     503             :       os << ia.as_number(); 
     504             :     }
     505             :     return os;
     506             :   }
     507             : #endif
     508             : 
     509             : 
     510             : } } //namespace date_time
     511             : 
     512             : #if defined(BOOST_MSVC)
     513             : #pragma warning(pop)
     514             : #endif
     515             : 
     516             : #endif

Generated by: LCOV version 1.16