|
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: 2008-11-12 14:37:53 -0500 (Wed, 12 Nov 2008) $ |
|
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 |
|
21 namespace boost { |
|
22 namespace 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 */ |
|
39 template<typename int_type_> |
|
40 class int_adapter { |
|
41 public: |
|
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(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(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(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(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(value_) && rhs.is_neg_inf(rhs.as_number())) || |
|
216 (is_neg_inf(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_ + 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(value_) && rhs.is_pos_inf(rhs.as_number())) || |
|
265 (is_neg_inf(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_ - 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 } |
|
379 private: |
|
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(value_) && !is_neg_inf(rhs.value_)) || |
|
396 (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) ) |
|
397 { |
|
398 return -1; // less than |
|
399 } |
|
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 |
|
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 |