source: NonGTP/Boost/boost/date_time/int_adapter.hpp @ 857

Revision 857, 13.9 KB checked in by igarcia, 19 years ago (diff)
Line 
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 or http://www.boost.org/LICENSE-1.0)
8 * Author: Jeff Garland, Bart Garst
9 * $Date: 2004/02/26 18:26:47 $
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#include <iostream>
18
19namespace boost {
20namespace date_time {
21
22
23//! Adapter to create integer types with +-infinity, and not a value
24/*! This class is used internally in counted date/time representations.
25 *  It adds the floating point like features of infinities and
26 *  not a number. It also provides mathmatical operations with
27 *  consideration to special values following these rules:
28 *@code
29 *  +infinity  -  infinity  == Not A Number (NAN)
30 *   infinity  *  non-zero  == infinity
31 *   infinity  *  zero      == NAN
32 *  +infinity  * -integer   == -infinity
33 *   infinity  /  infinity  == NAN
34 *   infinity  *  infinity  == infinity
35 *@endcode
36 */
37template<typename int_type_>
38class int_adapter {
39public:
40  typedef int_type_ int_type;
41  int_adapter(int_type v) :
42    value_(v)
43  {}
44  static bool has_infinity()
45  {
46    return  true;
47  }
48  static const int_adapter  pos_infinity()
49  {
50    return (::std::numeric_limits<int_type>::max)();
51  }
52  static const int_adapter  neg_infinity()
53  {
54    return (::std::numeric_limits<int_type>::min)();
55  }
56  static const int_adapter  not_a_number()
57  {
58    return (::std::numeric_limits<int_type>::max)()-1;
59  }
60  static  int_adapter max BOOST_PREVENT_MACRO_SUBSTITUTION ()
61  {
62    return (::std::numeric_limits<int_type>::max)()-2;
63  }
64  static  int_adapter min BOOST_PREVENT_MACRO_SUBSTITUTION ()
65  {
66    return (::std::numeric_limits<int_type>::min)()+1;
67  }
68  static int_adapter from_special(special_values sv)
69  {
70    switch (sv) {
71    case not_a_date_time: return not_a_number();
72    case neg_infin:       return neg_infinity();
73    case pos_infin:       return pos_infinity();
74    case max_date_time:   return (max)();
75    case min_date_time:   return (min)();
76    default:              return not_a_number();
77    }
78  }
79  static bool is_inf(int_type v)
80  {
81    return (v == neg_infinity().as_number() ||
82            v == pos_infinity().as_number());
83  }
84  static bool is_neg_inf(int_type v)
85  {
86    return (v == neg_infinity().as_number());
87  }
88  static bool is_pos_inf(int_type v)
89  {
90    return (v == pos_infinity().as_number());
91  }
92  static bool is_not_a_number(int_type v)
93  {
94    return (v == not_a_number().as_number());
95  }
96  //! Returns either special value type or is_not_special
97  static special_values to_special(int_type v)
98  {
99    if (is_not_a_number(v)) return not_a_date_time;
100    if (is_neg_inf(v)) return neg_infin;
101    if (is_pos_inf(v)) return pos_infin;
102    return not_special;
103  }
104
105  //-3 leaves room for representations of infinity and not a date
106  static  int_type maxcount()
107  {
108    return (::std::numeric_limits<int_type>::max)()-3;
109  }
110  bool is_infinity() const
111  {
112    return (value_ == neg_infinity().as_number() ||
113            value_ == pos_infinity().as_number());
114  }
115  bool is_pos_infinity()const
116  {
117    return(value_ == pos_infinity().as_number());
118  }
119  bool is_neg_infinity()const
120  {
121    return(value_ == neg_infinity().as_number());
122  }
123  bool is_nan() const
124  {
125    return (value_ == not_a_number().as_number());
126  }
127  bool is_special() const
128  {
129    return(is_infinity() || is_nan());
130  }
131  bool operator==(const int_adapter& rhs) const
132  {
133    return (compare(rhs) == 0);
134  }
135  bool operator==(const int& rhs) const
136  {
137    // quiets compiler warnings
138    bool is_signed = std::numeric_limits<int_type>::is_signed;
139    if(!is_signed)
140    {
141      if(is_neg_inf(value_) && rhs == 0)
142      {
143        return false;
144      }
145    }
146    return (compare(rhs) == 0);
147  }
148  bool operator!=(const int_adapter& rhs) const
149  {
150    return (compare(rhs) != 0);
151  }
152  bool operator!=(const int& rhs) const
153  {
154    // quiets compiler warnings
155    bool is_signed = std::numeric_limits<int_type>::is_signed;
156    if(!is_signed)
157    {
158      if(is_neg_inf(value_) && rhs == 0)
159      {
160        return true;
161      }
162    }
163    return (compare(rhs) != 0);
164  }
165  bool operator<(const int_adapter& rhs) const
166  {
167    return (compare(rhs) == -1);
168  }
169  bool operator<(const int& rhs) const
170  {
171    // quiets compiler warnings
172    bool is_signed = std::numeric_limits<int_type>::is_signed;
173    if(!is_signed)
174    {
175      if(is_neg_inf(value_) && rhs == 0)
176      {
177        return true;
178      }
179    }
180    return (compare(rhs) == -1);
181  }
182  bool operator>(const int_adapter& rhs) const
183  {
184    return (compare(rhs) == 1);
185  }
186  int_type as_number() const
187  {
188    return value_;
189  }
190  //! Returns either special value type or is_not_special
191  special_values as_special() const
192  {
193    return int_adapter::to_special(value_);
194  }
195  //creates nasty ambiguities
196//   operator int_type() const
197//   {
198//     return value_;
199//   }
200
201  /*! Operator allows for adding dissimilar int_adapter types.
202   * The return type will match that of the the calling object's type */
203  template<class rhs_type>
204  inline
205  int_adapter operator+(const int_adapter<rhs_type>& rhs) const
206  {
207    if(is_special() || rhs.is_special())
208    {
209      if (is_nan() || rhs.is_nan())
210      {
211        return int_adapter::not_a_number();
212      }
213      if((is_pos_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ||
214      (is_neg_inf(value_) && rhs.is_pos_inf(rhs.as_number())) )
215      {
216        return int_adapter::not_a_number();
217      }
218      if (is_infinity())
219      {
220        return *this;
221      }
222      if (rhs.is_pos_inf(rhs.as_number()))
223      {
224        return int_adapter::pos_infinity();
225      }
226      if (rhs.is_neg_inf(rhs.as_number()))
227      {
228        return int_adapter::neg_infinity();
229      }
230    }
231    return int_adapter<int_type>(value_ + rhs.as_number());
232  }
233
234  int_adapter operator+(const int_type rhs) const
235  {
236    if(is_special())
237    {
238      if (is_nan())
239      {
240        return int_adapter<int_type>(not_a_number());
241      }
242      if (is_infinity())
243      {
244        return *this;
245      }
246    }
247    return int_adapter<int_type>(value_ + rhs);
248  }
249 
250  /*! Operator allows for subtracting dissimilar int_adapter types.
251   * The return type will match that of the the calling object's type */
252  template<class rhs_type>
253  inline
254  int_adapter operator-(const int_adapter<rhs_type>& rhs)const
255  {
256    if(is_special() || rhs.is_special())
257    {
258      if (is_nan() || rhs.is_nan())
259      {
260        return int_adapter::not_a_number();
261      }
262      if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) ||
263         (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) )
264      {
265        return int_adapter::not_a_number();
266      }
267      if (is_infinity())
268      {
269        return *this;
270      }
271      if (rhs.is_pos_inf(rhs.as_number()))
272      {
273        return int_adapter::neg_infinity();
274      }
275      if (rhs.is_neg_inf(rhs.as_number()))
276      {
277        return int_adapter::pos_infinity();
278      }
279    }
280    return int_adapter<int_type>(value_ - rhs.as_number());
281  }
282  int_adapter operator-(const int_type rhs) const
283  {
284    if(is_special())
285    {
286      if (is_nan())
287      {
288        return int_adapter<int_type>(not_a_number());
289      }
290      if (is_infinity())
291      {
292        return *this;
293      }
294    }
295    return int_adapter<int_type>(value_ - rhs);
296  }
297
298  // should templatize this to be consistant with op +-
299  int_adapter operator*(const int_adapter& rhs)const
300  {
301    if(this->is_special() || rhs.is_special())
302    {
303      return mult_div_specials(rhs);
304    }
305    return int_adapter<int_type>(value_ * rhs.value_);
306  }
307  /*! Provided for cases when automatic conversion from
308   * 'int' to 'int_adapter' causes incorrect results. */
309  int_adapter operator*(const int rhs) const
310  {
311    if(is_special())
312    {
313      return mult_div_specials(rhs);
314    }
315    return int_adapter<int_type>(value_ * rhs);
316  }
317
318  // should templatize this to be consistant with op +-
319  int_adapter operator/(const int_adapter& rhs)const
320  {
321    if(this->is_special() || rhs.is_special())
322    {
323      if(is_infinity() && rhs.is_infinity())
324      {
325        return int_adapter<int_type>(not_a_number());
326      }
327      if(rhs != 0)
328      {
329        return mult_div_specials(rhs);
330      }
331      else { // let divide by zero blow itself up
332        return int_adapter<int_type>(value_ / rhs.value_);
333      }
334    }
335    return int_adapter<int_type>(value_ / rhs.value_);
336  }
337  /*! Provided for cases when automatic conversion from
338   * 'int' to 'int_adapter' causes incorrect results. */
339  int_adapter operator/(const int rhs) const
340  {
341    if(is_special() && rhs != 0)
342    {
343      return mult_div_specials(rhs);
344    }
345    return int_adapter<int_type>(value_ / rhs);
346  }
347
348  // should templatize this to be consistant with op +-
349  int_adapter operator%(const int_adapter& rhs)const
350  {
351    if(this->is_special() || rhs.is_special())
352    {
353      if(is_infinity() && rhs.is_infinity())
354      {
355        return int_adapter<int_type>(not_a_number());
356      }
357      if(rhs != 0)
358      {
359        return mult_div_specials(rhs);
360      }
361      else { // let divide by zero blow itself up
362        return int_adapter<int_type>(value_ % rhs.value_);
363      }
364    }
365    return int_adapter<int_type>(value_ % rhs.value_);
366  }
367  /*! Provided for cases when automatic conversion from
368   * 'int' to 'int_adapter' causes incorrect results. */
369  int_adapter operator%(const int rhs) const
370  {
371    if(is_special() && rhs != 0)
372    {
373      return mult_div_specials(rhs);
374    }
375    return int_adapter<int_type>(value_ % rhs);
376  }
377private:
378  int_type value_;
379 
380  //! returns -1, 0, 1, or 2 if 'this' is <, ==, >, or 'nan comparison' rhs
381  int compare(const int_adapter& rhs)const
382  {
383    if(this->is_special() || rhs.is_special())
384    {
385      if(this->is_nan() || rhs.is_nan()) {
386        if(this->is_nan() && rhs.is_nan()) {
387          return 0; // equal
388        }
389        else {
390          return 2; // nan
391        }
392      }
393      if((is_neg_inf(value_) && !is_neg_inf(rhs.value_)) ||
394         (is_pos_inf(rhs.value_) && !is_pos_inf(value_)) )
395        {
396          return -1; // less than
397        }
398      if((is_pos_inf(value_) && !is_pos_inf(rhs.value_)) ||
399         (is_neg_inf(rhs.value_) && !is_neg_inf(value_)) ) {
400        return 1; // greater than
401      }
402    }
403    if(value_ < rhs.value_) return -1;
404    if(value_ > rhs.value_) return 1;
405    // implied-> if(value_ == rhs.value_)
406    return 0;
407  }
408  /* When multiplying and dividing with at least 1 special value
409   * very simmilar rules apply. In those cases where the rules
410   * are different, they are handled in the respective operator
411   * function. */
412  //! Assumes at least 'this' or 'rhs' is a special value
413  int_adapter mult_div_specials(const int_adapter& rhs)const
414  {
415    int min_value;
416    // quiets compiler warnings
417    bool is_signed = std::numeric_limits<int_type>::is_signed;
418    if(is_signed) {
419      min_value = 0;
420    }
421    else {
422      min_value = 1;// there is no zero with unsigned
423    }
424    if(this->is_nan() || rhs.is_nan()) {
425      return int_adapter<int_type>(not_a_number());
426    }
427    if((*this > 0 && rhs > 0) || (*this < min_value && rhs < min_value)) {
428        return int_adapter<int_type>(pos_infinity());
429    }
430    if((*this > 0 && rhs < min_value) || (*this < min_value && rhs > 0)) {
431        return int_adapter<int_type>(neg_infinity());
432    }
433    //implied -> if(this->value_ == 0 || rhs.value_ == 0)
434    return int_adapter<int_type>(not_a_number());
435  }
436  /* Overloaded function necessary because of special
437   * situation where int_adapter is instantiated with
438   * 'unsigned' and func is called with negative int.
439   * It would produce incorrect results since 'unsigned'
440   * wraps around when initialized with a negative value */
441  //! Assumes 'this' is a special value
442  int_adapter mult_div_specials(const int& rhs) const
443  {
444    int min_value;
445    // quiets compiler warnings
446    bool is_signed = std::numeric_limits<int_type>::is_signed;
447    if(is_signed) {
448      min_value = 0;
449    }
450    else {
451      min_value = 1;// there is no zero with unsigned
452    }
453    if(this->is_nan()) {
454      return int_adapter<int_type>(not_a_number());
455    }
456    if((*this > 0 && rhs > 0) || (*this < min_value && rhs < 0)) {
457        return int_adapter<int_type>(pos_infinity());
458    }
459    if((*this > 0 && rhs < 0) || (*this < min_value && rhs > 0)) {
460        return int_adapter<int_type>(neg_infinity());
461    }
462    //implied -> if(this->value_ == 0 || rhs.value_ == 0)
463    return int_adapter<int_type>(not_a_number());
464  }
465 
466};
467
468#ifndef BOOST_DATE_TIME_NO_LOCALE
469  /*! Expected output is either a numeric representation
470   * or a special values representation.<BR>
471   * Ex. "12", "+infinity", "not-a-number", etc. */
472  //template<class charT = char, class traits = std::traits<charT>, typename int_type>
473  template<class charT, class traits, typename int_type>
474  inline
475  std::basic_ostream<charT, traits>&
476  operator<<(std::basic_ostream<charT, traits>& os, const int_adapter<int_type>& ia)
477  {
478    if(ia.is_special()) {
479      // switch copied from date_names_put.hpp
480      switch(ia.as_special())
481        {
482      case not_a_date_time:
483        os << "not-a-number";
484        break;
485      case pos_infin:
486        os << "+infinity";
487        break;
488      case neg_infin:
489        os << "-infinity";
490        break;
491      default:
492        os << "";
493      }
494    }
495    else {
496      os << ia.as_number();
497    }
498    return os;
499  }
500#endif
501
502
503} } //namespace date_time
504
505
506
507#endif
Note: See TracBrowser for help on using the repository browser.