Subversion
revision.hpp
Go to the documentation of this file.
1 /**
2  * @file svnxx/revision.hpp
3  * @copyright
4  * ====================================================================
5  * Licensed to the Apache Software Foundation (ASF) under one
6  * or more contributor license agreements. See the NOTICE file
7  * distributed with this work for additional information
8  * regarding copyright ownership. The ASF licenses this file
9  * to you under the Apache License, Version 2.0 (the
10  * "License"); you may not use this file except in compliance
11  * with the License. You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing,
16  * software distributed under the License is distributed on an
17  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  * KIND, either express or implied. See the License for the
19  * specific language governing permissions and limitations
20  * under the License.
21  * ====================================================================
22  * @endcopyright
23  */
24 
25 #ifndef SVNXX_REVISION_HPP
26 #define SVNXX_REVISION_HPP
27 
28 #include "svn_opt_impl.h"
29 #include "svn_types_impl.h"
30 
31 #include <chrono>
32 #include <cstdint>
33 #include <new>
34 
35 #include "tristate.hpp"
36 
37 namespace apache {
38 namespace subversion {
39 namespace svnxx {
40 
41 /**
42  * @brief A revision, see @ref svn_opt_revision_t.
43  *
44  * The @c revision can represent a revision number, a point in time
45  * in the repository or a property of the working copy or repository
46  * node (see revision::kind).
47  */
48 class revision
49 {
50 public:
51  /**
52  * @brief Revision number type.
53  */
54  enum class number : svn_revnum_t
55  {
56  invalid = SVN_INVALID_REVNUM, ///< Invalid revision number.
57  };
58 
59  /**
60  * @brief Revision by date/time uses the system clock.
61  */
62  template<typename Duration>
63  using time = std::chrono::time_point<std::chrono::system_clock, Duration>;
64 
65  /**
66  * @brief The resolution of the stored date/time.
67  */
68  using usec = std::chrono::microseconds;
69 
70  /**
71  * @brief Revision kind discriminator (see @ref svn_opt_revision_kind).
72  */
73  // NOTE: Keep these values identical to those in svn_opt_revision_kind!
74  enum class kind : std::int8_t
75  {
76  unspecified = svn_opt_revision_unspecified,
78  date = svn_opt_revision_date,
79  committed = svn_opt_revision_committed,
80  previous = svn_opt_revision_previous,
81  base = svn_opt_revision_base,
82  working = svn_opt_revision_working,
83  head = svn_opt_revision_head,
84  };
85 
86  /**
87  * @brief Default constructor.
88  * @post get_kind() == kind::unspecified.
89  */
90  revision() noexcept
91  : tag(kind::unspecified)
92  {}
93 
94  /**
95  * @brief Construct a revision of the given kind.
96  * @pre The @a revkind argument may be any @c kind value @b except
97  * kind::number or kind::date, which require additional
98  * parameters and therefore have their own constructors.
99  * @post get_kind() == @a revkind.
100  * @throw std::invalid_argument if the @a revkind value
101  * precondition is not met.
102  */
103  explicit revision(kind revkind)
104  : tag(revkind)
105  {
106  if (revkind == kind::number || revkind == kind::date)
107  throw std::invalid_argument("invalid svn::revision::kind");
108  }
109 
110  /**
111  * @brief Construct a numbered revision.
112  * @post get_kind() == kind::number.
113  */
114  explicit revision(number revnum_) noexcept
115  : tag(kind::number),
116  revnum(revnum_)
117  {}
118 
119  /**
120  * @brief Construct a dated revision from a system clock time point.
121  * @post get_kind() == kind::date.
122  */
123  template<typename D>
124  explicit revision(time<D> time_) noexcept
125  : tag(kind::date),
126  date(std::chrono::time_point_cast<usec>(time_))
127  {}
128 
129  /**
130  * @brief Assignment operator.
131  * Uses in-place destruction/construction to maintain the immutability
132  * of the revision kind.
133  */
135  {
136  this->~revision();
137  new(this) revision(that);
138  return *this;
139  }
140 
141  /**
142  * @brief Return the revision kind.
143  */
144  kind get_kind() const noexcept
145  {
146  return tag;
147  }
148 
149  /**
150  * @brief Return the revision number.
151  * @pre get_kind() == kind::number.
152  * @throw std::logic_error if the precondition is not met.
153  */
155  {
156  if (tag != kind::number)
157  throw std::logic_error("svn::revision kind != number");
158  return revnum;
159  }
160 
161  /**
162  * @brief Return the revision date/time as a system clock time point.
163  * @pre get_kind() == kind::date.
164  * @throw std::logic_error if the precondition is not met.
165  */
166  template<typename D>
168  {
169  if (tag != kind::date)
170  throw std::logic_error("svn::revision kind != date");
171  return std::chrono::time_point_cast<D>(date);
172  }
173 
174 private:
175  // Even if we were using C++17, we wouldn't use std::variant because we
176  // already maintain an explicit discriminator tag for the union.
177  const kind tag; // Union discriminator
178  union {
179  number revnum; // (tag == kind::number): revision number.
180  time<usec> date; // (tag == kind::date): microseconds from epoch.
181  };
182 };
183 
184 /**
185  * @related revision
186  * @brief revision::number alias for convenience.
187  */
189 
190 /**
191  * @related revision
192  * @brief Equality comparison.
193  */
194 inline bool operator==(const revision& a, const revision& b)
195 {
196  const auto kind = a.get_kind();
197  if (kind != b.get_kind())
198  return false;
199  else if (kind == revision::kind::number)
200  return a.get_number() == b.get_number();
201  else if (kind == revision::kind::date)
202  return a.get_date<revision::usec>() == b.get_date<revision::usec>();
203  else
204  return true;
205 }
206 
207 /**
208  * @related revision
209  * @brief Inequality comparison.
210  */
211 inline bool operator!=(const revision& a, const revision& b)
212 {
213  return !(a == b);
214 }
215 
216 /**
217  * @related revision
218  * @brief Ordering: less-than (<tt>operator @<</tt>).
219  * @returns a @c tristate result of comparing two @c revision values,
220  * according to the following table:
221  * <table border=1>
222  * <tr>
223  * <th><center><code>@<</code></center></th>
224  * <th><center><tt>number</tt></center></th>
225  * <th><center><tt>date</tt></center></th>
226  * <th><center><em>other</em></center></th>
227  * </tr>
228  * <tr>
229  * <th><center><tt>number</tt></center></th>
230  * <td><center><tt>a.get_number() < b.get_number()</tt></center></td>
231  * <td><center><em>unknown</em></center></td>
232  * <td><center><em>unknown</em></center></td>
233  * </tr>
234  * <tr>
235  * <th><center><tt>date</tt></center></th>
236  * <td><center><em>unknown</em></center></td>
237  * <td><center><tt>a.get_date() < b.get_date()</tt></center></td>
238  * <td><center><em>unknown</em></center></td>
239  * </tr>
240  * <tr>
241  * <th><center><em>other</em></center></th>
242  * <td><center><em>unknown</em></center></td>
243  * <td><center><em>unknown</em></center></td>
244  * <td><center><em>unknown</em></center></td>
245  * </tr>
246  * </table>
247  */
248 inline tristate operator<(const revision& a, const revision& b)
249 {
250  const auto kind = a.get_kind();
251  if (kind != b.get_kind())
252  return tristate::unknown();
253  else if (kind == revision::kind::number)
254  return a.get_number() < b.get_number();
255  else if (kind == revision::kind::date)
256  return a.get_date<revision::usec>() < b.get_date<revision::usec>();
257  else
258  return tristate::unknown();
259 }
260 
261 /**
262  * @related revision
263  * @brief Ordering: greater-than (<tt>operator @></tt>).
264  * @returns a @c tristate result of comparing two @c revision values,
265  * according to the following table:
266  * <table border=1>
267  * <tr>
268  * <th><center><code>@></code></center></th>
269  * <th><center><tt>number</tt></center></th>
270  * <th><center><tt>date</tt></center></th>
271  * <th><center><em>other</em></center></th>
272  * </tr>
273  * <tr>
274  * <th><center><tt>number</tt></center></th>
275  * <td><center><tt>a.get_number() > b.get_number()</tt></center></td>
276  * <td><center><em>unknown</em></center></td>
277  * <td><center><em>unknown</em></center></td>
278  * </tr>
279  * <tr>
280  * <th><center><tt>date</tt></center></th>
281  * <td><center><em>unknown</em></center></td>
282  * <td><center><tt>a.get_date() > b.get_date()</tt></center></td>
283  * <td><center><em>unknown</em></center></td>
284  * </tr>
285  * <tr>
286  * <th><center><em>other</em></center></th>
287  * <td><center><em>unknown</em></center></td>
288  * <td><center><em>unknown</em></center></td>
289  * <td><center><em>unknown</em></center></td>
290  * </tr>
291  * </table>
292  */
293 inline tristate operator>(const revision& a, const revision& b)
294 {
295  const auto kind = a.get_kind();
296  if (kind != b.get_kind())
297  return tristate::unknown();
298  else if (kind == revision::kind::number)
299  return a.get_number() > b.get_number();
300  else if (kind == revision::kind::date)
301  return a.get_date<revision::usec>() > b.get_date<revision::usec>();
302  else
303  return tristate::unknown();
304 }
305 
306 /**
307  * @related revision
308  * @brief Ordering: less-or-equal (<tt>operator @<=</tt>).
309  * @returns a @c tristate result of comparing two @c revision values,
310  * according to the following table:
311  * <table border=1>
312  * <tr>
313  * <th><center><code>@<=</code></center></th>
314  * <th><center><tt>number</tt></center></th>
315  * <th><center><tt>date</tt></center></th>
316  * <th><center><em>other</em></center></th>
317  * </tr>
318  * <tr>
319  * <th><center><tt>number</tt></center></th>
320  * <td><center><tt>a.get_number() <= b.get_number()</tt></center></td>
321  * <td><center><em>unknown</em></center></td>
322  * <td><center><em>unknown</em></center></td>
323  * </tr>
324  * <tr>
325  * <th><center><tt>date</tt></center></th>
326  * <td><center><em>unknown</em></center></td>
327  * <td><center><tt>a.get_date() <= b.get_date()</tt></center></td>
328  * <td><center><em>unknown</em></center></td>
329  * </tr>
330  * <tr>
331  * <th><center><em>other</em></center></th>
332  * <td><center><em>unknown</em></center></td>
333  * <td><center><em>unknown</em></center></td>
334  * <td><center><em>true</em>&dagger; or <em>unknown</em></center></td>
335  * </tr>
336  * </table>
337  * &dagger; <em>true</em> when <tt>a.get_kind() == b.get_kind()</tt>.
338  */
339 inline tristate operator<=(const revision& a, const revision& b)
340 {
341  return (a == b || !(a > b));
342 }
343 
344 /**
345  * @related revision
346  * @brief Ordering: greater-or-equal (<tt>operator @>=</tt>).
347  * @returns a @c tristate result of comparing two @c revision values,
348  * according to the following table:
349  * <table border=1>
350  * <tr>
351  * <th><center><code>@>=</code></center></th>
352  * <th><center><tt>number</tt></center></th>
353  * <th><center><tt>date</tt></center></th>
354  * <th><center><em>other</em></center></th>
355  * </tr>
356  * <tr>
357  * <th><center><tt>number</tt></center></th>
358  * <td><center><tt>a.get_number() >= b.get_number()</tt></center></td>
359  * <td><center><em>unknown</em></center></td>
360  * <td><center><em>unknown</em></center></td>
361  * </tr>
362  * <tr>
363  * <th><center><tt>date</tt></center></th>
364  * <td><center><em>unknown</em></center></td>
365  * <td><center><tt>a.get_date() >= b.get_date()</tt></center></td>
366  * <td><center><em>unknown</em></center></td>
367  * </tr>
368  * <tr>
369  * <th><center><em>other</em></center></th>
370  * <td><center><em>unknown</em></center></td>
371  * <td><center><em>unknown</em></center></td>
372  * <td><center><em>true</em>&dagger; or <em>unknown</em></center></td>
373  * </tr>
374  * </table>
375  * &dagger; <em>true</em> when <tt>a.get_kind() == b.get_kind()</tt>.
376  */
377 inline tristate operator>=(const revision& a, const revision& b)
378 {
379  return (a == b || !(a < b));
380 }
381 
382 } // namespace svnxx
383 } // namespace subversion
384 } // namespace apache
385 
386 #endif // SVNXX_REVISION_HPP
apache::subversion::svnxx::revision::number::invalid
@ invalid
Invalid revision number.
tristate.hpp
svn_types_impl.h
Subversion's data types (common implementation)
apache::subversion::svnxx::revision::operator>
tristate operator>(const revision &a, const revision &b)
Ordering: greater-than (operator >).
Definition: revision.hpp:293
svn_opt_impl.h
Option and argument parsing for Subversion command lines (common implementation)
SVN_INVALID_REVNUM
#define SVN_INVALID_REVNUM
The 'official' invalid revision number.
Definition: svn_types_impl.h:99
apache::subversion::svnxx::revision::get_number
number get_number() const
Return the revision number.
Definition: revision.hpp:154
svn_opt_revision_date
@ svn_opt_revision_date
revision given as date
Definition: svn_opt_impl.h:62
apache::subversion::svnxx::revision::number
number
Revision number type.
Definition: revision.hpp:54
apache::subversion::svnxx::revision::revision
revision(kind revkind)
Construct a revision of the given kind.
Definition: revision.hpp:103
apache::subversion::svnxx::revision::time
std::chrono::time_point< std::chrono::system_clock, Duration > time
Revision by date/time uses the system clock.
Definition: revision.hpp:63
svn_opt_revision_working
@ svn_opt_revision_working
current, plus local mods
Definition: svn_opt_impl.h:74
svn_opt_revision_base
@ svn_opt_revision_base
.svn/entries current revision
Definition: svn_opt_impl.h:71
apache::subversion::svnxx::revision::operator=
revision & operator=(const revision &that)
Assignment operator.
Definition: revision.hpp:134
apache::subversion::svnxx::revision::revision
revision(time< D > time_) noexcept
Construct a dated revision from a system clock time point.
Definition: revision.hpp:124
apache::subversion::svnxx::revision::usec
std::chrono::microseconds usec
The resolution of the stored date/time.
Definition: revision.hpp:68
svn_opt_revision_unspecified
@ svn_opt_revision_unspecified
No revision information given.
Definition: svn_opt_impl.h:56
svn_opt_revision_head
@ svn_opt_revision_head
repository youngest
Definition: svn_opt_impl.h:77
apache::subversion::svnxx::revision::operator<=
tristate operator<=(const revision &a, const revision &b)
Ordering: less-or-equal (operator <=).
Definition: revision.hpp:339
apache::subversion::svnxx::revision::revnum
revision::number revnum
revision::number alias for convenience.
Definition: revision.hpp:188
apache::subversion::svnxx::revision::revision
revision() noexcept
Default constructor.
Definition: revision.hpp:90
apache::subversion::svnxx::revision::revision
revision(number revnum_) noexcept
Construct a numbered revision.
Definition: revision.hpp:114
svn_opt_revision_committed
@ svn_opt_revision_committed
rev of most recent change
Definition: svn_opt_impl.h:65
apache::subversion::svnxx::tristate::unknown
static constexpr tristate unknown() noexcept
Factory method for the unknown state.
Definition: tristate.hpp:86
svn_opt_revision_previous
@ svn_opt_revision_previous
(rev of most recent change) - 1
Definition: svn_opt_impl.h:68
apache::subversion::svnxx::revision::operator<
tristate operator<(const revision &a, const revision &b)
Ordering: less-than (operator <).
Definition: revision.hpp:248
apache::subversion::svnxx::revision::operator>=
tristate operator>=(const revision &a, const revision &b)
Ordering: greater-or-equal (operator >=).
Definition: revision.hpp:377
apache::subversion::svnxx::revision::operator==
bool operator==(const revision &a, const revision &b)
Equality comparison.
Definition: revision.hpp:194
apache::subversion::svnxx::revision
A revision, see svn_opt_revision_t.
Definition: revision.hpp:48
svn_revnum_t
long int svn_revnum_t
A revision number.
Definition: svn_types_impl.h:95
apache::subversion::svnxx::revision::kind
kind
Revision kind discriminator (see svn_opt_revision_kind).
Definition: revision.hpp:74
apache::subversion::svnxx::revision::operator!=
bool operator!=(const revision &a, const revision &b)
Inequality comparison.
Definition: revision.hpp:211
apache::subversion::svnxx::revision::get_kind
kind get_kind() const noexcept
Return the revision kind.
Definition: revision.hpp:144
apache::subversion::svnxx::revision::get_date
time< D > get_date() const
Return the revision date/time as a system clock time point.
Definition: revision.hpp:167
svn_opt_revision_number
@ svn_opt_revision_number
revision given as number
Definition: svn_opt_impl.h:59
apache::subversion::svnxx::tristate
A three-state Boolean-like type.
Definition: tristate.hpp:69