1 #ifndef _DATE_TIME_INT_ADAPTER_HPP__
2 #define _DATE_TIME_INT_ADAPTER_HPP__
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
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
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:
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
39 template<typename int_type_>
42 typedef int_type_ int_type;
43 int_adapter(int_type v) :
46 static bool has_infinity()
50 static const int_adapter pos_infinity()
52 return (::std::numeric_limits<int_type>::max)();
54 static const int_adapter neg_infinity()
56 return (::std::numeric_limits<int_type>::min)();
58 static const int_adapter not_a_number()
60 return (::std::numeric_limits<int_type>::max)()-1;
62 static int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION ()
64 return (::std::numeric_limits<int_type>::max)()-2;
66 static int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION ()
68 return (::std::numeric_limits<int_type>::min)()+1;
70 static int_adapter from_special(special_values 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();
81 static bool is_inf(int_type v)
83 return (v == neg_infinity().as_number() ||
84 v == pos_infinity().as_number());
86 static bool is_neg_inf(int_type v)
88 return (v == neg_infinity().as_number());
90 static bool is_pos_inf(int_type v)
92 return (v == pos_infinity().as_number());
94 static bool is_not_a_number(int_type v)
96 return (v == not_a_number().as_number());
98 //! Returns either special value type or is_not_special
99 static special_values to_special(int_type v)
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;
107 //-3 leaves room for representations of infinity and not a date
108 static int_type maxcount()
110 return (::std::numeric_limits<int_type>::max)()-3;
112 bool is_infinity() const
114 return (value_ == neg_infinity().as_number() ||
115 value_ == pos_infinity().as_number());
117 bool is_pos_infinity()const
119 return(value_ == pos_infinity().as_number());
121 bool is_neg_infinity()const
123 return(value_ == neg_infinity().as_number());
127 return (value_ == not_a_number().as_number());
129 bool is_special() const
131 return(is_infinity() || is_nan());
133 bool operator==(const int_adapter& rhs) const
135 return (compare(rhs) == 0);
137 bool operator==(const int& rhs) const
139 // quiets compiler warnings
140 bool is_signed = std::numeric_limits<int_type>::is_signed;
143 if(is_neg_inf(value_) && rhs == 0)
148 return (compare(rhs) == 0);
150 bool operator!=(const int_adapter& rhs) const
152 return (compare(rhs) != 0);
154 bool operator!=(const int& rhs) const
156 // quiets compiler warnings
157 bool is_signed = std::numeric_limits<int_type>::is_signed;
160 if(is_neg_inf(value_) && rhs == 0)
165 return (compare(rhs) != 0);
167 bool operator<(const int_adapter& rhs) const
169 return (compare(rhs) == -1);
171 bool operator<(const int& rhs) const
173 // quiets compiler warnings
174 bool is_signed = std::numeric_limits<int_type>::is_signed;
177 if(is_neg_inf(value_) && rhs == 0)
182 return (compare(rhs) == -1);
184 bool operator>(const int_adapter& rhs) const
186 return (compare(rhs) == 1);
188 int_type as_number() const
192 //! Returns either special value type or is_not_special
193 special_values as_special() const
195 return int_adapter::to_special(value_);
197 //creates nasty ambiguities
198 // operator int_type() const
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>
207 int_adapter operator+(const int_adapter<rhs_type>& rhs) const
209 if(is_special() || rhs.is_special())
211 if (is_nan() || rhs.is_nan())
213 return int_adapter::not_a_number();
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())) )
218 return int_adapter::not_a_number();
224 if (rhs.is_pos_inf(rhs.as_number()))
226 return int_adapter::pos_infinity();
228 if (rhs.is_neg_inf(rhs.as_number()))
230 return int_adapter::neg_infinity();
233 return int_adapter<int_type>(value_ + static_cast<int_type>(rhs.as_number()));
236 int_adapter operator+(const int_type rhs) const
242 return int_adapter<int_type>(not_a_number());
249 return int_adapter<int_type>(value_ + rhs);
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>
256 int_adapter operator-(const int_adapter<rhs_type>& rhs)const
258 if(is_special() || rhs.is_special())
260 if (is_nan() || rhs.is_nan())
262 return int_adapter::not_a_number();
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())) )
267 return int_adapter::not_a_number();
273 if (rhs.is_pos_inf(rhs.as_number()))
275 return int_adapter::neg_infinity();
277 if (rhs.is_neg_inf(rhs.as_number()))
279 return int_adapter::pos_infinity();
282 return int_adapter<int_type>(value_ - static_cast<int_type>(rhs.as_number()));
284 int_adapter operator-(const int_type rhs) const
290 return int_adapter<int_type>(not_a_number());
297 return int_adapter<int_type>(value_ - rhs);
300 // should templatize this to be consistant with op +-
301 int_adapter operator*(const int_adapter& rhs)const
303 if(this->is_special() || rhs.is_special())
305 return mult_div_specials(rhs);
307 return int_adapter<int_type>(value_ * rhs.value_);
309 /*! Provided for cases when automatic conversion from
310 * 'int' to 'int_adapter' causes incorrect results. */
311 int_adapter operator*(const int rhs) const
315 return mult_div_specials(rhs);
317 return int_adapter<int_type>(value_ * rhs);
320 // should templatize this to be consistant with op +-
321 int_adapter operator/(const int_adapter& rhs)const
323 if(this->is_special() || rhs.is_special())
325 if(is_infinity() && rhs.is_infinity())
327 return int_adapter<int_type>(not_a_number());
331 return mult_div_specials(rhs);
333 else { // let divide by zero blow itself up
334 return int_adapter<int_type>(value_ / rhs.value_);
337 return int_adapter<int_type>(value_ / rhs.value_);
339 /*! Provided for cases when automatic conversion from
340 * 'int' to 'int_adapter' causes incorrect results. */
341 int_adapter operator/(const int rhs) const
343 if(is_special() && rhs != 0)
345 return mult_div_specials(rhs);
347 return int_adapter<int_type>(value_ / rhs);
350 // should templatize this to be consistant with op +-
351 int_adapter operator%(const int_adapter& rhs)const
353 if(this->is_special() || rhs.is_special())
355 if(is_infinity() && rhs.is_infinity())
357 return int_adapter<int_type>(not_a_number());
361 return mult_div_specials(rhs);
363 else { // let divide by zero blow itself up
364 return int_adapter<int_type>(value_ % rhs.value_);
367 return int_adapter<int_type>(value_ % rhs.value_);
369 /*! Provided for cases when automatic conversion from
370 * 'int' to 'int_adapter' causes incorrect results. */
371 int_adapter operator%(const int rhs) const
373 if(is_special() && rhs != 0)
375 return mult_div_specials(rhs);
377 return int_adapter<int_type>(value_ % rhs);
382 //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs
383 int compare(const int_adapter& rhs)const
385 if(this->is_special() || rhs.is_special())
387 if(this->is_nan() || rhs.is_nan()) {
388 if(this->is_nan() && rhs.is_nan()) {
395 if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) ||
396 (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) )
398 return -1; // less than
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
405 if(value_ < rhs.value_) return -1;
406 if(value_ > rhs.value_) return 1;
407 // implied-> if(value_ == rhs.value_)
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
414 //! Assumes at least 'this' or 'rhs' is a special value
415 int_adapter mult_div_specials(const int_adapter& rhs)const
418 // quiets compiler warnings
419 bool is_signed = std::numeric_limits<int_type>::is_signed;
424 min_value = 1;// there is no zero with unsigned
426 if(this->is_nan() || rhs.is_nan()) {
427 return int_adapter<int_type>(not_a_number());
429 if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) {
430 return int_adapter<int_type>(pos_infinity());
432 if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) {
433 return int_adapter<int_type>(neg_infinity());
435 //implied -> if(this->value_ == 0 || rhs.value_ == 0)
436 return int_adapter<int_type>(not_a_number());
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
447 // quiets compiler warnings
448 bool is_signed = std::numeric_limits<int_type>::is_signed;
453 min_value = 1;// there is no zero with unsigned
456 return int_adapter<int_type>(not_a_number());
458 if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) {
459 return int_adapter<int_type>(pos_infinity());
461 if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) {
462 return int_adapter<int_type>(neg_infinity());
464 //implied -> if(this->value_ == 0 || rhs.value_ == 0)
465 return int_adapter<int_type>(not_a_number());
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>
477 std::basic_ostream<charT, traits>&
478 operator<<(std::basic_ostream<charT, traits>& os, const int_adapter<int_type>& ia)
480 if(ia.is_special()) {
481 // switch copied from date_names_put.hpp
482 switch(ia.as_special())
484 case not_a_date_time:
485 os << "not-a-number";
498 os << ia.as_number();
505 } } //namespace date_time