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
27namespace boost {
28namespace 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 */
45template<typename int_type_>
46class int_adapter {
47public:
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
395private:
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

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