in C++20, compiler generate operator!=() if the corresponding operator==() is already defined, the language now understands that the comparison is symmetric in the new standard. fortunately, our operator!=() is always equivalent to `! operator==()`, this matches the behavior of the default generated operator!=(). so, in this change, all `operator!=` are removed. in addition to the defaulted operator!=, C++20 also brings to us the defaulted operator==() -- it is able to generated the operator==() if the member-wise lexicographical comparison. under some circumstances, this is exactly what we need. so, in this change, if the operator==() is also implemented as a lexicographical comparison of all memeber variables of the class/struct in question, it is implemented using the default generated one by removing its body and mark the function as `default`. moreover, if the class happen to have other comparison operators which are implemented using lexicographical comparison, the default generated `operator<=>` is used in place of the defaulted `operator==`. sometimes, we fail to mark the operator== with the `const` specifier, in this change, to fulfil the need of C++ standard, and to be more correct, the `const` specifier is added. also, to generate the defaulted operator==, the operand should be `const class_name&`, but it is not always the case, in the class of `version`, we use `version` as the parameter type, to fulfill the need of the C++ standard, the parameter type is changed to `const version&` instead. this does not change the semantic of the comparison operator. and is a more idiomatic way to pass non-trivial struct as function parameters. please note, because in C++20, both operator= and operator<=> are symmetric, some of the operators in `multiprecision` are removed. they are the symmetric form of the another variant. if they were not removed, compiler would, for instance, find ambiguous overloaded operator '=='. this change is a cleanup to modernize the code base with C++20 features. Signed-off-by: Kefu Chai <kefu.chai@scylladb.com> Closes #13687
130 lines
4.4 KiB
C++
130 lines
4.4 KiB
C++
/*
|
|
* Copyright (C) 2017-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <seastar/core/sstring.hh>
|
|
|
|
#include <cstdint>
|
|
#include <string_view>
|
|
#include <ostream>
|
|
#include <stdexcept>
|
|
|
|
// Wrapper for a value with a type-tag for differentiating instances.
|
|
template <class Value, class Tag>
|
|
class cql_duration_counter final {
|
|
public:
|
|
using value_type = Value;
|
|
|
|
explicit constexpr cql_duration_counter(value_type count) noexcept : _count(count) {}
|
|
|
|
constexpr operator value_type() const noexcept { return _count; }
|
|
private:
|
|
value_type _count;
|
|
};
|
|
|
|
using months_counter = cql_duration_counter<int32_t, struct month_tag>;
|
|
using days_counter = cql_duration_counter<int32_t, struct day_tag>;
|
|
using nanoseconds_counter = cql_duration_counter<int64_t, struct nanosecond_tag>;
|
|
|
|
class cql_duration_error : public std::invalid_argument {
|
|
public:
|
|
explicit cql_duration_error(std::string_view what) : std::invalid_argument(what.data()) {}
|
|
|
|
virtual ~cql_duration_error() = default;
|
|
};
|
|
|
|
//
|
|
// A duration of time.
|
|
//
|
|
// Three counters represent the time: the number of months, of days, and of nanoseconds. This is necessary because
|
|
// the number hours in a day can vary during daylight savings and because the number of days in a month vary.
|
|
//
|
|
// As a consequence of this representation, there can exist no total ordering relation on durations. To see why,
|
|
// consider a duration `1mo5s` (1 month and 5 seconds). In a month with 30 days, this represents a smaller duration of
|
|
// time than in a month with 31 days.
|
|
//
|
|
// The primary use of this type is to manipulate absolute time-stamps with relative offsets. For example,
|
|
// `"Jan. 31 2005 at 23:15" + 3mo5d`.
|
|
//
|
|
class cql_duration final {
|
|
public:
|
|
using common_counter_type = int64_t;
|
|
|
|
static_assert(
|
|
(sizeof(common_counter_type) >= sizeof(months_counter::value_type)) &&
|
|
(sizeof(common_counter_type) >= sizeof(days_counter::value_type)) &&
|
|
(sizeof(common_counter_type) >= sizeof(nanoseconds_counter::value_type)),
|
|
"The common counter type is smaller than one of the component counter types.");
|
|
|
|
// A zero-valued duration.
|
|
constexpr cql_duration() noexcept = default;
|
|
|
|
// Construct a duration with explicit values for its three counters.
|
|
constexpr cql_duration(months_counter m, days_counter d, nanoseconds_counter n) noexcept :
|
|
months(m),
|
|
days(d),
|
|
nanoseconds(n) {}
|
|
|
|
//
|
|
// Parse a duration string.
|
|
//
|
|
// Three formats for durations are supported:
|
|
//
|
|
// 1. "Standard" format. This consists of one or more pairs of a count and a unit specifier. Examples are "23d1mo"
|
|
// and "5h23m10s". Components of the total duration must be written in decreasing order. That is, "5h2y" is
|
|
// an invalid duration string.
|
|
//
|
|
// The allowed units are:
|
|
// - "y": years
|
|
// - "mo": months
|
|
// - "w": weeks
|
|
// - "d": days
|
|
// - "h": hours
|
|
// - "m": minutes
|
|
// - "s": seconds
|
|
// - "ms": milliseconds
|
|
// - "us" or "µs": microseconds
|
|
// - "ns": nanoseconds
|
|
//
|
|
// Units are case-insensitive.
|
|
//
|
|
// 2. ISO-8601 format. "P[n]Y[n]M[n]DT[n]H[n]M[n]S" or "P[n]W". All specifiers are optional. Examples are
|
|
// "P23Y1M" or "P10W".
|
|
//
|
|
// 3. ISO-8601 alternate format. "P[YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]". All specifiers are mandatory. An example is
|
|
// "P2000-10-14T07:22:30".
|
|
//
|
|
// For all formats, a negative duration is indicated by beginning the string with the '-' symbol. For example,
|
|
// "-2y10ns".
|
|
//
|
|
// Throws `cql_duration_error` in the event of a parsing error.
|
|
//
|
|
explicit cql_duration(std::string_view s);
|
|
|
|
months_counter::value_type months{0};
|
|
days_counter::value_type days{0};
|
|
nanoseconds_counter::value_type nanoseconds{0};
|
|
|
|
//
|
|
// Note that equality comparison is based on exact counter matches. It is not valid to expect equivalency across
|
|
// counters like months and days. See the documentation for `duration` for more.
|
|
//
|
|
friend bool operator==(const cql_duration&, const cql_duration&) noexcept = default;
|
|
};
|
|
|
|
//
|
|
// Pretty-print a duration using the standard format.
|
|
//
|
|
// Durations are simplified during printing so that `duration(24, 0, 0)` is printed as "2y".
|
|
//
|
|
std::ostream& operator<<(std::ostream& os, const cql_duration& d);
|
|
|
|
// See above.
|
|
seastar::sstring to_string(const cql_duration&);
|