]>
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 | ||
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_ + 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(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_ - 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 | } | |
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 |