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