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
21 #if defined(BOOST_MSVC)
23 // conditional expression is constant
24 #pragma warning(disable: 4127)
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:
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
45 template<typename int_type_>
48 typedef int_type_ int_type;
49 int_adapter(int_type v) :
52 static bool has_infinity()
56 static const int_adapter pos_infinity()
58 return (::std::numeric_limits<int_type>::max)();
60 static const int_adapter neg_infinity()
62 return (::std::numeric_limits<int_type>::min)();
64 static const int_adapter not_a_number()
66 return (::std::numeric_limits<int_type>::max)()-1;
68 static int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION ()
70 return (::std::numeric_limits<int_type>::max)()-2;
72 static int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION ()
74 return (::std::numeric_limits<int_type>::min)()+1;
76 static int_adapter from_special(special_values sv)
79 case not_a_date_time: return not_a_number();
80 case neg_infin: return neg_infinity();
81 case pos_infin: return pos_infinity();
82 case max_date_time: return (max)();
83 case min_date_time: return (min)();
84 default: return not_a_number();
87 static bool is_inf(int_type v)
89 return (v == neg_infinity().as_number() ||
90 v == pos_infinity().as_number());
92 static bool is_neg_inf(int_type v)
94 return (v == neg_infinity().as_number());
96 static bool is_pos_inf(int_type v)
98 return (v == pos_infinity().as_number());
100 static bool is_not_a_number(int_type v)
102 return (v == not_a_number().as_number());
104 //! Returns either special value type or is_not_special
105 static special_values to_special(int_type v)
107 if (is_not_a_number(v)) return not_a_date_time;
108 if (is_neg_inf(v)) return neg_infin;
109 if (is_pos_inf(v)) return pos_infin;
113 //-3 leaves room for representations of infinity and not a date
114 static int_type maxcount()
116 return (::std::numeric_limits<int_type>::max)()-3;
118 bool is_infinity() const
120 return (value_ == neg_infinity().as_number() ||
121 value_ == pos_infinity().as_number());
123 bool is_pos_infinity()const
125 return(value_ == pos_infinity().as_number());
127 bool is_neg_infinity()const
129 return(value_ == neg_infinity().as_number());
133 return (value_ == not_a_number().as_number());
135 bool is_special() const
137 return(is_infinity() || is_nan());
139 bool operator==(const int_adapter& rhs) const
141 return (compare(rhs) == 0);
143 bool operator==(const int& rhs) const
145 if(!std::numeric_limits<int_type>::is_signed)
147 if(is_neg_inf(value_) && rhs == 0)
152 return (compare(rhs) == 0);
154 bool operator!=(const int_adapter& rhs) const
156 return (compare(rhs) != 0);
158 bool operator!=(const int& rhs) const
160 if(!std::numeric_limits<int_type>::is_signed)
162 if(is_neg_inf(value_) && rhs == 0)
167 return (compare(rhs) != 0);
169 bool operator<(const int_adapter& rhs) const
171 return (compare(rhs) == -1);
173 bool operator<(const int& rhs) const
175 // quiets compiler warnings
176 if(!std::numeric_limits<int_type>::is_signed)
178 if(is_neg_inf(value_) && rhs == 0)
183 return (compare(rhs) == -1);
185 bool operator>(const int_adapter& rhs) const
187 return (compare(rhs) == 1);
189 int_type as_number() const
193 //! Returns either special value type or is_not_special
194 special_values as_special() const
196 return int_adapter::to_special(value_);
198 //creates nasty ambiguities
199 // operator int_type() const
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>
208 int_adapter operator+(const int_adapter<rhs_type>& rhs) const
210 if(is_special() || rhs.is_special())
212 if (is_nan() || rhs.is_nan())
214 return int_adapter::not_a_number();
216 if((is_pos_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ||
217 (is_neg_inf(value_) && rhs.is_pos_inf(rhs.as_number())) )
219 return int_adapter::not_a_number();
225 if (rhs.is_pos_inf(rhs.as_number()))
227 return int_adapter::pos_infinity();
229 if (rhs.is_neg_inf(rhs.as_number()))
231 return int_adapter::neg_infinity();
234 return int_adapter<int_type>(value_ + static_cast<int_type>(rhs.as_number()));
237 int_adapter operator+(const int_type rhs) const
243 return int_adapter<int_type>(not_a_number());
250 return int_adapter<int_type>(value_ + rhs);
253 /*! Operator allows for subtracting dissimilar int_adapter types.
254 * The return type will match that of the the calling object's type */
255 template<class rhs_type>
257 int_adapter operator-(const int_adapter<rhs_type>& rhs)const
259 if(is_special() || rhs.is_special())
261 if (is_nan() || rhs.is_nan())
263 return int_adapter::not_a_number();
265 if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) ||
266 (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) )
268 return int_adapter::not_a_number();
274 if (rhs.is_pos_inf(rhs.as_number()))
276 return int_adapter::neg_infinity();
278 if (rhs.is_neg_inf(rhs.as_number()))
280 return int_adapter::pos_infinity();
283 return int_adapter<int_type>(value_ - static_cast<int_type>(rhs.as_number()));
285 int_adapter operator-(const int_type rhs) const
291 return int_adapter<int_type>(not_a_number());
298 return int_adapter<int_type>(value_ - rhs);
301 // should templatize this to be consistant with op +-
302 int_adapter operator*(const int_adapter& rhs)const
304 if(this->is_special() || rhs.is_special())
306 return mult_div_specials(rhs);
308 return int_adapter<int_type>(value_ * rhs.value_);
310 /*! Provided for cases when automatic conversion from
311 * 'int' to 'int_adapter' causes incorrect results. */
312 int_adapter operator*(const int rhs) const
316 return mult_div_specials(rhs);
318 return int_adapter<int_type>(value_ * rhs);
321 // should templatize this to be consistant with op +-
322 int_adapter operator/(const int_adapter& rhs)const
324 if(this->is_special() || rhs.is_special())
326 if(is_infinity() && rhs.is_infinity())
328 return int_adapter<int_type>(not_a_number());
332 return mult_div_specials(rhs);
334 else { // let divide by zero blow itself up
335 return int_adapter<int_type>(value_ / rhs.value_);
338 return int_adapter<int_type>(value_ / rhs.value_);
340 /*! Provided for cases when automatic conversion from
341 * 'int' to 'int_adapter' causes incorrect results. */
342 int_adapter operator/(const int rhs) const
344 if(is_special() && rhs != 0)
346 return mult_div_specials(rhs);
348 return int_adapter<int_type>(value_ / rhs);
351 // should templatize this to be consistant with op +-
352 int_adapter operator%(const int_adapter& rhs)const
354 if(this->is_special() || rhs.is_special())
356 if(is_infinity() && rhs.is_infinity())
358 return int_adapter<int_type>(not_a_number());
362 return mult_div_specials(rhs);
364 else { // let divide by zero blow itself up
365 return int_adapter<int_type>(value_ % rhs.value_);
368 return int_adapter<int_type>(value_ % rhs.value_);
370 /*! Provided for cases when automatic conversion from
371 * 'int' to 'int_adapter' causes incorrect results. */
372 int_adapter operator%(const int rhs) const
374 if(is_special() && rhs != 0)
376 return mult_div_specials(rhs);
378 return int_adapter<int_type>(value_ % rhs);
383 //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs
384 int compare(const int_adapter& rhs)const
386 if(this->is_special() || rhs.is_special())
388 if(this->is_nan() || rhs.is_nan()) {
389 if(this->is_nan() && rhs.is_nan()) {
396 if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) ||
397 (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) )
399 return -1; // less than
401 if((is_pos_inf(value_) && !is_pos_inf(rhs.value_)) ||
402 (is_neg_inf(rhs.value_) && !is_neg_inf(value_)) ) {
403 return 1; // greater than
406 if(value_ < rhs.value_) return -1;
407 if(value_ > rhs.value_) return 1;
408 // implied-> if(value_ == rhs.value_)
411 /* When multiplying and dividing with at least 1 special value
412 * very simmilar rules apply. In those cases where the rules
413 * are different, they are handled in the respective operator
415 //! Assumes at least 'this' or 'rhs' is a special value
416 int_adapter mult_div_specials(const int_adapter& rhs)const
418 if(this->is_nan() || rhs.is_nan()) {
419 return int_adapter<int_type>(not_a_number());
421 BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1;
422 if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) {
423 return int_adapter<int_type>(pos_infinity());
425 if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) {
426 return int_adapter<int_type>(neg_infinity());
428 //implied -> if(this->value_ == 0 || rhs.value_ == 0)
429 return int_adapter<int_type>(not_a_number());
431 /* Overloaded function necessary because of special
432 * situation where int_adapter is instantiated with
433 * 'unsigned' and func is called with negative int.
434 * It would produce incorrect results since 'unsigned'
435 * wraps around when initialized with a negative value */
436 //! Assumes 'this' is a special value
437 int_adapter mult_div_specials(const int& rhs) const
440 return int_adapter<int_type>(not_a_number());
442 BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1;
443 if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) {
444 return int_adapter<int_type>(pos_infinity());
446 if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) {
447 return int_adapter<int_type>(neg_infinity());
449 //implied -> if(this->value_ == 0 || rhs.value_ == 0)
450 return int_adapter<int_type>(not_a_number());
455 #ifndef BOOST_DATE_TIME_NO_LOCALE
456 /*! Expected output is either a numeric representation
457 * or a special values representation.<BR>
458 * Ex. "12", "+infinity", "not-a-number", etc. */
459 //template<class charT = char, class traits = std::traits<charT>, typename int_type>
460 template<class charT, class traits, typename int_type>
462 std::basic_ostream<charT, traits>&
463 operator<<(std::basic_ostream<charT, traits>& os, const int_adapter<int_type>& ia)
465 if(ia.is_special()) {
466 // switch copied from date_names_put.hpp
467 switch(ia.as_special())
469 case not_a_date_time:
470 os << "not-a-number";
483 os << ia.as_number();
490 } } //namespace date_time
492 #if defined(BOOST_MSVC)