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 | |
21 | #if defined(BOOST_MSVC) |
22 | #pragma warning(push) |
23 | // conditional expression is constant |
24 | #pragma warning(disable: 4127) |
25 | #endif |
26 | |
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; |
49 | BOOST_CXX14_CONSTEXPR int_adapter(int_type v) : |
50 | value_(v) |
51 | {} |
52 | static BOOST_CONSTEXPR bool has_infinity() |
53 | { |
54 | return true; |
55 | } |
56 | static BOOST_CONSTEXPR int_adapter pos_infinity() |
57 | { |
58 | return (::std::numeric_limits<int_type>::max)(); |
59 | } |
60 | static BOOST_CONSTEXPR int_adapter neg_infinity() |
61 | { |
62 | return (::std::numeric_limits<int_type>::min)(); |
63 | } |
64 | static BOOST_CONSTEXPR int_adapter not_a_number() |
65 | { |
66 | return (::std::numeric_limits<int_type>::max)()-1; |
67 | } |
68 | static BOOST_CONSTEXPR int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION () |
69 | { |
70 | return (::std::numeric_limits<int_type>::max)()-2; |
71 | } |
72 | static BOOST_CONSTEXPR int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION () |
73 | { |
74 | return (::std::numeric_limits<int_type>::min)()+1; |
75 | } |
76 | static BOOST_CXX14_CONSTEXPR int_adapter from_special(special_values sv) |
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 | } |
87 | static BOOST_CONSTEXPR bool is_inf(int_type v) |
88 | { |
89 | return (v == neg_infinity().as_number() || |
90 | v == pos_infinity().as_number()); |
91 | } |
92 | static BOOST_CXX14_CONSTEXPR bool is_neg_inf(int_type v) |
93 | { |
94 | return (v == neg_infinity().as_number()); |
95 | } |
96 | static BOOST_CXX14_CONSTEXPR bool is_pos_inf(int_type v) |
97 | { |
98 | return (v == pos_infinity().as_number()); |
99 | } |
100 | static BOOST_CXX14_CONSTEXPR bool is_not_a_number(int_type v) |
101 | { |
102 | return (v == not_a_number().as_number()); |
103 | } |
104 | //! Returns either special value type or is_not_special |
105 | static BOOST_CXX14_CONSTEXPR special_values to_special(int_type v) |
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 |
114 | static BOOST_CONSTEXPR int_type maxcount() |
115 | { |
116 | return (::std::numeric_limits<int_type>::max)()-3; |
117 | } |
118 | BOOST_CONSTEXPR bool is_infinity() const |
119 | { |
120 | return (value_ == neg_infinity().as_number() || |
121 | value_ == pos_infinity().as_number()); |
122 | } |
123 | BOOST_CONSTEXPR bool is_pos_infinity()const |
124 | { |
125 | return(value_ == pos_infinity().as_number()); |
126 | } |
127 | BOOST_CONSTEXPR bool is_neg_infinity()const |
128 | { |
129 | return(value_ == neg_infinity().as_number()); |
130 | } |
131 | BOOST_CONSTEXPR bool is_nan() const |
132 | { |
133 | return (value_ == not_a_number().as_number()); |
134 | } |
135 | BOOST_CONSTEXPR bool is_special() const |
136 | { |
137 | return(is_infinity() || is_nan()); |
138 | } |
139 | BOOST_CONSTEXPR bool operator==(const int_adapter& rhs) const |
140 | { |
141 | return (compare(rhs) == 0); |
142 | } |
143 | BOOST_CXX14_CONSTEXPR bool operator==(const int& rhs) const |
144 | { |
145 | if(!std::numeric_limits<int_type>::is_signed) |
146 | { |
147 | if(is_neg_inf(v: value_) && rhs == 0) |
148 | { |
149 | return false; |
150 | } |
151 | } |
152 | return (compare(rhs) == 0); |
153 | } |
154 | BOOST_CONSTEXPR bool operator!=(const int_adapter& rhs) const |
155 | { |
156 | return (compare(rhs) != 0); |
157 | } |
158 | BOOST_CXX14_CONSTEXPR bool operator!=(const int& rhs) const |
159 | { |
160 | if(!std::numeric_limits<int_type>::is_signed) |
161 | { |
162 | if(is_neg_inf(v: value_) && rhs == 0) |
163 | { |
164 | return true; |
165 | } |
166 | } |
167 | return (compare(rhs) != 0); |
168 | } |
169 | BOOST_CONSTEXPR bool operator<(const int_adapter& rhs) const |
170 | { |
171 | return (compare(rhs) == -1); |
172 | } |
173 | BOOST_CXX14_CONSTEXPR bool operator<(const int& rhs) const |
174 | { |
175 | // quiets compiler warnings |
176 | if(!std::numeric_limits<int_type>::is_signed) |
177 | { |
178 | if(is_neg_inf(v: value_) && rhs == 0) |
179 | { |
180 | return true; |
181 | } |
182 | } |
183 | return (compare(rhs) == -1); |
184 | } |
185 | BOOST_CONSTEXPR bool operator>(const int_adapter& rhs) const |
186 | { |
187 | return (compare(rhs) == 1); |
188 | } |
189 | BOOST_CONSTEXPR int_type as_number() const |
190 | { |
191 | return value_; |
192 | } |
193 | //! Returns either special value type or is_not_special |
194 | BOOST_CONSTEXPR special_values as_special() const |
195 | { |
196 | return int_adapter::to_special(v: 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> |
207 | BOOST_CXX14_CONSTEXPR |
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(v: value_) && rhs.is_neg_inf(rhs.as_number())) || |
217 | (is_neg_inf(v: 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 | |
237 | BOOST_CXX14_CONSTEXPR |
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> |
257 | BOOST_CXX14_CONSTEXPR |
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(v: value_) && rhs.is_pos_inf(rhs.as_number())) || |
267 | (is_neg_inf(v: 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 | } |
286 | |
287 | BOOST_CXX14_CONSTEXPR |
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 +- |
305 | BOOST_CXX14_CONSTEXPR |
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 | } |
314 | |
315 | /*! Provided for cases when automatic conversion from |
316 | * 'int' to 'int_adapter' causes incorrect results. */ |
317 | BOOST_CXX14_CONSTEXPR |
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 +- |
328 | BOOST_CXX14_CONSTEXPR |
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 |
342 | return int_adapter<int_type>(value_ / rhs.value_); //NOLINT |
343 | } |
344 | } |
345 | return int_adapter<int_type>(value_ / rhs.value_); |
346 | } |
347 | |
348 | /*! Provided for cases when automatic conversion from |
349 | * 'int' to 'int_adapter' causes incorrect results. */ |
350 | BOOST_CXX14_CONSTEXPR |
351 | int_adapter operator/(const int rhs) const |
352 | { |
353 | if(is_special() && rhs != 0) |
354 | { |
355 | return mult_div_specials(rhs); |
356 | } |
357 | // let divide by zero blow itself up like int |
358 | return int_adapter<int_type>(value_ / rhs); //NOLINT |
359 | } |
360 | |
361 | // should templatize this to be consistant with op +- |
362 | BOOST_CXX14_CONSTEXPR |
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 |
376 | return int_adapter<int_type>(value_ % rhs.value_); //NOLINT |
377 | } |
378 | } |
379 | return int_adapter<int_type>(value_ % rhs.value_); |
380 | } |
381 | |
382 | /*! Provided for cases when automatic conversion from |
383 | * 'int' to 'int_adapter' causes incorrect results. */ |
384 | BOOST_CXX14_CONSTEXPR |
385 | int_adapter operator%(const int rhs) const |
386 | { |
387 | if(is_special() && rhs != 0) |
388 | { |
389 | return mult_div_specials(rhs); |
390 | } |
391 | // let divide by zero blow itself up |
392 | return int_adapter<int_type>(value_ % rhs); //NOLINT |
393 | } |
394 | |
395 | private: |
396 | int_type value_; |
397 | |
398 | //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs |
399 | BOOST_CXX14_CONSTEXPR |
400 | int compare( const int_adapter& rhs ) const |
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(v: value_) && !is_neg_inf(v: rhs.value_)) || |
413 | (is_pos_inf(v: rhs.value_) && !is_pos_inf(v: value_)) ) |
414 | { |
415 | return -1; // less than |
416 | } |
417 | if((is_pos_inf(v: value_) && !is_pos_inf(v: rhs.value_)) || |
418 | (is_neg_inf(v: rhs.value_) && !is_neg_inf(v: 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 | } |
427 | |
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 |
433 | BOOST_CXX14_CONSTEXPR |
434 | int_adapter mult_div_specials(const int_adapter& rhs) const |
435 | { |
436 | if(this->is_nan() || rhs.is_nan()) { |
437 | return int_adapter<int_type>(not_a_number()); |
438 | } |
439 | BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; |
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 | } |
449 | |
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 |
456 | BOOST_CXX14_CONSTEXPR |
457 | int_adapter mult_div_specials(const int& rhs) const |
458 | { |
459 | if(this->is_nan()) { |
460 | return int_adapter<int_type>(not_a_number()); |
461 | } |
462 | BOOST_CONSTEXPR_OR_CONST int min_value = std::numeric_limits<int_type>::is_signed ? 0 : 1; |
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 | } |
472 | |
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 | |
512 | #if defined(BOOST_MSVC) |
513 | #pragma warning(pop) |
514 | #endif |
515 | |
516 | #endif |
517 | |