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
37namespace apache {
38namespace subversion {
39namespace 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 */
49{
50public:
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,
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
174private:
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 */
194inline 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)
203 else
204 return true;
205}
206
207/**
208 * @related revision
209 * @brief Inequality comparison.
210 */
211inline 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 */
248inline 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)
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 */
293inline 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)
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 */
339inline 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 */
377inline 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
A revision, see svn_opt_revision_t.
Definition: revision.hpp:49
tristate operator>(const revision &a, const revision &b)
Ordering: greater-than (operator >).
Definition: revision.hpp:293
bool operator!=(const revision &a, const revision &b)
Inequality comparison.
Definition: revision.hpp:211
std::chrono::time_point< std::chrono::system_clock, Duration > time
Revision by date/time uses the system clock.
Definition: revision.hpp:63
revision(time< D > time_) noexcept
Construct a dated revision from a system clock time point.
Definition: revision.hpp:124
revision & operator=(const revision &that)
Assignment operator.
Definition: revision.hpp:134
revision(number revnum_) noexcept
Construct a numbered revision.
Definition: revision.hpp:114
revision::number revnum
revision::number alias for convenience.
Definition: revision.hpp:188
revision() noexcept
Default constructor.
Definition: revision.hpp:90
std::chrono::microseconds usec
The resolution of the stored date/time.
Definition: revision.hpp:68
number get_number() const
Return the revision number.
Definition: revision.hpp:154
tristate operator<(const revision &a, const revision &b)
Ordering: less-than (operator <).
Definition: revision.hpp:248
bool operator==(const revision &a, const revision &b)
Equality comparison.
Definition: revision.hpp:194
number
Revision number type.
Definition: revision.hpp:55
time< D > get_date() const
Return the revision date/time as a system clock time point.
Definition: revision.hpp:167
revision(kind revkind)
Construct a revision of the given kind.
Definition: revision.hpp:103
tristate operator<=(const revision &a, const revision &b)
Ordering: less-or-equal (operator <=).
Definition: revision.hpp:339
tristate operator>=(const revision &a, const revision &b)
Ordering: greater-or-equal (operator >=).
Definition: revision.hpp:377
kind get_kind() const noexcept
Return the revision kind.
Definition: revision.hpp:144
kind
Revision kind discriminator (see svn_opt_revision_kind).
Definition: revision.hpp:75
A three-state Boolean-like type.
Definition: tristate.hpp:70
static constexpr tristate unknown() noexcept
Factory method for the unknown state.
Definition: tristate.hpp:86
Option and argument parsing for Subversion command lines (common implementation)
@ svn_opt_revision_head
repository youngest
Definition: svn_opt_impl.h:77
@ svn_opt_revision_working
current, plus local mods
Definition: svn_opt_impl.h:74
@ svn_opt_revision_number
revision given as number
Definition: svn_opt_impl.h:59
@ svn_opt_revision_date
revision given as date
Definition: svn_opt_impl.h:62
@ svn_opt_revision_unspecified
No revision information given.
Definition: svn_opt_impl.h:56
@ svn_opt_revision_committed
rev of most recent change
Definition: svn_opt_impl.h:65
@ svn_opt_revision_previous
(rev of most recent change) - 1
Definition: svn_opt_impl.h:68
@ svn_opt_revision_base
.svn/entries current revision
Definition: svn_opt_impl.h:71
Subversion's data types (common implementation)
#define SVN_INVALID_REVNUM
The 'official' invalid revision number.
long int svn_revnum_t
A revision number.