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