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