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

Revision 857, 10.5 KB checked in by igarcia, 18 years ago (diff)
Line 
1#ifndef DATE_TIME_PERIOD_HPP___
2#define DATE_TIME_PERIOD_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: 2005/07/24 23:47:50 $
10 */
11
12/*! \file period.hpp
13  This file contain the implementation of the period abstraction. This is
14  basically the same idea as a range.  Although this class is intended for
15  use in the time library, it is pretty close to general enough for other
16  numeric uses.
17
18*/
19
20#include "boost/operators.hpp"
21
22
23namespace boost {
24namespace date_time {
25  //!Provides generalized period type useful in date-time systems
26  /*!This template uses a class to represent a time point within the period
27    and another class to represent a duration.  As a result, this class is
28    not appropriate for use when the number and duration representation
29    are the same (eg: in the regular number domain).
30   
31    A period can be specified by providing either the begining point and
32    a duration or the begining point and the end point( end is NOT part
33    of the period but 1 unit past it. A period will be "invalid" if either
34    end_point <= begin_point or the given duration is <= 0. Any valid period
35    will return false for is_null().
36   
37    Zero length periods are also considered invalid. Zero length periods are
38    periods where the begining and end points are the same, or, the given
39    duration is zero. For a zero length period, the last point will be one
40    unit less than the begining point.
41
42    In the case that the begin and last are the same, the period has a
43    length of one unit.
44   
45    The best way to handle periods is usually to provide a begining point and
46    a duration.  So, day1 + 7 days is a week period which includes all of the
47    first day and 6 more days (eg: Sun to Sat).
48
49   */
50  template<class point_rep, class duration_rep>
51  class period : private
52      boost::less_than_comparable<period<point_rep, duration_rep>
53    , boost::equality_comparable< period<point_rep, duration_rep>
54    > >
55  {
56  public:
57    typedef point_rep point_type;
58    typedef duration_rep duration_type;
59
60    period(point_rep first_point, point_rep end_point);
61    period(point_rep first_point, duration_rep len);
62    point_rep begin() const;
63    point_rep end() const;
64    point_rep last() const;
65    duration_rep length() const;
66    bool is_null() const;
67    bool operator==(const period& rhs) const;
68    bool operator<(const period& rhs) const;
69    void shift(const duration_rep& d);
70    bool contains(const point_rep& point) const;
71    bool contains(const period& other) const;
72    bool intersects(const period& other) const;
73    bool is_adjacent(const period& other) const;
74    bool is_before(const point_rep& point) const;
75    bool is_after(const point_rep& point) const;
76    period intersection(const period& other) const;
77    period merge(const period& other) const;
78    period span(const period& other) const;
79  private:
80    point_rep begin_;
81    point_rep last_;
82  };
83
84  //! create a period from begin to last eg: [begin,end)
85  /*! If end <= begin then the period will be invalid
86   */
87  template<class point_rep, class duration_rep>
88  inline
89  period<point_rep,duration_rep>::period(point_rep first_point,
90                                         point_rep end_point) :
91    begin_(first_point),
92    last_(end_point - duration_rep::unit())
93  {}
94
95  //! create a period as [begin, begin+len)
96  /*! If len is <= 0 then the period will be invalid
97   */
98  template<class point_rep, class duration_rep>
99  inline
100  period<point_rep,duration_rep>::period(point_rep first_point, duration_rep len) :
101    begin_(first_point),
102    last_(first_point + len-duration_rep::unit())
103  { }
104
105
106  //! Return the first element in the period
107  template<class point_rep, class duration_rep>
108  inline
109  point_rep period<point_rep,duration_rep>::begin() const
110  {
111    return begin_;
112  }
113
114  //! Return one past the last element
115  template<class point_rep, class duration_rep>
116  inline
117  point_rep period<point_rep,duration_rep>::end() const
118  {
119    return last_ + duration_rep::unit();
120  }
121
122  //! Return the last item in the period
123  template<class point_rep, class duration_rep>
124  inline
125  point_rep period<point_rep,duration_rep>::last() const
126  {
127    return last_;
128  }
129
130  //! True if period is ill formed (length is zero or less)
131  template<class point_rep, class duration_rep>
132  inline
133  bool period<point_rep,duration_rep>::is_null() const
134  {
135    return end() <= begin_;
136  }
137
138  //! Return the length of the period
139  template<class point_rep, class duration_rep>
140  inline
141  duration_rep period<point_rep,duration_rep>::length() const
142  {
143    if(last_ < begin_){ // invalid period
144      return last_+duration_rep::unit() - begin_;
145    }
146    else{
147      return end() - begin_; // normal case
148    }
149  }
150
151  //! Equality operator
152  template<class point_rep, class duration_rep>
153  inline
154  bool period<point_rep,duration_rep>::operator==(const period& rhs) const
155  {
156    return  ((begin_ == rhs.begin_) &&
157             (last_ == rhs.last_));
158  }
159
160  //! Strict as defined by rhs.last <= lhs.last
161  template<class point_rep, class duration_rep>
162  inline
163  bool period<point_rep,duration_rep>::operator<(const period& rhs) const
164  {
165    return (last_ < rhs.begin_);
166  }
167
168
169  //! Shift the start and end by the specified amount
170  template<class point_rep, class duration_rep>
171  inline
172  void period<point_rep,duration_rep>::shift(const duration_rep& d)
173  {
174    begin_ = begin_ + d;
175    last_  = last_  + d;
176  }
177
178  //! True if the point is inside the period, zero length periods contain no points
179  template<class point_rep, class duration_rep>
180  inline
181  bool period<point_rep,duration_rep>::contains(const point_rep& point) const
182  {
183    return ((point >= begin_) &&
184            (point <= last_));
185  }
186
187
188  //! True if this period fully contains (or equals) the other period
189  template<class point_rep, class duration_rep>
190  inline
191  bool period<point_rep,duration_rep>::contains(const period<point_rep,duration_rep>& other) const
192  {
193    return ((begin_ <= other.begin_) && (last_ >= other.last_));
194  }
195
196
197  //! True if periods are next to each other without a gap.
198  /* In the example below, p1 and p2 are adjacent, but p3 is not adjacent
199   * with either of p1 or p2.
200   *@code
201   *   [-p1-)
202   *        [-p2-)
203   *          [-p3-)
204   *@endcode
205   */
206  template<class point_rep, class duration_rep>
207  inline
208  bool
209  period<point_rep,duration_rep>::is_adjacent(const period<point_rep,duration_rep>& other) const
210  {
211    return (other.begin() == end() ||
212            begin_ == other.end());
213  }
214
215
216  //! True if all of the period is prior or t < start
217  /* In the example below only point 1 would evaluate to true.
218   *@code
219   *     [---------])
220   * ^   ^    ^     ^   ^
221   * 1   2    3     4   5
222   *
223   *@endcode
224   */
225  template<class point_rep, class duration_rep>
226  inline
227  bool
228  period<point_rep,duration_rep>::is_after(const point_rep& t) const
229  {
230    if (is_null())
231    {
232      return false; //null period isn't after
233    }
234   
235    return t < begin_;
236  }
237
238  //! True if all of the period is prior to the passed point or end <= t
239  /* In the example below points 4 and 5 return true.
240   *@code
241   *     [---------])
242   * ^   ^    ^     ^   ^
243   * 1   2    3     4   5
244   *
245   *@endcode
246   */
247  template<class point_rep, class duration_rep>
248  inline
249  bool
250  period<point_rep,duration_rep>::is_before(const point_rep& t) const
251  {
252    if (is_null())
253    {
254      return false;  //null period isn't before anything
255    }
256   
257    return last_ < t;
258  }
259
260
261  //! True if the periods overlap in any way
262  /* In the example below p1 intersects with p2, p4, and p6.
263   *@code
264   *       [---p1---)
265   *             [---p2---)
266   *                [---p3---)
267   *  [---p4---)
268   * [-p5-)
269   *         [-p6-)
270   *@endcode
271   */
272  template<class point_rep, class duration_rep>
273  inline
274  bool period<point_rep,duration_rep>::intersects(const period<point_rep,duration_rep>& other) const
275  {
276    return ( contains(other.begin_) ||
277             other.contains(begin_) ||
278             ((other.begin_ < begin_) && (other.last_ >= begin_)));
279  }
280
281  //! Returns the period of intersection or invalid range no intersection
282  template<class point_rep, class duration_rep>
283  inline
284  period<point_rep,duration_rep>
285  period<point_rep,duration_rep>::intersection(const period<point_rep,duration_rep>& other) const
286  {
287    if (begin_ > other.begin_) {
288      if (last_ <= other.last_) { //case2
289        return *this; 
290      }
291      //case 1
292      return period<point_rep,duration_rep>(begin_, other.end());
293    }
294    else {
295      if (last_ <= other.last_) { //case3
296        return period<point_rep,duration_rep>(other.begin_, this->end());
297      }
298      //case4
299      return other;
300    }
301    //unreachable
302  }
303
304  //! Returns the union of intersecting periods -- or null period
305  /*!
306   */
307  template<class point_rep, class duration_rep>
308  inline
309  period<point_rep,duration_rep>
310  period<point_rep,duration_rep>::merge(const period<point_rep,duration_rep>& other) const
311  {
312    if (this->intersects(other)) {     
313      if (begin_ < other.begin_) {
314        return period<point_rep,duration_rep>(begin_, last_ > other.last_ ? this->end() : other.end());
315      }
316     
317      return period<point_rep,duration_rep>(other.begin_, last_ > other.last_ ? this->end() : other.end());
318     
319    }
320    return period<point_rep,duration_rep>(begin_,begin_); // no intersect return null
321  }
322
323  //! Combine two periods with earliest start and latest end.
324  /*! Combines two periods and any gap between them such that
325   *  start = min(p1.start, p2.start)
326   *  end   = max(p1.end  , p2.end)
327   *@code
328   *        [---p1---)
329   *                       [---p2---)
330   * result:
331   *        [-----------p3----------)
332   *@endcode
333   */
334  template<class point_rep, class duration_rep>
335  inline
336  period<point_rep,duration_rep>
337  period<point_rep,duration_rep>::span(const period<point_rep,duration_rep>& other) const
338  {
339    point_rep start((begin_ < other.begin_) ? begin() : other.begin());
340    point_rep newend((last_  < other.last_)  ? other.end() : this->end());
341    return period<point_rep,duration_rep>(start, newend);
342  }
343
344
345} } //namespace date_time
346
347
348
349#endif
Note: See TracBrowser for help on using the repository browser.