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; int_adapter(int_type v)49 BOOST_CXX14_CONSTEXPR int_adapter(int_type v) : 50 value_(v) 51 {} has_infinity()52 static BOOST_CONSTEXPR bool has_infinity() 53 { 54 return true; 55 } pos_infinity()56 static BOOST_CONSTEXPR int_adapter pos_infinity() 57 { 58 return (::std::numeric_limits<int_type>::max)(); 59 } neg_infinity()60 static BOOST_CONSTEXPR int_adapter neg_infinity() 61 { 62 return (::std::numeric_limits<int_type>::min)(); 63 } not_a_number()64 static BOOST_CONSTEXPR int_adapter not_a_number() 65 { 66 return (::std::numeric_limits<int_type>::max)()-1; 67 } BOOST_PREVENT_MACRO_SUBSTITUTION()68 static BOOST_CONSTEXPR int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION () 69 { 70 return (::std::numeric_limits<int_type>::max)()-2; 71 } BOOST_PREVENT_MACRO_SUBSTITUTION()72 static BOOST_CONSTEXPR int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION () 73 { 74 return (::std::numeric_limits<int_type>::min)()+1; 75 } from_special(special_values sv)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 } is_inf(int_type v)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 } is_neg_inf(int_type v)92 static BOOST_CXX14_CONSTEXPR bool is_neg_inf(int_type v) 93 { 94 return (v == neg_infinity().as_number()); 95 } is_pos_inf(int_type v)96 static BOOST_CXX14_CONSTEXPR bool is_pos_inf(int_type v) 97 { 98 return (v == pos_infinity().as_number()); 99 } is_not_a_number(int_type v)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 to_special(int_type v)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 maxcount()114 static BOOST_CONSTEXPR int_type maxcount() 115 { 116 return (::std::numeric_limits<int_type>::max)()-3; 117 } is_infinity() const118 BOOST_CONSTEXPR bool is_infinity() const 119 { 120 return (value_ == neg_infinity().as_number() || 121 value_ == pos_infinity().as_number()); 122 } is_pos_infinity() const123 BOOST_CONSTEXPR bool is_pos_infinity()const 124 { 125 return(value_ == pos_infinity().as_number()); 126 } is_neg_infinity() const127 BOOST_CONSTEXPR bool is_neg_infinity()const 128 { 129 return(value_ == neg_infinity().as_number()); 130 } is_nan() const131 BOOST_CONSTEXPR bool is_nan() const 132 { 133 return (value_ == not_a_number().as_number()); 134 } is_special() const135 BOOST_CONSTEXPR bool is_special() const 136 { 137 return(is_infinity() || is_nan()); 138 } operator ==(const int_adapter & rhs) const139 BOOST_CONSTEXPR bool operator==(const int_adapter& rhs) const 140 { 141 return (compare(rhs) == 0); 142 } operator ==(const int & rhs) const143 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 } operator !=(const int_adapter & rhs) const154 BOOST_CONSTEXPR bool operator!=(const int_adapter& rhs) const 155 { 156 return (compare(rhs) != 0); 157 } operator !=(const int & rhs) const158 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 } operator <(const int_adapter & rhs) const169 BOOST_CONSTEXPR bool operator<(const int_adapter& rhs) const 170 { 171 return (compare(rhs) == -1); 172 } operator <(const int & rhs) const173 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 } operator >(const int_adapter & rhs) const185 BOOST_CONSTEXPR bool operator>(const int_adapter& rhs) const 186 { 187 return (compare(rhs) == 1); 188 } as_number() const189 BOOST_CONSTEXPR int_type as_number() const 190 { 191 return value_; 192 } 193 //! Returns either special value type or is_not_special as_special() const194 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 operator +(const int_adapter<rhs_type> & rhs) const208 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 237 BOOST_CXX14_CONSTEXPR operator +(const int_type rhs) const238 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 operator -(const int_adapter<rhs_type> & rhs) const258 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 } 286 287 BOOST_CXX14_CONSTEXPR operator -(const int_type rhs) const288 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 operator *(const int_adapter & rhs) const306 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 operator *(const int rhs) const318 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 operator /(const int_adapter & rhs) const329 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 operator /(const int rhs) const351 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 operator %(const int_adapter & rhs) const363 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 operator %(const int rhs) const385 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 compare(const int_adapter & rhs) const400 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 mult_div_specials(const int_adapter & rhs) const434 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 mult_div_specials(const int & rhs) const457 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>& operator <<(std::basic_ostream<charT,traits> & os,const int_adapter<int_type> & ia)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