]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
11fdf7f2 TL |
21 | #if defined(BOOST_MSVC) |
22 | #pragma warning(push) | |
23 | // conditional expression is constant | |
24 | #pragma warning(disable: 4127) | |
25 | #endif | |
26 | ||
7c673cae FG |
27 | namespace boost { |
28 | namespace date_time { | |
29 | ||
30 | ||
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: | |
36 | *@code | |
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 | |
43 | *@endcode | |
44 | */ | |
45 | template<typename int_type_> | |
46 | class int_adapter { | |
47 | public: | |
48 | typedef int_type_ int_type; | |
f67539c2 | 49 | BOOST_CXX14_CONSTEXPR int_adapter(int_type v) : |
7c673cae FG |
50 | value_(v) |
51 | {} | |
f67539c2 | 52 | static BOOST_CONSTEXPR bool has_infinity() |
7c673cae FG |
53 | { |
54 | return true; | |
55 | } | |
f67539c2 | 56 | static BOOST_CONSTEXPR int_adapter pos_infinity() |
7c673cae FG |
57 | { |
58 | return (::std::numeric_limits<int_type>::max)(); | |
59 | } | |
f67539c2 | 60 | static BOOST_CONSTEXPR int_adapter neg_infinity() |
7c673cae FG |
61 | { |
62 | return (::std::numeric_limits<int_type>::min)(); | |
63 | } | |
f67539c2 | 64 | static BOOST_CONSTEXPR int_adapter not_a_number() |
7c673cae FG |
65 | { |
66 | return (::std::numeric_limits<int_type>::max)()-1; | |
67 | } | |
f67539c2 | 68 | static BOOST_CONSTEXPR int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION () |
7c673cae FG |
69 | { |
70 | return (::std::numeric_limits<int_type>::max)()-2; | |
71 | } | |
f67539c2 | 72 | static BOOST_CONSTEXPR int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION () |
7c673cae FG |
73 | { |
74 | return (::std::numeric_limits<int_type>::min)()+1; | |
75 | } | |
f67539c2 | 76 | static BOOST_CXX14_CONSTEXPR int_adapter from_special(special_values sv) |
7c673cae FG |
77 | { |
78 | switch (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(); | |
85 | } | |
86 | } | |
f67539c2 | 87 | static BOOST_CONSTEXPR bool is_inf(int_type v) |
7c673cae FG |
88 | { |
89 | return (v == neg_infinity().as_number() || | |
90 | v == pos_infinity().as_number()); | |
91 | } | |
f67539c2 | 92 | static BOOST_CXX14_CONSTEXPR bool is_neg_inf(int_type v) |
7c673cae FG |
93 | { |
94 | return (v == neg_infinity().as_number()); | |
95 | } | |
f67539c2 | 96 | static BOOST_CXX14_CONSTEXPR bool is_pos_inf(int_type v) |
7c673cae FG |
97 | { |
98 | return (v == pos_infinity().as_number()); | |
99 | } | |
f67539c2 | 100 | static BOOST_CXX14_CONSTEXPR bool is_not_a_number(int_type v) |
7c673cae FG |
101 | { |
102 | return (v == not_a_number().as_number()); | |
103 | } | |
104 | //! Returns either special value type or is_not_special | |
f67539c2 | 105 | static BOOST_CXX14_CONSTEXPR special_values to_special(int_type v) |
7c673cae FG |
106 | { |
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; | |
110 | return not_special; | |
111 | } | |
112 | ||
113 | //-3 leaves room for representations of infinity and not a date | |
f67539c2 | 114 | static BOOST_CONSTEXPR int_type maxcount() |
7c673cae FG |
115 | { |
116 | return (::std::numeric_limits<int_type>::max)()-3; | |
117 | } | |
f67539c2 | 118 | BOOST_CONSTEXPR bool is_infinity() const |
7c673cae FG |
119 | { |
120 | return (value_ == neg_infinity().as_number() || | |
121 | value_ == pos_infinity().as_number()); | |
122 | } | |
f67539c2 | 123 | BOOST_CONSTEXPR bool is_pos_infinity()const |
7c673cae FG |
124 | { |
125 | return(value_ == pos_infinity().as_number()); | |
126 | } | |
f67539c2 | 127 | BOOST_CONSTEXPR bool is_neg_infinity()const |
7c673cae FG |
128 | { |
129 | return(value_ == neg_infinity().as_number()); | |
130 | } | |
f67539c2 | 131 | BOOST_CONSTEXPR bool is_nan() const |
7c673cae FG |
132 | { |
133 | return (value_ == not_a_number().as_number()); | |
134 | } | |
f67539c2 | 135 | BOOST_CONSTEXPR bool is_special() const |
7c673cae FG |
136 | { |
137 | return(is_infinity() || is_nan()); | |
138 | } | |
f67539c2 | 139 | BOOST_CONSTEXPR bool operator==(const int_adapter& rhs) const |
7c673cae FG |
140 | { |
141 | return (compare(rhs) == 0); | |
142 | } | |
f67539c2 | 143 | BOOST_CXX14_CONSTEXPR bool operator==(const int& rhs) const |
7c673cae | 144 | { |
11fdf7f2 | 145 | if(!std::numeric_limits<int_type>::is_signed) |
7c673cae FG |
146 | { |
147 | if(is_neg_inf(value_) && rhs == 0) | |
148 | { | |
149 | return false; | |
150 | } | |
151 | } | |
152 | return (compare(rhs) == 0); | |
153 | } | |
f67539c2 | 154 | BOOST_CONSTEXPR bool operator!=(const int_adapter& rhs) const |
7c673cae FG |
155 | { |
156 | return (compare(rhs) != 0); | |
157 | } | |
f67539c2 | 158 | BOOST_CXX14_CONSTEXPR bool operator!=(const int& rhs) const |
7c673cae | 159 | { |
11fdf7f2 | 160 | if(!std::numeric_limits<int_type>::is_signed) |
7c673cae FG |
161 | { |
162 | if(is_neg_inf(value_) && rhs == 0) | |
163 | { | |
164 | return true; | |
165 | } | |
166 | } | |
167 | return (compare(rhs) != 0); | |
168 | } | |
f67539c2 | 169 | BOOST_CONSTEXPR bool operator<(const int_adapter& rhs) const |
7c673cae FG |
170 | { |
171 | return (compare(rhs) == -1); | |
172 | } | |
f67539c2 | 173 | BOOST_CXX14_CONSTEXPR bool operator<(const int& rhs) const |
7c673cae FG |
174 | { |
175 | // quiets compiler warnings | |
11fdf7f2 | 176 | if(!std::numeric_limits<int_type>::is_signed) |
7c673cae FG |
177 | { |
178 | if(is_neg_inf(value_) && rhs == 0) | |
179 | { | |
180 | return true; | |
181 | } | |
182 | } | |
183 | return (compare(rhs) == -1); | |
184 | } | |
f67539c2 | 185 | BOOST_CONSTEXPR bool operator>(const int_adapter& rhs) const |
7c673cae FG |
186 | { |
187 | return (compare(rhs) == 1); | |
188 | } | |
f67539c2 | 189 | BOOST_CONSTEXPR int_type as_number() const |
7c673cae FG |
190 | { |
191 | return value_; | |
192 | } | |
193 | //! Returns either special value type or is_not_special | |
f67539c2 | 194 | BOOST_CONSTEXPR special_values as_special() const |
7c673cae FG |
195 | { |
196 | return int_adapter::to_special(value_); | |
197 | } | |
198 | //creates nasty ambiguities | |
199 | // operator int_type() const | |
200 | // { | |
201 | // return value_; | |
202 | // } | |
203 | ||
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> | |
f67539c2 | 207 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
208 | int_adapter operator+(const int_adapter<rhs_type>& rhs) const |
209 | { | |
210 | if(is_special() || rhs.is_special()) | |
211 | { | |
212 | if (is_nan() || rhs.is_nan()) | |
213 | { | |
214 | return int_adapter::not_a_number(); | |
215 | } | |
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())) ) | |
218 | { | |
219 | return int_adapter::not_a_number(); | |
220 | } | |
221 | if (is_infinity()) | |
222 | { | |
223 | return *this; | |
224 | } | |
225 | if (rhs.is_pos_inf(rhs.as_number())) | |
226 | { | |
227 | return int_adapter::pos_infinity(); | |
228 | } | |
229 | if (rhs.is_neg_inf(rhs.as_number())) | |
230 | { | |
231 | return int_adapter::neg_infinity(); | |
232 | } | |
233 | } | |
234 | return int_adapter<int_type>(value_ + static_cast<int_type>(rhs.as_number())); | |
235 | } | |
236 | ||
f67539c2 | 237 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
238 | int_adapter operator+(const int_type rhs) const |
239 | { | |
240 | if(is_special()) | |
241 | { | |
242 | if (is_nan()) | |
243 | { | |
244 | return int_adapter<int_type>(not_a_number()); | |
245 | } | |
246 | if (is_infinity()) | |
247 | { | |
248 | return *this; | |
249 | } | |
250 | } | |
251 | return int_adapter<int_type>(value_ + rhs); | |
252 | } | |
253 | ||
254 | /*! Operator allows for subtracting dissimilar int_adapter types. | |
255 | * The return type will match that of the the calling object's type */ | |
256 | template<class rhs_type> | |
f67539c2 | 257 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
258 | int_adapter operator-(const int_adapter<rhs_type>& rhs)const |
259 | { | |
260 | if(is_special() || rhs.is_special()) | |
261 | { | |
262 | if (is_nan() || rhs.is_nan()) | |
263 | { | |
264 | return int_adapter::not_a_number(); | |
265 | } | |
266 | if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) || | |
267 | (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ) | |
268 | { | |
269 | return int_adapter::not_a_number(); | |
270 | } | |
271 | if (is_infinity()) | |
272 | { | |
273 | return *this; | |
274 | } | |
275 | if (rhs.is_pos_inf(rhs.as_number())) | |
276 | { | |
277 | return int_adapter::neg_infinity(); | |
278 | } | |
279 | if (rhs.is_neg_inf(rhs.as_number())) | |
280 | { | |
281 | return int_adapter::pos_infinity(); | |
282 | } | |
283 | } | |
284 | return int_adapter<int_type>(value_ - static_cast<int_type>(rhs.as_number())); | |
285 | } | |
f67539c2 TL |
286 | |
287 | BOOST_CXX14_CONSTEXPR | |
7c673cae FG |
288 | int_adapter operator-(const int_type rhs) const |
289 | { | |
290 | if(is_special()) | |
291 | { | |
292 | if (is_nan()) | |
293 | { | |
294 | return int_adapter<int_type>(not_a_number()); | |
295 | } | |
296 | if (is_infinity()) | |
297 | { | |
298 | return *this; | |
299 | } | |
300 | } | |
301 | return int_adapter<int_type>(value_ - rhs); | |
302 | } | |
303 | ||
304 | // should templatize this to be consistant with op +- | |
f67539c2 | 305 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
306 | int_adapter operator*(const int_adapter& rhs)const |
307 | { | |
308 | if(this->is_special() || rhs.is_special()) | |
309 | { | |
310 | return mult_div_specials(rhs); | |
311 | } | |
312 | return int_adapter<int_type>(value_ * rhs.value_); | |
313 | } | |
f67539c2 | 314 | |
7c673cae FG |
315 | /*! Provided for cases when automatic conversion from |
316 | * 'int' to 'int_adapter' causes incorrect results. */ | |
f67539c2 | 317 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
318 | int_adapter operator*(const int rhs) const |
319 | { | |
320 | if(is_special()) | |
321 | { | |
322 | return mult_div_specials(rhs); | |
323 | } | |
324 | return int_adapter<int_type>(value_ * rhs); | |
325 | } | |
326 | ||
327 | // should templatize this to be consistant with op +- | |
f67539c2 | 328 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
329 | int_adapter operator/(const int_adapter& rhs)const |
330 | { | |
331 | if(this->is_special() || rhs.is_special()) | |
332 | { | |
333 | if(is_infinity() && rhs.is_infinity()) | |
334 | { | |
335 | return int_adapter<int_type>(not_a_number()); | |
336 | } | |
337 | if(rhs != 0) | |
338 | { | |
339 | return mult_div_specials(rhs); | |
340 | } | |
341 | else { // let divide by zero blow itself up | |
f67539c2 | 342 | return int_adapter<int_type>(value_ / rhs.value_); //NOLINT |
7c673cae FG |
343 | } |
344 | } | |
345 | return int_adapter<int_type>(value_ / rhs.value_); | |
346 | } | |
f67539c2 | 347 | |
7c673cae FG |
348 | /*! Provided for cases when automatic conversion from |
349 | * 'int' to 'int_adapter' causes incorrect results. */ | |
f67539c2 | 350 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
351 | int_adapter operator/(const int rhs) const |
352 | { | |
353 | if(is_special() && rhs != 0) | |
354 | { | |
355 | return mult_div_specials(rhs); | |
356 | } | |
f67539c2 TL |
357 | // let divide by zero blow itself up like int |
358 | return int_adapter<int_type>(value_ / rhs); //NOLINT | |
7c673cae FG |
359 | } |
360 | ||
361 | // should templatize this to be consistant with op +- | |
f67539c2 | 362 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
363 | int_adapter operator%(const int_adapter& rhs)const |
364 | { | |
365 | if(this->is_special() || rhs.is_special()) | |
366 | { | |
367 | if(is_infinity() && rhs.is_infinity()) | |
368 | { | |
369 | return int_adapter<int_type>(not_a_number()); | |
370 | } | |
371 | if(rhs != 0) | |
372 | { | |
373 | return mult_div_specials(rhs); | |
374 | } | |
375 | else { // let divide by zero blow itself up | |
f67539c2 | 376 | return int_adapter<int_type>(value_ % rhs.value_); //NOLINT |
7c673cae FG |
377 | } |
378 | } | |
379 | return int_adapter<int_type>(value_ % rhs.value_); | |
380 | } | |
f67539c2 | 381 | |
7c673cae FG |
382 | /*! Provided for cases when automatic conversion from |
383 | * 'int' to 'int_adapter' causes incorrect results. */ | |
f67539c2 | 384 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
385 | int_adapter operator%(const int rhs) const |
386 | { | |
387 | if(is_special() && rhs != 0) | |
388 | { | |
389 | return mult_div_specials(rhs); | |
390 | } | |
f67539c2 TL |
391 | // let divide by zero blow itself up |
392 | return int_adapter<int_type>(value_ % rhs); //NOLINT | |
7c673cae | 393 | } |
f67539c2 | 394 | |
7c673cae FG |
395 | private: |
396 | int_type value_; | |
397 | ||
398 | //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs | |
f67539c2 TL |
399 | BOOST_CXX14_CONSTEXPR |
400 | int compare( const int_adapter& rhs ) const | |
7c673cae FG |
401 | { |
402 | if(this->is_special() || rhs.is_special()) | |
403 | { | |
404 | if(this->is_nan() || rhs.is_nan()) { | |
405 | if(this->is_nan() && rhs.is_nan()) { | |
406 | return 0; // equal | |
407 | } | |
408 | else { | |
409 | return 2; // nan | |
410 | } | |
411 | } | |
412 | if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) || | |
413 | (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) ) | |
414 | { | |
415 | return -1; // less than | |
416 | } | |
417 | if((is_pos_inf(value_) && !is_pos_inf(rhs.value_)) || | |
418 | (is_neg_inf(rhs.value_) && !is_neg_inf(value_)) ) { | |
419 | return 1; // greater than | |
420 | } | |
421 | } | |
422 | if(value_ < rhs.value_) return -1; | |
423 | if(value_ > rhs.value_) return 1; | |
424 | // implied-> if(value_ == rhs.value_) | |
425 | return 0; | |
426 | } | |
f67539c2 | 427 | |
7c673cae FG |
428 | /* When multiplying and dividing with at least 1 special value |
429 | * very simmilar rules apply. In those cases where the rules | |
430 | * are different, they are handled in the respective operator | |
431 | * function. */ | |
432 | //! Assumes at least 'this' or 'rhs' is a special value | |
f67539c2 TL |
433 | BOOST_CXX14_CONSTEXPR |
434 | int_adapter mult_div_specials(const int_adapter& rhs) const | |
7c673cae | 435 | { |
7c673cae FG |
436 | if(this->is_nan() || rhs.is_nan()) { |
437 | return int_adapter<int_type>(not_a_number()); | |
438 | } | |
11fdf7f2 | 439 | BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; |
7c673cae FG |
440 | if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) { |
441 | return int_adapter<int_type>(pos_infinity()); | |
442 | } | |
443 | if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) { | |
444 | return int_adapter<int_type>(neg_infinity()); | |
445 | } | |
446 | //implied -> if(this->value_ == 0 || rhs.value_ == 0) | |
447 | return int_adapter<int_type>(not_a_number()); | |
448 | } | |
f67539c2 | 449 | |
7c673cae FG |
450 | /* Overloaded function necessary because of special |
451 | * situation where int_adapter is instantiated with | |
452 | * 'unsigned' and func is called with negative int. | |
453 | * It would produce incorrect results since 'unsigned' | |
454 | * wraps around when initialized with a negative value */ | |
455 | //! Assumes 'this' is a special value | |
f67539c2 | 456 | BOOST_CXX14_CONSTEXPR |
7c673cae FG |
457 | int_adapter mult_div_specials(const int& rhs) const |
458 | { | |
7c673cae FG |
459 | if(this->is_nan()) { |
460 | return int_adapter<int_type>(not_a_number()); | |
461 | } | |
11fdf7f2 | 462 | BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; |
7c673cae FG |
463 | if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) { |
464 | return int_adapter<int_type>(pos_infinity()); | |
465 | } | |
466 | if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) { | |
467 | return int_adapter<int_type>(neg_infinity()); | |
468 | } | |
469 | //implied -> if(this->value_ == 0 || rhs.value_ == 0) | |
470 | return int_adapter<int_type>(not_a_number()); | |
471 | } | |
f67539c2 | 472 | |
7c673cae FG |
473 | }; |
474 | ||
475 | #ifndef BOOST_DATE_TIME_NO_LOCALE | |
476 | /*! Expected output is either a numeric representation | |
477 | * or a special values representation.<BR> | |
478 | * Ex. "12", "+infinity", "not-a-number", etc. */ | |
479 | //template<class charT = char, class traits = std::traits<charT>, typename int_type> | |
480 | template<class charT, class traits, typename int_type> | |
481 | inline | |
482 | std::basic_ostream<charT, traits>& | |
483 | operator<<(std::basic_ostream<charT, traits>& os, const int_adapter<int_type>& ia) | |
484 | { | |
485 | if(ia.is_special()) { | |
486 | // switch copied from date_names_put.hpp | |
487 | switch(ia.as_special()) | |
488 | { | |
489 | case not_a_date_time: | |
490 | os << "not-a-number"; | |
491 | break; | |
492 | case pos_infin: | |
493 | os << "+infinity"; | |
494 | break; | |
495 | case neg_infin: | |
496 | os << "-infinity"; | |
497 | break; | |
498 | default: | |
499 | os << ""; | |
500 | } | |
501 | } | |
502 | else { | |
503 | os << ia.as_number(); | |
504 | } | |
505 | return os; | |
506 | } | |
507 | #endif | |
508 | ||
509 | ||
510 | } } //namespace date_time | |
511 | ||
11fdf7f2 TL |
512 | #if defined(BOOST_MSVC) |
513 | #pragma warning(pop) | |
514 | #endif | |
7c673cae FG |
515 | |
516 | #endif |