revision.hpp
Go to the documentation of this file.
/**
* @file svnxx/revision.hpp
* @copyright
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
* @endcopyright
*/
#ifndef SVNXX_REVISION_HPP
#define SVNXX_REVISION_HPP
#include "svn_opt_impl.h"
#include "svn_types_impl.h"
#include <chrono>
#include <cstdint>
#include <new>
#include "tristate.hpp"
namespace apache {
namespace subversion {
namespace svnxx {
/**
* @brief A revision, see @ref svn_opt_revision_t.
*
* The @c revision can represent a revision number, a point in time
* in the repository or a property of the working copy or repository
* node (see revision::kind).
*/
class revision
{
public:
/**
* @brief Revision number type.
*/
enum class number : svn_revnum_t
{
invalid = SVN_INVALID_REVNUM, ///< Invalid revision number.
};
/**
* @brief Revision by date/time uses the system clock.
*/
template<typename Duration>
using time = std::chrono::time_point<std::chrono::system_clock, Duration>;
/**
* @brief The resolution of the stored date/time.
*/
using usec = std::chrono::microseconds;
/**
* @brief Revision kind discriminator (see @ref svn_opt_revision_kind).
*/
// NOTE: Keep these values identical to those in svn_opt_revision_kind!
enum class kind : std::int8_t
{
unspecified = svn_opt_revision_unspecified,
number = svn_opt_revision_number,
date = svn_opt_revision_date,
committed = svn_opt_revision_committed,
previous = svn_opt_revision_previous,
base = svn_opt_revision_base,
working = svn_opt_revision_working,
head = svn_opt_revision_head,
};
/**
* @brief Default constructor.
* @post get_kind() == kind::unspecified.
*/
revision() noexcept
: tag(kind::unspecified)
{}
/**
* @brief Construct a revision of the given kind.
* @pre The @a revkind argument may be any @c kind value @b except
* kind::number or kind::date, which require additional
* parameters and therefore have their own constructors.
* @post get_kind() == @a revkind.
* @throw std::invalid_argument if the @a revkind value
* precondition is not met.
*/
explicit revision(kind revkind)
: tag(revkind)
{
if (revkind == kind::number || revkind == kind::date)
throw std::invalid_argument("invalid svn::revision::kind");
}
/**
* @brief Construct a numbered revision.
* @post get_kind() == kind::number.
*/
explicit revision(number revnum_) noexcept
: tag(kind::number),
revnum(revnum_)
{}
/**
* @brief Construct a dated revision from a system clock time point.
* @post get_kind() == kind::date.
*/
template<typename D>
explicit revision(time<D> time_) noexcept
: tag(kind::date),
date(std::chrono::time_point_cast<usec>(time_))
{}
/**
* @brief Assignment operator.
* Uses in-place destruction/construction to maintain the immutability
* of the revision kind.
*/
revision& operator=(const revision& that)
{
this->~revision();
new(this) revision(that);
return *this;
}
/**
* @brief Return the revision kind.
*/
kind get_kind() const noexcept
{
return tag;
}
/**
* @brief Return the revision number.
* @pre get_kind() == kind::number.
* @throw std::logic_error if the precondition is not met.
*/
number get_number() const
{
if (tag != kind::number)
throw std::logic_error("svn::revision kind != number");
return revnum;
}
/**
* @brief Return the revision date/time as a system clock time point.
* @pre get_kind() == kind::date.
* @throw std::logic_error if the precondition is not met.
*/
template<typename D>
time<D> get_date() const
{
if (tag != kind::date)
throw std::logic_error("svn::revision kind != date");
return std::chrono::time_point_cast<D>(date);
}
private:
// Even if we were using C++17, we wouldn't use std::variant because we
// already maintain an explicit discriminator tag for the union.
const kind tag; // Union discriminator
union {
number revnum; // (tag == kind::number): revision number.
time<usec> date; // (tag == kind::date): microseconds from epoch.
};
};
/**
* @related revision
* @brief revision::number alias for convenience.
*/
using revnum = revision::number;
/**
* @related revision
* @brief Equality comparison.
*/
inline bool operator==(const revision& a, const revision& b)
{
const auto kind = a.get_kind();
if (kind != b.get_kind())
return false;
else if (kind == revision::kind::number)
return a.get_number() == b.get_number();
else if (kind == revision::kind::date)
return a.get_date<revision::usec>() == b.get_date<revision::usec>();
else
return true;
}
/**
* @related revision
* @brief Inequality comparison.
*/
inline bool operator!=(const revision& a, const revision& b)
{
return !(a == b);
}
/**
* @related revision
* @brief Ordering: less-than (<tt>operator @<</tt>).
* @returns a @c tristate result of comparing two @c revision values,
* according to the following table:
* <table border=1>
* <tr>
* <th><center><code>@<</code></center></th>
* <th><center><tt>number</tt></center></th>
* <th><center><tt>date</tt></center></th>
* <th><center><em>other</em></center></th>
* </tr>
* <tr>
* <th><center><tt>number</tt></center></th>
* <td><center><tt>a.get_number() < b.get_number()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><tt>date</tt></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><tt>a.get_date() < b.get_date()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><em>other</em></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* </table>
*/
inline tristate operator<(const revision& a, const revision& b)
{
const auto kind = a.get_kind();
if (kind != b.get_kind())
return tristate::unknown();
else if (kind == revision::kind::number)
return a.get_number() < b.get_number();
else if (kind == revision::kind::date)
return a.get_date<revision::usec>() < b.get_date<revision::usec>();
else
return tristate::unknown();
}
/**
* @related revision
* @brief Ordering: greater-than (<tt>operator @></tt>).
* @returns a @c tristate result of comparing two @c revision values,
* according to the following table:
* <table border=1>
* <tr>
* <th><center><code>@></code></center></th>
* <th><center><tt>number</tt></center></th>
* <th><center><tt>date</tt></center></th>
* <th><center><em>other</em></center></th>
* </tr>
* <tr>
* <th><center><tt>number</tt></center></th>
* <td><center><tt>a.get_number() > b.get_number()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><tt>date</tt></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><tt>a.get_date() > b.get_date()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><em>other</em></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* </table>
*/
inline tristate operator>(const revision& a, const revision& b)
{
const auto kind = a.get_kind();
if (kind != b.get_kind())
return tristate::unknown();
else if (kind == revision::kind::number)
return a.get_number() > b.get_number();
else if (kind == revision::kind::date)
return a.get_date<revision::usec>() > b.get_date<revision::usec>();
else
return tristate::unknown();
}
/**
* @related revision
* @brief Ordering: less-or-equal (<tt>operator @<=</tt>).
* @returns a @c tristate result of comparing two @c revision values,
* according to the following table:
* <table border=1>
* <tr>
* <th><center><code>@<=</code></center></th>
* <th><center><tt>number</tt></center></th>
* <th><center><tt>date</tt></center></th>
* <th><center><em>other</em></center></th>
* </tr>
* <tr>
* <th><center><tt>number</tt></center></th>
* <td><center><tt>a.get_number() <= b.get_number()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><tt>date</tt></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><tt>a.get_date() <= b.get_date()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><em>other</em></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>true</em>&dagger; or <em>unknown</em></center></td>
* </tr>
* </table>
* &dagger; <em>true</em> when <tt>a.get_kind() == b.get_kind()</tt>.
*/
inline tristate operator<=(const revision& a, const revision& b)
{
return (a == b || !(a > b));
}
/**
* @related revision
* @brief Ordering: greater-or-equal (<tt>operator @>=</tt>).
* @returns a @c tristate result of comparing two @c revision values,
* according to the following table:
* <table border=1>
* <tr>
* <th><center><code>@>=</code></center></th>
* <th><center><tt>number</tt></center></th>
* <th><center><tt>date</tt></center></th>
* <th><center><em>other</em></center></th>
* </tr>
* <tr>
* <th><center><tt>number</tt></center></th>
* <td><center><tt>a.get_number() >= b.get_number()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><tt>date</tt></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><tt>a.get_date() >= b.get_date()</tt></center></td>
* <td><center><em>unknown</em></center></td>
* </tr>
* <tr>
* <th><center><em>other</em></center></th>
* <td><center><em>unknown</em></center></td>
* <td><center><em>unknown</em></center></td>
* <td><center><em>true</em>&dagger; or <em>unknown</em></center></td>
* </tr>
* </table>
* &dagger; <em>true</em> when <tt>a.get_kind() == b.get_kind()</tt>.
*/
inline tristate operator>=(const revision& a, const revision& b)
{
return (a == b || !(a < b));
}
} // namespace svnxx
} // namespace subversion
} // namespace apache
#endif // SVNXX_REVISION_HPP
apache::subversion::svnxx::revision
A revision, see svn_opt_revision_t.
Definition: revision.hpp:49
apache::subversion::svnxx::revision::operator>
tristate operator>(const revision &a, const revision &b)
Ordering: greater-than (operator >).
Definition: revision.hpp:293
apache::subversion::svnxx::revision::operator!=
bool operator!=(const revision &a, const revision &b)
Inequality comparison.
Definition: revision.hpp:211
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
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::revision
revision(number revnum_) noexcept
Construct a numbered revision.
Definition: revision.hpp:114
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::usec
std::chrono::microseconds usec
The resolution of the stored date/time.
Definition: revision.hpp:68
apache::subversion::svnxx::revision::get_number
number get_number() const
Return the revision number.
Definition: revision.hpp:154
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::get_date
time< D > get_date() const
Return the revision date/time as a system clock time point.
Definition: revision.hpp:167
apache::subversion::svnxx::revision::operator==
bool operator==(const revision &a, const revision &b)
Equality comparison.
Definition: revision.hpp:194
apache::subversion::svnxx::revision::number
number
Revision number type.
Definition: revision.hpp:55
apache::subversion::svnxx::revision::number::invalid
@ invalid
Invalid revision number.
apache::subversion::svnxx::revision::operator=
revision & operator=(const revision &that)
Assignment operator.
Definition: revision.hpp:134
apache::subversion::svnxx::revision::revision
revision(kind revkind)
Construct a revision of the given kind.
Definition: revision.hpp:103
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::operator>=
tristate operator>=(const revision &a, const revision &b)
Ordering: greater-or-equal (operator >=).
Definition: revision.hpp:377
apache::subversion::svnxx::revision::get_kind
kind get_kind() const noexcept
Return the revision kind.
Definition: revision.hpp:144
apache::subversion::svnxx::revision::kind
kind
Revision kind discriminator (see svn_opt_revision_kind).
Definition: revision.hpp:75
apache::subversion::svnxx::tristate
A three-state Boolean-like type.
Definition: tristate.hpp:70
apache::subversion::svnxx::tristate::unknown
static constexpr tristate unknown() noexcept
Factory method for the unknown state.
Definition: tristate.hpp:86
svn_opt_impl.h
Option and argument parsing for Subversion command lines (common implementation)
svn_opt_revision_head
@ svn_opt_revision_head
repository youngest
Definition: svn_opt_impl.h:77
svn_opt_revision_working
@ svn_opt_revision_working
current, plus local mods
Definition: svn_opt_impl.h:74
svn_opt_revision_number
@ svn_opt_revision_number
revision given as number
Definition: svn_opt_impl.h:59
svn_opt_revision_date
@ svn_opt_revision_date
revision given as date
Definition: svn_opt_impl.h:62
svn_opt_revision_unspecified
@ svn_opt_revision_unspecified
No revision information given.
Definition: svn_opt_impl.h:56
svn_opt_revision_committed
@ svn_opt_revision_committed
rev of most recent change
Definition: svn_opt_impl.h:65
svn_opt_revision_previous
@ svn_opt_revision_previous
(rev of most recent change) - 1
Definition: svn_opt_impl.h:68
svn_opt_revision_base
@ svn_opt_revision_base
.svn/entries current revision
Definition: svn_opt_impl.h:71
svn_types_impl.h
Subversion's data types (common implementation)
SVN_INVALID_REVNUM
#define SVN_INVALID_REVNUM
The 'official' invalid revision number.
Definition: svn_types_impl.h:99
svn_revnum_t
long int svn_revnum_t
A revision number.
Definition: svn_types_impl.h:95
tristate.hpp