1 #ifndef _DATE_TIME_WRAPPING_INT_HPP__
2 #define _DATE_TIME_WRAPPING_INT_HPP__
3 
4 /* Copyright (c) 2002,2003,2005 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 namespace boost {
14 namespace date_time {
15 
16 //! A wrapping integer used to support time durations (WARNING: only instantiate with a signed type)
17 /*! In composite date and time types this type is used to
18  *  wrap at the day boundary.
19  *  Ex:
20  *  A wrapping_int<short, 10> will roll over after nine, and
21  *  roll under below zero. This gives a range of [0,9]
22  *
23  * NOTE: it is strongly recommended that wrapping_int2 be used
24  * instead of wrapping_int as wrapping_int is to be depricated
25  * at some point soon.
26  *
27  * Also Note that warnings will occur if instantiated with an
28  * unsigned type. Only a signed type should be used!
29  */
30 template<typename int_type_, int_type_ wrap_val>
31 class wrapping_int {
32 public:
33   typedef int_type_ int_type;
34   //typedef overflow_type_ overflow_type;
wrap_value()35   static int_type wrap_value() {return wrap_val;}
36   //!Add, return true if wrapped
wrapping_int(int_type v)37   wrapping_int(int_type v) : value_(v) {}
38   //! Explicit converion method
as_int() const39   int_type as_int()   const   {return value_;}
operator int_type() const40   operator int_type() const   {return value_;}
41   //!Add, return number of wraps performed
42   /*! The sign of the returned value will indicate which direction the
43    * wraps went. Ex: add a negative number and wrapping under could occur,
44    * this would be indicated by a negative return value. If wrapping over
45    * took place, a positive value would be returned */
46   template< typename IntT >
add(IntT v)47   IntT add(IntT v)
48   {
49     int_type remainder = static_cast<int_type>(v % (wrap_val));
50     IntT overflow = static_cast<IntT>(v / (wrap_val));
51     value_ = static_cast<int_type>(value_ + remainder);
52     return calculate_wrap(overflow);
53   }
54   //! Subtract will return '+d' if wrapping under took place ('d' is the number of wraps)
55   /*! The sign of the returned value will indicate which direction the
56    * wraps went (positive indicates wrap under, negative indicates wrap over).
57    * Ex: subtract a negative number and wrapping over could
58    * occur, this would be indicated by a negative return value. If
59    * wrapping under took place, a positive value would be returned. */
60   template< typename IntT >
subtract(IntT v)61   IntT subtract(IntT v)
62   {
63     int_type remainder = static_cast<int_type>(v % (wrap_val));
64     IntT underflow = static_cast<IntT>(-(v / (wrap_val)));
65     value_ = static_cast<int_type>(value_ - remainder);
66     return calculate_wrap(underflow) * -1;
67   }
68 private:
69   int_type value_;
70 
71   template< typename IntT >
calculate_wrap(IntT wrap)72   IntT calculate_wrap(IntT wrap)
73   {
74     if ((value_) >= wrap_val)
75     {
76       ++wrap;
77       value_ -= (wrap_val);
78     }
79     else if(value_ < 0)
80     {
81       --wrap;
82       value_ += (wrap_val);
83     }
84     return wrap;
85   }
86 
87 };
88 
89 
90 //! A wrapping integer used to wrap around at the top (WARNING: only instantiate with a signed type)
91 /*! Bad name, quick impl to fix a bug -- fix later!!
92  *  This allows the wrap to restart at a value other than 0.
93  */
94 template<typename int_type_, int_type_ wrap_min, int_type_ wrap_max>
95 class wrapping_int2 {
96 public:
97   typedef int_type_ int_type;
wrap_value()98   static int_type wrap_value() {return wrap_max;}
min_value()99   static int_type min_value()  {return wrap_min;}
100   /*! If initializing value is out of range of [wrap_min, wrap_max],
101    * value will be initialized to closest of min or max */
wrapping_int2(int_type v)102   wrapping_int2(int_type v) : value_(v) {
103     if(value_ < wrap_min)
104     {
105       value_ = wrap_min;
106     }
107     if(value_ > wrap_max)
108     {
109       value_ = wrap_max;
110     }
111   }
112   //! Explicit converion method
as_int() const113   int_type as_int()   const   {return value_;}
operator int_type() const114   operator int_type() const {return value_;}
115   //!Add, return number of wraps performed
116   /*! The sign of the returned value will indicate which direction the
117    * wraps went. Ex: add a negative number and wrapping under could occur,
118    * this would be indicated by a negative return value. If wrapping over
119    * took place, a positive value would be returned */
120   template< typename IntT >
add(IntT v)121   IntT add(IntT v)
122   {
123     int_type remainder = static_cast<int_type>(v % (wrap_max - wrap_min + 1));
124     IntT overflow = static_cast<IntT>(v / (wrap_max - wrap_min + 1));
125     value_ = static_cast<int_type>(value_ + remainder);
126     return calculate_wrap(overflow);
127   }
128   //! Subtract will return '-d' if wrapping under took place ('d' is the number of wraps)
129   /*! The sign of the returned value will indicate which direction the
130    * wraps went. Ex: subtract a negative number and wrapping over could
131    * occur, this would be indicated by a positive return value. If
132    * wrapping under took place, a negative value would be returned */
133   template< typename IntT >
subtract(IntT v)134   IntT subtract(IntT v)
135   {
136     int_type remainder = static_cast<int_type>(v % (wrap_max - wrap_min + 1));
137     IntT underflow = static_cast<IntT>(-(v / (wrap_max - wrap_min + 1)));
138     value_ = static_cast<int_type>(value_ - remainder);
139     return calculate_wrap(underflow);
140   }
141 
142 private:
143   int_type value_;
144 
145   template< typename IntT >
calculate_wrap(IntT wrap)146   IntT calculate_wrap(IntT wrap)
147   {
148     if ((value_) > wrap_max)
149     {
150       ++wrap;
151       value_ -= (wrap_max - wrap_min + 1);
152     }
153     else if((value_) < wrap_min)
154     {
155       --wrap;
156       value_ += (wrap_max - wrap_min + 1);
157     }
158     return wrap;
159   }
160 };
161 
162 
163 
164 } } //namespace date_time
165 
166 
167 
168 #endif
169 
170