]> rtime.felk.cvut.cz Git - eurobot/public.git/blob - src/boost/boost/date_time/int_adapter.hpp
Add subset of boost library headers needed for compilation on PowerPC
[eurobot/public.git] / src / boost / 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.txt or http://www.boost.org/LICENSE_1_0.txt)
8  * Author: Jeff Garland, Bart Garst
9  * $Date: 2008-11-12 14:37:53 -0500 (Wed, 12 Nov 2008) $
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_ + 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_ - 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