Fixed addition of multi-year duration to year_month.

* Added new overloads for operator+/- between year_month and duration
  that is convertible to years, so it is better candidate for operands
  that are convertible to both years and months. To preserve
  functionality, this operator is conditionally noexcept.

* Reworked year_month_day, year_month_day_last, year_month_weekday,
  and year_month_weekday_last.

* Added tests for this new functionality.
This commit is contained in:
Tomasz Kamiński 2018-05-06 19:13:36 +02:00 committed by Howard Hinnant
parent 5d15157bbb
commit 328cecaa56
4 changed files with 691 additions and 444 deletions

File diff suppressed because it is too large Load Diff

View File

@ -30,16 +30,16 @@ int conversions = 0;
//to/from impl //to/from impl
struct mil_clock struct mil_clock
{ {
using duration = std::common_type_t<std::chrono::system_clock::duration, date::days>; using duration = typename std::common_type<std::chrono::system_clock::duration, date::days>::type;
using rep = duration::rep; using rep = duration::rep;
using period = duration::period; using period = duration::period;
using time_point = std::chrono::time_point<mil_clock, duration>; using time_point = std::chrono::time_point<mil_clock, duration>;
static constexpr date::sys_days epoch = date::year{2000}/date::month{0}/date::day{1}; static constexpr date::sys_days epoch{date::days{1000}};
template<typename Duration> template<typename Duration>
static static
std::chrono::time_point<std::chrono::system_clock, std::common_type_t<Duration, date::days>> std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, date::days>::type>
to_sys(std::chrono::time_point<mil_clock, Duration> const& tp) to_sys(std::chrono::time_point<mil_clock, Duration> const& tp)
{ {
++conversions; ++conversions;
@ -48,11 +48,11 @@ struct mil_clock
template<typename Duration> template<typename Duration>
static static
std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>> std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
from_sys(std::chrono::time_point<std::chrono::system_clock, Duration> const& tp) from_sys(std::chrono::time_point<std::chrono::system_clock, Duration> const& tp)
{ {
++conversions; ++conversions;
using res = std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>>; using res = std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>;
return res(tp - epoch); return res(tp - epoch);
} }
@ -103,11 +103,11 @@ namespace date
struct clock_time_conversion<mil_clock, s2s_clock> struct clock_time_conversion<mil_clock, s2s_clock>
{ {
template<typename Duration> template<typename Duration>
std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>> std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
operator()(std::chrono::time_point<s2s_clock, Duration> const& tp) operator()(std::chrono::time_point<s2s_clock, Duration> const& tp)
{ {
++conversions; ++conversions;
using res = std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>>; using res = std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>;
return res(tp.time_since_epoch() - mil_clock::epoch.time_since_epoch()); return res(tp.time_since_epoch() - mil_clock::epoch.time_since_epoch());
} }
}; };

View File

@ -34,7 +34,7 @@ struct bad_clock
date::utc_time<Duration> date::utc_time<Duration>
to_sys(std::chrono::time_point<bad_clock, Duration> const& tp) to_sys(std::chrono::time_point<bad_clock, Duration> const& tp)
{ {
return utc_time<Duration>(tp.time_since_epoch()); return date::utc_time<Duration>(tp.time_since_epoch());
} }
}; };

View File

@ -0,0 +1,297 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Tomasz Kamiński
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "date.h"
#include <chrono>
#include <cassert>
#include <type_traits>
#define CPP11_ASSERT(...) static_assert(__VA_ARGS__, "")
#if __cplusplus >= 201402
// C++14
# define CPP14_ASSERT(...) static_assert(__VA_ARGS__, "")
#else
// C++11
# define CPP14_ASSERT(...) assert(__VA_ARGS__)
#endif
#define NOEXCEPT_ASSERT(...) static_assert(noexcept(__VA_ARGS__), "")
//Invocation involves a conversion between duration that is currently
//not marked as noexcept.
#define NOEXCEPT_CONVERSION(...)
template<typename T>
constexpr T copy(T const& t) noexcept { return t; }
int
main()
{
using namespace date;
using namespace std::chrono;
using decades = duration<int, std::ratio_multiply<std::ratio<10>, years::period>>;
using decamonths = duration<int, std::ratio_multiply<std::ratio<10>, months::period>>;
constexpr months one_month{1};
constexpr years one_year{1};
constexpr decades one_decade{1};
constexpr decamonths one_decamonth{1};
{
constexpr year_month ym = 2001_y/feb;
CPP14_ASSERT(ym + one_month == 2001_y/mar);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
}
{
constexpr year_month_day ym = 2001_y/feb/10;
CPP14_ASSERT(ym + one_month == 2001_y/mar/10);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/10);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/10);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/10);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/10);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/10);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/10);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/10);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/10);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/10);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/10);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/10);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/10);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/10);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/10);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/10);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/10);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/10);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
}
{
constexpr year_month_day_last ym = 2001_y/feb/last;
CPP14_ASSERT(ym + one_month == 2001_y/mar/last);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/last);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/last);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/last);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/last);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/last);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/last);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/last);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/last);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/last);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/last);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/last);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/last);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/last);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/last);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/last);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/last);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/last);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
}
{
constexpr year_month_weekday ym = 2001_y/feb/fri[4];
CPP14_ASSERT(ym + one_month == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/fri[4]);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/fri[4]);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/fri[4]);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/fri[4]);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/fri[4]);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/fri[4]);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/fri[4]);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
}
{
constexpr year_month_weekday_last ym = 2001_y/feb/fri[last];
CPP14_ASSERT(ym + one_month == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/fri[last]);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/fri[last]);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/fri[last]);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/fri[last]);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/fri[last]);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/fri[last]);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/fri[last]);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
}
}