period.hpp 12 KB

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