mirror of
https://github.com/intel/llvm.git
synced 2026-01-27 06:06:34 +08:00
[libc++][chrono] Fixes month inc and dec operations.
The operator++, operator++(int), operator--, and operator--(int) need to change the month to a valid value. The wording is specified in terms of operator+(const month& x, const months& y) noexcept; which has the correct behavior. The aforementioned operators instead used ++/-- on the internal value direction, resulting in incorrect behaviour. As a drive-by improve the unit tests: - use the typical constexpr test method - test whether the month is valid after the operations - format the tests Fixes: https://llvm.org/PR63912 Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D155504
This commit is contained in:
@@ -31,9 +31,9 @@ private:
|
||||
public:
|
||||
month() = default;
|
||||
_LIBCPP_HIDE_FROM_ABI explicit inline constexpr month(unsigned __val) noexcept : __m_(static_cast<unsigned char>(__val)) {}
|
||||
_LIBCPP_HIDE_FROM_ABI inline constexpr month& operator++() noexcept { ++__m_; return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI inline constexpr month& operator++() noexcept { *this += months{1}; return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI inline constexpr month operator++(int) noexcept { month __tmp = *this; ++(*this); return __tmp; }
|
||||
_LIBCPP_HIDE_FROM_ABI inline constexpr month& operator--() noexcept { --__m_; return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI inline constexpr month& operator--() noexcept { *this -= months{1}; return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI inline constexpr month operator--(int) noexcept { month __tmp = *this; --(*this); return __tmp; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr month& operator+=(const months& __m1) noexcept;
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr month& operator-=(const months& __m1) noexcept;
|
||||
|
||||
@@ -13,42 +13,52 @@
|
||||
// constexpr month& operator--() noexcept;
|
||||
// constexpr month operator--(int) noexcept;
|
||||
|
||||
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename M>
|
||||
constexpr bool testConstexpr()
|
||||
{
|
||||
M m1{10};
|
||||
if (static_cast<unsigned>(--m1) != 9) return false;
|
||||
if (static_cast<unsigned>(m1--) != 9) return false;
|
||||
if (static_cast<unsigned>(m1) != 8) return false;
|
||||
return true;
|
||||
constexpr bool test() {
|
||||
using month = std::chrono::month;
|
||||
for (unsigned i = 0; i <= 15; ++i) {
|
||||
month m1(i);
|
||||
month m2 = m1--;
|
||||
assert(m1.ok());
|
||||
assert(m1 != m2);
|
||||
|
||||
unsigned exp = i == 0 ? 11 : i == 1 ? 12 : i - 1;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m1) == exp);
|
||||
}
|
||||
for (unsigned i = 0; i <= 15; ++i) {
|
||||
month m1(i);
|
||||
month m2 = --m1;
|
||||
assert(m1.ok());
|
||||
assert(m2.ok());
|
||||
assert(m1 == m2);
|
||||
|
||||
unsigned exp = i == 0 ? 11 : i == 1 ? 12 : i - 1;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m1) == exp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using month = std::chrono::month;
|
||||
int main(int, char**) {
|
||||
using month = std::chrono::month;
|
||||
|
||||
ASSERT_NOEXCEPT(--(std::declval<month&>()) );
|
||||
ASSERT_NOEXCEPT( (std::declval<month&>())--);
|
||||
ASSERT_NOEXCEPT(--(std::declval<month&>()));
|
||||
ASSERT_NOEXCEPT((std::declval<month&>())--);
|
||||
|
||||
ASSERT_SAME_TYPE(month , decltype( std::declval<month&>()--));
|
||||
ASSERT_SAME_TYPE(month&, decltype(--std::declval<month&>() ));
|
||||
ASSERT_SAME_TYPE(month, decltype(std::declval<month&>()--));
|
||||
ASSERT_SAME_TYPE(month&, decltype(--std::declval<month&>()));
|
||||
|
||||
static_assert(testConstexpr<month>(), "");
|
||||
|
||||
for (unsigned i = 10; i <= 20; ++i)
|
||||
{
|
||||
month m(i);
|
||||
assert(static_cast<unsigned>(--m) == i - 1);
|
||||
assert(static_cast<unsigned>(m--) == i - 1);
|
||||
assert(static_cast<unsigned>(m) == i - 2);
|
||||
}
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,41 +13,52 @@
|
||||
// constexpr month& operator++() noexcept;
|
||||
// constexpr month operator++(int) noexcept;
|
||||
|
||||
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename M>
|
||||
constexpr bool testConstexpr()
|
||||
{
|
||||
M m1{1};
|
||||
if (static_cast<unsigned>(++m1) != 2) return false;
|
||||
if (static_cast<unsigned>(m1++) != 2) return false;
|
||||
if (static_cast<unsigned>(m1) != 3) return false;
|
||||
return true;
|
||||
constexpr bool test() {
|
||||
using month = std::chrono::month;
|
||||
for (unsigned i = 0; i <= 15; ++i) {
|
||||
month m1(i);
|
||||
month m2 = m1++;
|
||||
assert(m1.ok());
|
||||
assert(m1 != m2);
|
||||
|
||||
unsigned exp = i + 1;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m1) == exp);
|
||||
}
|
||||
for (unsigned i = 0; i <= 15; ++i) {
|
||||
month m1(i);
|
||||
month m2 = ++m1;
|
||||
assert(m1.ok());
|
||||
assert(m2.ok());
|
||||
assert(m1 == m2);
|
||||
|
||||
unsigned exp = i + 1;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m1) == exp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using month = std::chrono::month;
|
||||
ASSERT_NOEXCEPT(++(std::declval<month&>()) );
|
||||
ASSERT_NOEXCEPT( (std::declval<month&>())++);
|
||||
int main(int, char**) {
|
||||
using month = std::chrono::month;
|
||||
|
||||
ASSERT_SAME_TYPE(month , decltype( std::declval<month&>()++));
|
||||
ASSERT_SAME_TYPE(month&, decltype(++std::declval<month&>() ));
|
||||
ASSERT_NOEXCEPT(++(std::declval<month&>()));
|
||||
ASSERT_NOEXCEPT((std::declval<month&>())++);
|
||||
|
||||
static_assert(testConstexpr<month>(), "");
|
||||
ASSERT_SAME_TYPE(month, decltype(std::declval<month&>()++));
|
||||
ASSERT_SAME_TYPE(month&, decltype(++std::declval<month&>()));
|
||||
|
||||
for (unsigned i = 0; i <= 10; ++i)
|
||||
{
|
||||
month m(i);
|
||||
assert(static_cast<unsigned>(++m) == i + 1);
|
||||
assert(static_cast<unsigned>(m++) == i + 1);
|
||||
assert(static_cast<unsigned>(m) == i + 2);
|
||||
}
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,50 +19,43 @@
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename M, typename Ms>
|
||||
constexpr bool testConstexpr()
|
||||
{
|
||||
M m1{1};
|
||||
if (static_cast<unsigned>(m1 += Ms{ 1}) != 2) return false;
|
||||
if (static_cast<unsigned>(m1 += Ms{ 2}) != 4) return false;
|
||||
if (static_cast<unsigned>(m1 += Ms{ 8}) != 12) return false;
|
||||
if (static_cast<unsigned>(m1 -= Ms{ 1}) != 11) return false;
|
||||
if (static_cast<unsigned>(m1 -= Ms{ 2}) != 9) return false;
|
||||
if (static_cast<unsigned>(m1 -= Ms{ 8}) != 1) return false;
|
||||
return true;
|
||||
constexpr bool test() {
|
||||
using month = std::chrono::month;
|
||||
using months = std::chrono::months;
|
||||
|
||||
for (unsigned i = 1; i <= 10; ++i) {
|
||||
month m(i);
|
||||
int exp = i + 10;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m += months{10}) == static_cast<unsigned>(exp));
|
||||
assert(static_cast<unsigned>(m) == static_cast<unsigned>(exp));
|
||||
assert(m.ok());
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i <= 10; ++i) {
|
||||
month m(i);
|
||||
int exp = i - 9;
|
||||
while (exp < 1)
|
||||
exp += 12;
|
||||
assert(static_cast<unsigned>(m -= months{9}) == static_cast<unsigned>(exp));
|
||||
assert(static_cast<unsigned>(m) == static_cast<unsigned>(exp));
|
||||
assert(m.ok());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using month = std::chrono::month;
|
||||
using months = std::chrono::months;
|
||||
int main(int, char**) {
|
||||
using month = std::chrono::month;
|
||||
using months = std::chrono::months;
|
||||
|
||||
ASSERT_NOEXCEPT(std::declval<month&>() += std::declval<months&>());
|
||||
ASSERT_NOEXCEPT(std::declval<month&>() -= std::declval<months&>());
|
||||
ASSERT_SAME_TYPE(month&, decltype(std::declval<month&>() += std::declval<months&>()));
|
||||
ASSERT_SAME_TYPE(month&, decltype(std::declval<month&>() -= std::declval<months&>()));
|
||||
ASSERT_NOEXCEPT(std::declval<month&>() += std::declval<months&>());
|
||||
ASSERT_NOEXCEPT(std::declval<month&>() -= std::declval<months&>());
|
||||
ASSERT_SAME_TYPE(month&, decltype(std::declval<month&>() += std::declval<months&>()));
|
||||
ASSERT_SAME_TYPE(month&, decltype(std::declval<month&>() -= std::declval<months&>()));
|
||||
|
||||
static_assert(testConstexpr<month, months>(), "");
|
||||
|
||||
for (unsigned i = 1; i <= 10; ++i)
|
||||
{
|
||||
month m(i);
|
||||
int exp = i + 10;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m += months{10}) == static_cast<unsigned>(exp));
|
||||
assert(static_cast<unsigned>(m) == static_cast<unsigned>(exp));
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i <= 10; ++i)
|
||||
{
|
||||
month m(i);
|
||||
int exp = i - 9;
|
||||
while (exp < 1)
|
||||
exp += 12;
|
||||
assert(static_cast<unsigned>(m -= months{ 9}) == static_cast<unsigned>(exp));
|
||||
assert(static_cast<unsigned>(m) == static_cast<unsigned>(exp));
|
||||
}
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -58,12 +58,11 @@ int main(int, char**)
|
||||
for (unsigned i = 1; i <= 12; ++i)
|
||||
{
|
||||
month m1 = m - months{i};
|
||||
// months off = m - month {i};
|
||||
assert(m1.ok());
|
||||
int exp = 6 - i;
|
||||
if (exp < 1)
|
||||
exp += 12;
|
||||
assert(static_cast<unsigned>(m1) == static_cast<unsigned>(exp));
|
||||
// assert(off.count() == static_cast<unsigned>(exp));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -23,51 +23,45 @@
|
||||
// holding a value in the range [1, 12] even if !x.ok(). -end note]
|
||||
// [Example: February + months{11} == January. -end example]
|
||||
|
||||
|
||||
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename M, typename Ms>
|
||||
constexpr bool testConstexpr()
|
||||
{
|
||||
M m{1};
|
||||
Ms offset{4};
|
||||
assert(m + offset == M{5});
|
||||
assert(offset + m == M{5});
|
||||
// Check the example
|
||||
assert(M{2} + Ms{11} == M{1});
|
||||
return true;
|
||||
constexpr bool test() {
|
||||
using month = std::chrono::month;
|
||||
using months = std::chrono::months;
|
||||
|
||||
month my{2};
|
||||
for (unsigned i = 0; i <= 15; ++i) {
|
||||
month m1 = my + months{i};
|
||||
month m2 = months{i} + my;
|
||||
assert(m1.ok());
|
||||
assert(m2.ok());
|
||||
assert(m1 == m2);
|
||||
unsigned exp = i + 2;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m1) == exp);
|
||||
assert(static_cast<unsigned>(m2) == exp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using month = std::chrono::month;
|
||||
using months = std::chrono::months;
|
||||
int main(int, char**) {
|
||||
using month = std::chrono::month;
|
||||
using months = std::chrono::months;
|
||||
|
||||
ASSERT_NOEXCEPT(std::declval<month>() + std::declval<months>());
|
||||
ASSERT_NOEXCEPT(std::declval<months>() + std::declval<month>());
|
||||
ASSERT_NOEXCEPT(std::declval<month>() + std::declval<months>());
|
||||
ASSERT_NOEXCEPT(std::declval<months>() + std::declval<month>());
|
||||
|
||||
ASSERT_SAME_TYPE(month, decltype(std::declval<month>() + std::declval<months>()));
|
||||
ASSERT_SAME_TYPE(month, decltype(std::declval<months>() + std::declval<month>() ));
|
||||
ASSERT_SAME_TYPE(month, decltype(std::declval<month>() + std::declval<months>()));
|
||||
ASSERT_SAME_TYPE(month, decltype(std::declval<months>() + std::declval<month>()));
|
||||
|
||||
static_assert(testConstexpr<month, months>(), "");
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
month my{2};
|
||||
for (unsigned i = 0; i <= 15; ++i)
|
||||
{
|
||||
month m1 = my + months{i};
|
||||
month m2 = months{i} + my;
|
||||
assert(m1 == m2);
|
||||
unsigned exp = i + 2;
|
||||
while (exp > 12)
|
||||
exp -= 12;
|
||||
assert(static_cast<unsigned>(m1) == exp);
|
||||
assert(static_cast<unsigned>(m2) == exp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user