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$
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
21namespace boost {
22namespace 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 */
39template<typename int_type_>
40class int_adapter {
41public:
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(v: 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(v: 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(v: 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(v: 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(v: value_) && rhs.is_neg_inf(rhs.as_number())) ||
216 (is_neg_inf(v: 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_ + static_cast<int_type>(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(v: value_) && rhs.is_pos_inf(rhs.as_number())) ||
265 (is_neg_inf(v: 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_ - static_cast<int_type>(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 }
379private:
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(v: value_) && !is_neg_inf(v: rhs.value_)) ||
396 (is_pos_inf(v: rhs.value_) && !is_pos_inf(v: value_)) )
397 {
398 return -1; // less than
399 }
400 if((is_pos_inf(v: value_) && !is_pos_inf(v: rhs.value_)) ||
401 (is_neg_inf(v: rhs.value_) && !is_neg_inf(v: 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
510

source code of boost/boost/date_time/int_adapter.hpp