Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / date_time / int_adapter.hpp
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
19 namespace boost {
20 namespace 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  */
37 template<typename int_type_>
38 class int_adapter {
39 public:
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   }
377 private:
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