Line data Source code
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 150618 : BOOST_CXX14_CONSTEXPR int_adapter(int_type v) : 50 75309 : value_(v) 51 150618 : {} 52 : static BOOST_CONSTEXPR bool has_infinity() 53 : { 54 : return true; 55 : } 56 15066 : static BOOST_CONSTEXPR int_adapter pos_infinity() 57 : { 58 15066 : return (::std::numeric_limits<int_type>::max)(); 59 : } 60 15066 : static BOOST_CONSTEXPR int_adapter neg_infinity() 61 : { 62 15066 : return (::std::numeric_limits<int_type>::min)(); 63 : } 64 30096 : static BOOST_CONSTEXPR int_adapter not_a_number() 65 : { 66 30096 : return (::std::numeric_limits<int_type>::max)()-1; 67 : } 68 0 : static BOOST_CONSTEXPR int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION () 69 : { 70 0 : return (::std::numeric_limits<int_type>::max)()-2; 71 : } 72 0 : static BOOST_CONSTEXPR int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION () 73 : { 74 0 : return (::std::numeric_limits<int_type>::min)()+1; 75 : } 76 7512 : static BOOST_CXX14_CONSTEXPR int_adapter from_special(special_values sv) 77 : { 78 7512 : switch (sv) { 79 7512 : case not_a_date_time: return not_a_number(); 80 0 : case neg_infin: return neg_infinity(); 81 0 : case pos_infin: return pos_infinity(); 82 0 : case max_date_time: return (max)(); 83 0 : case min_date_time: return (min)(); 84 0 : default: return not_a_number(); 85 : } 86 7512 : } 87 5020 : static BOOST_CONSTEXPR bool is_inf(int_type v) 88 : { 89 5020 : return (v == neg_infinity().as_number() || 90 5020 : v == pos_infinity().as_number()); 91 : } 92 0 : static BOOST_CXX14_CONSTEXPR bool is_neg_inf(int_type v) 93 : { 94 0 : return (v == neg_infinity().as_number()); 95 : } 96 0 : static BOOST_CXX14_CONSTEXPR bool is_pos_inf(int_type v) 97 : { 98 0 : return (v == pos_infinity().as_number()); 99 : } 100 7526 : static BOOST_CXX14_CONSTEXPR bool is_not_a_number(int_type v) 101 : { 102 7526 : return (v == not_a_number().as_number()); 103 : } 104 : //! Returns either special value type or is_not_special 105 0 : static BOOST_CXX14_CONSTEXPR special_values to_special(int_type v) 106 : { 107 0 : if (is_not_a_number(v)) return not_a_date_time; 108 0 : if (is_neg_inf(v)) return neg_infin; 109 0 : if (is_pos_inf(v)) return pos_infin; 110 0 : return not_special; 111 0 : } 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 10046 : BOOST_CONSTEXPR bool is_infinity() const 119 : { 120 10046 : return (value_ == neg_infinity().as_number() || 121 10046 : 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 12552 : BOOST_CONSTEXPR bool is_nan() const 132 : { 133 12552 : return (value_ == not_a_number().as_number()); 134 : } 135 10046 : BOOST_CONSTEXPR bool is_special() const 136 : { 137 10046 : 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(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(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(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 72761 : BOOST_CONSTEXPR int_type as_number() const 190 : { 191 72761 : 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(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 2506 : int_adapter operator+(const int_adapter<rhs_type>& rhs) const 209 : { 210 2506 : if(is_special() || rhs.is_special()) 211 : { 212 2506 : if (is_nan() || rhs.is_nan()) 213 : { 214 2506 : return int_adapter::not_a_number(); 215 : } 216 0 : if((is_pos_inf(value_) && rhs.is_neg_inf(rhs.as_number())) || 217 0 : (is_neg_inf(value_) && rhs.is_pos_inf(rhs.as_number())) ) 218 : { 219 0 : return int_adapter::not_a_number(); 220 : } 221 0 : if (is_infinity()) 222 : { 223 0 : return *this; 224 : } 225 0 : if (rhs.is_pos_inf(rhs.as_number())) 226 : { 227 0 : return int_adapter::pos_infinity(); 228 : } 229 0 : if (rhs.is_neg_inf(rhs.as_number())) 230 : { 231 0 : return int_adapter::neg_infinity(); 232 : } 233 0 : } 234 0 : return int_adapter<int_type>(value_ + static_cast<int_type>(rhs.as_number())); 235 2506 : } 236 : 237 : BOOST_CXX14_CONSTEXPR 238 0 : int_adapter operator+(const int_type rhs) const 239 : { 240 0 : if(is_special()) 241 : { 242 0 : if (is_nan()) 243 : { 244 0 : return int_adapter<int_type>(not_a_number()); 245 : } 246 0 : if (is_infinity()) 247 : { 248 0 : return *this; 249 : } 250 0 : } 251 0 : return int_adapter<int_type>(value_ + rhs); 252 0 : } 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 0 : int_adapter operator-(const int_adapter<rhs_type>& rhs)const 259 : { 260 0 : if(is_special() || rhs.is_special()) 261 : { 262 0 : if (is_nan() || rhs.is_nan()) 263 : { 264 0 : return int_adapter::not_a_number(); 265 : } 266 0 : if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) || 267 0 : (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ) 268 : { 269 0 : return int_adapter::not_a_number(); 270 : } 271 0 : if (is_infinity()) 272 : { 273 0 : return *this; 274 : } 275 0 : if (rhs.is_pos_inf(rhs.as_number())) 276 : { 277 0 : return int_adapter::neg_infinity(); 278 : } 279 0 : if (rhs.is_neg_inf(rhs.as_number())) 280 : { 281 0 : return int_adapter::pos_infinity(); 282 : } 283 0 : } 284 0 : return int_adapter<int_type>(value_ - static_cast<int_type>(rhs.as_number())); 285 0 : } 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(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 : } 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