Chris@16: #ifndef _DATE_TIME_INT_ADAPTER_HPP__ Chris@16: #define _DATE_TIME_INT_ADAPTER_HPP__ Chris@16: Chris@16: /* Copyright (c) 2002,2003 CrystalClear Software, Inc. Chris@16: * Use, modification and distribution is subject to the Chris@16: * Boost Software License, Version 1.0. (See accompanying Chris@16: * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Author: Jeff Garland, Bart Garst Chris@101: * $Date$ Chris@16: */ Chris@16: Chris@16: Chris@16: #include "boost/config.hpp" Chris@16: #include "boost/limits.hpp" //work around compilers without limits Chris@16: #include "boost/date_time/special_defs.hpp" Chris@16: #include "boost/date_time/locale_config.hpp" Chris@16: #ifndef BOOST_DATE_TIME_NO_LOCALE Chris@16: # include Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: namespace date_time { Chris@16: Chris@16: Chris@16: //! Adapter to create integer types with +-infinity, and not a value Chris@16: /*! This class is used internally in counted date/time representations. Chris@16: * It adds the floating point like features of infinities and Chris@16: * not a number. It also provides mathmatical operations with Chris@16: * consideration to special values following these rules: Chris@16: *@code Chris@16: * +infinity - infinity == Not A Number (NAN) Chris@16: * infinity * non-zero == infinity Chris@16: * infinity * zero == NAN Chris@16: * +infinity * -integer == -infinity Chris@16: * infinity / infinity == NAN Chris@16: * infinity * infinity == infinity Chris@16: *@endcode Chris@16: */ Chris@16: template Chris@16: class int_adapter { Chris@16: public: Chris@16: typedef int_type_ int_type; Chris@16: int_adapter(int_type v) : Chris@16: value_(v) Chris@16: {} Chris@16: static bool has_infinity() Chris@16: { Chris@16: return true; Chris@16: } Chris@16: static const int_adapter pos_infinity() Chris@16: { Chris@16: return (::std::numeric_limits::max)(); Chris@16: } Chris@16: static const int_adapter neg_infinity() Chris@16: { Chris@16: return (::std::numeric_limits::min)(); Chris@16: } Chris@16: static const int_adapter not_a_number() Chris@16: { Chris@16: return (::std::numeric_limits::max)()-1; Chris@16: } Chris@16: static int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION () Chris@16: { Chris@16: return (::std::numeric_limits::max)()-2; Chris@16: } Chris@16: static int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION () Chris@16: { Chris@16: return (::std::numeric_limits::min)()+1; Chris@16: } Chris@16: static int_adapter from_special(special_values sv) Chris@16: { Chris@16: switch (sv) { Chris@16: case not_a_date_time: return not_a_number(); Chris@16: case neg_infin: return neg_infinity(); Chris@16: case pos_infin: return pos_infinity(); Chris@16: case max_date_time: return (max)(); Chris@16: case min_date_time: return (min)(); Chris@16: default: return not_a_number(); Chris@16: } Chris@16: } Chris@16: static bool is_inf(int_type v) Chris@16: { Chris@16: return (v == neg_infinity().as_number() || Chris@16: v == pos_infinity().as_number()); Chris@16: } Chris@16: static bool is_neg_inf(int_type v) Chris@16: { Chris@16: return (v == neg_infinity().as_number()); Chris@16: } Chris@16: static bool is_pos_inf(int_type v) Chris@16: { Chris@16: return (v == pos_infinity().as_number()); Chris@16: } Chris@16: static bool is_not_a_number(int_type v) Chris@16: { Chris@16: return (v == not_a_number().as_number()); Chris@16: } Chris@16: //! Returns either special value type or is_not_special Chris@16: static special_values to_special(int_type v) Chris@16: { Chris@16: if (is_not_a_number(v)) return not_a_date_time; Chris@16: if (is_neg_inf(v)) return neg_infin; Chris@16: if (is_pos_inf(v)) return pos_infin; Chris@16: return not_special; Chris@16: } Chris@16: Chris@16: //-3 leaves room for representations of infinity and not a date Chris@16: static int_type maxcount() Chris@16: { Chris@16: return (::std::numeric_limits::max)()-3; Chris@16: } Chris@16: bool is_infinity() const Chris@16: { Chris@16: return (value_ == neg_infinity().as_number() || Chris@16: value_ == pos_infinity().as_number()); Chris@16: } Chris@16: bool is_pos_infinity()const Chris@16: { Chris@16: return(value_ == pos_infinity().as_number()); Chris@16: } Chris@16: bool is_neg_infinity()const Chris@16: { Chris@16: return(value_ == neg_infinity().as_number()); Chris@16: } Chris@16: bool is_nan() const Chris@16: { Chris@16: return (value_ == not_a_number().as_number()); Chris@16: } Chris@16: bool is_special() const Chris@16: { Chris@16: return(is_infinity() || is_nan()); Chris@16: } Chris@16: bool operator==(const int_adapter& rhs) const Chris@16: { Chris@16: return (compare(rhs) == 0); Chris@16: } Chris@16: bool operator==(const int& rhs) const Chris@16: { Chris@16: // quiets compiler warnings Chris@16: bool is_signed = std::numeric_limits::is_signed; Chris@16: if(!is_signed) Chris@16: { Chris@16: if(is_neg_inf(value_) && rhs == 0) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: return (compare(rhs) == 0); Chris@16: } Chris@16: bool operator!=(const int_adapter& rhs) const Chris@16: { Chris@16: return (compare(rhs) != 0); Chris@16: } Chris@16: bool operator!=(const int& rhs) const Chris@16: { Chris@16: // quiets compiler warnings Chris@16: bool is_signed = std::numeric_limits::is_signed; Chris@16: if(!is_signed) Chris@16: { Chris@16: if(is_neg_inf(value_) && rhs == 0) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: } Chris@16: return (compare(rhs) != 0); Chris@16: } Chris@16: bool operator<(const int_adapter& rhs) const Chris@16: { Chris@16: return (compare(rhs) == -1); Chris@16: } Chris@16: bool operator<(const int& rhs) const Chris@16: { Chris@16: // quiets compiler warnings Chris@16: bool is_signed = std::numeric_limits::is_signed; Chris@16: if(!is_signed) Chris@16: { Chris@16: if(is_neg_inf(value_) && rhs == 0) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: } Chris@16: return (compare(rhs) == -1); Chris@16: } Chris@16: bool operator>(const int_adapter& rhs) const Chris@16: { Chris@16: return (compare(rhs) == 1); Chris@16: } Chris@16: int_type as_number() const Chris@16: { Chris@16: return value_; Chris@16: } Chris@16: //! Returns either special value type or is_not_special Chris@16: special_values as_special() const Chris@16: { Chris@16: return int_adapter::to_special(value_); Chris@16: } Chris@16: //creates nasty ambiguities Chris@16: // operator int_type() const Chris@16: // { Chris@16: // return value_; Chris@16: // } Chris@16: Chris@16: /*! Operator allows for adding dissimilar int_adapter types. Chris@16: * The return type will match that of the the calling object's type */ Chris@16: template Chris@16: inline Chris@16: int_adapter operator+(const int_adapter& rhs) const Chris@16: { Chris@16: if(is_special() || rhs.is_special()) Chris@16: { Chris@16: if (is_nan() || rhs.is_nan()) Chris@16: { Chris@16: return int_adapter::not_a_number(); Chris@16: } Chris@16: if((is_pos_inf(value_) && rhs.is_neg_inf(rhs.as_number())) || Chris@16: (is_neg_inf(value_) && rhs.is_pos_inf(rhs.as_number())) ) Chris@16: { Chris@16: return int_adapter::not_a_number(); Chris@16: } Chris@16: if (is_infinity()) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: if (rhs.is_pos_inf(rhs.as_number())) Chris@16: { Chris@16: return int_adapter::pos_infinity(); Chris@16: } Chris@16: if (rhs.is_neg_inf(rhs.as_number())) Chris@16: { Chris@16: return int_adapter::neg_infinity(); Chris@16: } Chris@16: } Chris@16: return int_adapter(value_ + rhs.as_number()); Chris@16: } Chris@16: Chris@16: int_adapter operator+(const int_type rhs) const Chris@16: { Chris@16: if(is_special()) Chris@16: { Chris@16: if (is_nan()) Chris@16: { Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: if (is_infinity()) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: } Chris@16: return int_adapter(value_ + rhs); Chris@16: } Chris@16: Chris@16: /*! Operator allows for subtracting dissimilar int_adapter types. Chris@16: * The return type will match that of the the calling object's type */ Chris@16: template Chris@16: inline Chris@16: int_adapter operator-(const int_adapter& rhs)const Chris@16: { Chris@16: if(is_special() || rhs.is_special()) Chris@16: { Chris@16: if (is_nan() || rhs.is_nan()) Chris@16: { Chris@16: return int_adapter::not_a_number(); Chris@16: } Chris@16: if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) || Chris@16: (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ) Chris@16: { Chris@16: return int_adapter::not_a_number(); Chris@16: } Chris@16: if (is_infinity()) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: if (rhs.is_pos_inf(rhs.as_number())) Chris@16: { Chris@16: return int_adapter::neg_infinity(); Chris@16: } Chris@16: if (rhs.is_neg_inf(rhs.as_number())) Chris@16: { Chris@16: return int_adapter::pos_infinity(); Chris@16: } Chris@16: } Chris@16: return int_adapter(value_ - rhs.as_number()); Chris@16: } Chris@16: int_adapter operator-(const int_type rhs) const Chris@16: { Chris@16: if(is_special()) Chris@16: { Chris@16: if (is_nan()) Chris@16: { Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: if (is_infinity()) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: } Chris@16: return int_adapter(value_ - rhs); Chris@16: } Chris@16: Chris@16: // should templatize this to be consistant with op +- Chris@16: int_adapter operator*(const int_adapter& rhs)const Chris@16: { Chris@16: if(this->is_special() || rhs.is_special()) Chris@16: { Chris@16: return mult_div_specials(rhs); Chris@16: } Chris@16: return int_adapter(value_ * rhs.value_); Chris@16: } Chris@16: /*! Provided for cases when automatic conversion from Chris@16: * 'int' to 'int_adapter' causes incorrect results. */ Chris@16: int_adapter operator*(const int rhs) const Chris@16: { Chris@16: if(is_special()) Chris@16: { Chris@16: return mult_div_specials(rhs); Chris@16: } Chris@16: return int_adapter(value_ * rhs); Chris@16: } Chris@16: Chris@16: // should templatize this to be consistant with op +- Chris@16: int_adapter operator/(const int_adapter& rhs)const Chris@16: { Chris@16: if(this->is_special() || rhs.is_special()) Chris@16: { Chris@16: if(is_infinity() && rhs.is_infinity()) Chris@16: { Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: if(rhs != 0) Chris@16: { Chris@16: return mult_div_specials(rhs); Chris@16: } Chris@16: else { // let divide by zero blow itself up Chris@16: return int_adapter(value_ / rhs.value_); Chris@16: } Chris@16: } Chris@16: return int_adapter(value_ / rhs.value_); Chris@16: } Chris@16: /*! Provided for cases when automatic conversion from Chris@16: * 'int' to 'int_adapter' causes incorrect results. */ Chris@16: int_adapter operator/(const int rhs) const Chris@16: { Chris@16: if(is_special() && rhs != 0) Chris@16: { Chris@16: return mult_div_specials(rhs); Chris@16: } Chris@16: return int_adapter(value_ / rhs); Chris@16: } Chris@16: Chris@16: // should templatize this to be consistant with op +- Chris@16: int_adapter operator%(const int_adapter& rhs)const Chris@16: { Chris@16: if(this->is_special() || rhs.is_special()) Chris@16: { Chris@16: if(is_infinity() && rhs.is_infinity()) Chris@16: { Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: if(rhs != 0) Chris@16: { Chris@16: return mult_div_specials(rhs); Chris@16: } Chris@16: else { // let divide by zero blow itself up Chris@16: return int_adapter(value_ % rhs.value_); Chris@16: } Chris@16: } Chris@16: return int_adapter(value_ % rhs.value_); Chris@16: } Chris@16: /*! Provided for cases when automatic conversion from Chris@16: * 'int' to 'int_adapter' causes incorrect results. */ Chris@16: int_adapter operator%(const int rhs) const Chris@16: { Chris@16: if(is_special() && rhs != 0) Chris@16: { Chris@16: return mult_div_specials(rhs); Chris@16: } Chris@16: return int_adapter(value_ % rhs); Chris@16: } Chris@16: private: Chris@16: int_type value_; Chris@16: Chris@16: //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs Chris@16: int compare(const int_adapter& rhs)const Chris@16: { Chris@16: if(this->is_special() || rhs.is_special()) Chris@16: { Chris@16: if(this->is_nan() || rhs.is_nan()) { Chris@16: if(this->is_nan() && rhs.is_nan()) { Chris@16: return 0; // equal Chris@16: } Chris@16: else { Chris@16: return 2; // nan Chris@16: } Chris@16: } Chris@16: if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) || Chris@16: (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) ) Chris@16: { Chris@16: return -1; // less than Chris@16: } Chris@16: if((is_pos_inf(value_) && !is_pos_inf(rhs.value_)) || Chris@16: (is_neg_inf(rhs.value_) && !is_neg_inf(value_)) ) { Chris@16: return 1; // greater than Chris@16: } Chris@16: } Chris@16: if(value_ < rhs.value_) return -1; Chris@16: if(value_ > rhs.value_) return 1; Chris@16: // implied-> if(value_ == rhs.value_) Chris@16: return 0; Chris@16: } Chris@16: /* When multiplying and dividing with at least 1 special value Chris@16: * very simmilar rules apply. In those cases where the rules Chris@16: * are different, they are handled in the respective operator Chris@16: * function. */ Chris@16: //! Assumes at least 'this' or 'rhs' is a special value Chris@16: int_adapter mult_div_specials(const int_adapter& rhs)const Chris@16: { Chris@16: int min_value; Chris@16: // quiets compiler warnings Chris@16: bool is_signed = std::numeric_limits::is_signed; Chris@16: if(is_signed) { Chris@16: min_value = 0; Chris@16: } Chris@16: else { Chris@16: min_value = 1;// there is no zero with unsigned Chris@16: } Chris@16: if(this->is_nan() || rhs.is_nan()) { Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) { Chris@16: return int_adapter(pos_infinity()); Chris@16: } Chris@16: if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) { Chris@16: return int_adapter(neg_infinity()); Chris@16: } Chris@16: //implied -> if(this->value_ == 0 || rhs.value_ == 0) Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: /* Overloaded function necessary because of special Chris@16: * situation where int_adapter is instantiated with Chris@16: * 'unsigned' and func is called with negative int. Chris@16: * It would produce incorrect results since 'unsigned' Chris@16: * wraps around when initialized with a negative value */ Chris@16: //! Assumes 'this' is a special value Chris@16: int_adapter mult_div_specials(const int& rhs) const Chris@16: { Chris@16: int min_value; Chris@16: // quiets compiler warnings Chris@16: bool is_signed = std::numeric_limits::is_signed; Chris@16: if(is_signed) { Chris@16: min_value = 0; Chris@16: } Chris@16: else { Chris@16: min_value = 1;// there is no zero with unsigned Chris@16: } Chris@16: if(this->is_nan()) { Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) { Chris@16: return int_adapter(pos_infinity()); Chris@16: } Chris@16: if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) { Chris@16: return int_adapter(neg_infinity()); Chris@16: } Chris@16: //implied -> if(this->value_ == 0 || rhs.value_ == 0) Chris@16: return int_adapter(not_a_number()); Chris@16: } Chris@16: Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_DATE_TIME_NO_LOCALE Chris@16: /*! Expected output is either a numeric representation Chris@16: * or a special values representation.
Chris@16: * Ex. "12", "+infinity", "not-a-number", etc. */ Chris@16: //template, typename int_type> Chris@16: template Chris@16: inline Chris@16: std::basic_ostream& Chris@16: operator<<(std::basic_ostream& os, const int_adapter& ia) Chris@16: { Chris@16: if(ia.is_special()) { Chris@16: // switch copied from date_names_put.hpp Chris@16: switch(ia.as_special()) Chris@16: { Chris@16: case not_a_date_time: Chris@16: os << "not-a-number"; Chris@16: break; Chris@16: case pos_infin: Chris@16: os << "+infinity"; Chris@16: break; Chris@16: case neg_infin: Chris@16: os << "-infinity"; Chris@16: break; Chris@16: default: Chris@16: os << ""; Chris@16: } Chris@16: } Chris@16: else { Chris@16: os << ia.as_number(); Chris@16: } Chris@16: return os; Chris@16: } Chris@16: #endif Chris@16: Chris@16: Chris@16: } } //namespace date_time Chris@16: Chris@16: Chris@16: Chris@16: #endif