| // { dg-do run { target c++26 } } |
| |
| #include <chrono> |
| #include <unordered_set> |
| #include <limits.h> |
| #include <testsuite_hooks.h> |
| |
| #if _GLIBCXX_USE_CXX11_ABI |
| # if !defined(__cpp_lib_chrono) |
| # error "__cpp_lib_chrono not defined" |
| # elif __cpp_lib_chrono < 202306L |
| # error "Wrong value for __cpp_lib_chrono" |
| # endif |
| #endif |
| |
| template <typename T> |
| struct arithmetic_wrapper |
| { |
| arithmetic_wrapper() = default; |
| arithmetic_wrapper(T t) : t(t) {} |
| friend bool operator==(arithmetic_wrapper, arithmetic_wrapper) = default; |
| T t; |
| }; |
| |
| template <typename T> |
| struct std::hash<arithmetic_wrapper<T>> |
| { |
| size_t operator()(arithmetic_wrapper<T> val) const noexcept |
| { return std::hash<T>{}(val.t); } |
| }; |
| |
| template <typename T> |
| struct non_hashable_arithmetic_wrapper |
| { |
| non_hashable_arithmetic_wrapper() = default; |
| non_hashable_arithmetic_wrapper(T t) : t(t) {} |
| friend bool operator==(non_hashable_arithmetic_wrapper, non_hashable_arithmetic_wrapper) = default; |
| T t; |
| }; |
| |
| template <typename T> |
| constexpr bool is_hash_poisoned = !std::is_default_constructible_v<std::hash<T>>; |
| |
| template <typename T> |
| void test_unordered_set(const T& t) |
| { |
| std::unordered_set<T> set; |
| |
| set.insert(t); |
| VERIFY(set.size() == 1); |
| VERIFY(set.contains(t)); |
| |
| set.erase(t); |
| VERIFY(set.size() == 0); |
| VERIFY(!set.contains(t)); |
| } |
| |
| template <typename T> |
| void test_hash(const T& t) |
| { |
| static_assert(noexcept(std::hash<T>{}(t))); |
| static_assert(std::__is_fast_hash<T>::value); |
| test_unordered_set(t); |
| } |
| |
| void test01() |
| { |
| using namespace std::chrono; |
| using namespace std::literals::chrono_literals; |
| |
| // duration |
| test_hash(-999s); |
| test_hash(1234ms); |
| #if defined __SIZEOF_INT128__ |
| test_hash(duration<__int128>(123456)); |
| #endif |
| test_hash(duration<double>(123.45)); |
| using AWint = arithmetic_wrapper<int>; |
| test_hash(duration<AWint>(AWint(1234))); |
| using AWdouble = arithmetic_wrapper<double>; |
| test_hash(duration<AWdouble>(AWdouble(123.45))); |
| |
| // time_point |
| test_hash(sys_seconds(1234s)); |
| #if defined __SIZEOF_INT128__ |
| test_hash(sys_time<duration<__int128>>(duration<__int128>(123456))); |
| #endif |
| test_hash(sys_time<duration<double>>(duration<double>(123.45))); |
| test_hash(utc_seconds(1234s)); |
| test_hash(local_days(days(1234))); |
| test_hash(system_clock::now()); |
| test_hash(steady_clock::now()); |
| test_hash(utc_clock::now()); |
| test_hash(gps_clock::now()); |
| |
| // day |
| test_hash(1d); |
| test_hash(0d); |
| test_hash(255d); |
| test_hash(1234d); |
| test_hash(day(UINT_MAX)); |
| |
| // month |
| test_hash(January); |
| test_hash(September); |
| test_hash(month(0u)); |
| test_hash(month(255u)); |
| test_hash(month(1234u)); |
| test_hash(month(UINT_MAX)); |
| |
| // year |
| test_hash(2024y); |
| test_hash(0y); |
| test_hash(year::min()); |
| test_hash(year::max()); |
| test_hash(year(INT_MAX)); |
| test_hash(year(INT_MIN)); |
| |
| // weekday |
| test_hash(Monday); |
| test_hash(Thursday); |
| test_hash(weekday(255u)); |
| test_hash(weekday(UINT_MAX)); |
| |
| // weekday_indexed |
| test_hash(Monday[0u]); |
| test_hash(Monday[7u]); |
| test_hash(Monday[1234u]); |
| test_hash(weekday(1234u)[0u]); |
| |
| // weekday_last |
| test_hash(Monday[last]); |
| test_hash(Friday[last]); |
| test_hash(weekday(1234u)[last]); |
| |
| // month_day |
| test_hash(March / 3); |
| test_hash(March / 31); |
| test_hash(February / 31); |
| test_hash(February / 1234); |
| test_hash(month(1234u) / 1); |
| |
| // month_day_last |
| test_hash(March / last); |
| test_hash(month(1234u) / last); |
| |
| // month_weekday |
| test_hash(March / Tuesday[2u]); |
| test_hash(month(1234u) / Tuesday[2u]); |
| test_hash(March / weekday(1234u)[2u]); |
| test_hash(March / Tuesday[1234u]); |
| |
| // month_weekday_last |
| test_hash(April / Sunday[last]); |
| test_hash(month(1234u) / Tuesday[last]); |
| test_hash(April / weekday(1234u)[last]); |
| |
| // year_month |
| test_hash(2024y / August); |
| test_hash(1'000'000y / August); |
| test_hash(2024y / month(1234u)); |
| |
| // year_month_day |
| test_hash(2024y / August / 31); |
| test_hash(-10y / March / 5); |
| test_hash(2024y / February / 31); |
| test_hash(1'000'000y / March / 5); |
| test_hash(2024y / month(1234u) / 5); |
| test_hash(2024y / March / 1234); |
| |
| // year_month_day_last |
| test_hash(2024y / August / last); |
| test_hash(1'000'000y / August / last); |
| test_hash(2024y / month(1234u) / last); |
| |
| // year_month_weekday |
| test_hash(2024y / August / Tuesday[2u]); |
| test_hash(-10y / August / Tuesday[2u]); |
| test_hash(1'000'000y / August / Tuesday[2u]); |
| test_hash(2024y / month(1234u) / Tuesday[2u]); |
| test_hash(2024y / August / weekday(1234u)[2u]); |
| test_hash(2024y / August / Tuesday[1234u]); |
| |
| // year_month_weekday_last |
| test_hash(2024y / August / Tuesday[last]); |
| test_hash(-10y / August / Tuesday[last]); |
| test_hash(1'000'000y / August / Tuesday[last]); |
| test_hash(2024y / month(1234u) / Tuesday[last]); |
| test_hash(2024y / August / weekday(1234u)[last]); |
| |
| #if _GLIBCXX_USE_CXX11_ABI |
| // zoned_time |
| test_hash(zoned_seconds("Europe/Rome", sys_seconds(1234s))); |
| test_hash(zoned_time("Europe/Rome", system_clock::now())); |
| |
| // leap_second |
| for (leap_second l : get_tzdb().leap_seconds) |
| test_hash(l); |
| #endif |
| } |
| |
| void test02() |
| { |
| using namespace std::chrono; |
| using namespace std::literals::chrono_literals; |
| |
| { |
| std::unordered_set<milliseconds> set; |
| set.insert(2000ms); |
| VERIFY(set.contains(2000ms)); |
| VERIFY(set.contains(2s)); |
| VERIFY(!set.contains(1234ms)); |
| VERIFY(!set.contains(1234s)); |
| } |
| { |
| using TP = sys_time<milliseconds>; |
| std::unordered_set<TP> set; |
| set.insert(TP(2000ms)); |
| VERIFY(set.contains(TP(2000ms))); |
| VERIFY(set.contains(sys_seconds(2s))); |
| VERIFY(!set.contains(TP(1234ms))); |
| VERIFY(!set.contains(sys_seconds(1234s))); |
| } |
| } |
| |
| void test03() |
| { |
| using namespace std::chrono; |
| |
| static constexpr |
| auto test_hash = []<typename T>(const T& t) |
| { |
| static_assert(noexcept(std::hash<T>{}(t))); |
| }; |
| |
| static constexpr |
| auto test = []<typename D>(const D& d) |
| { |
| test_hash(d); |
| test_hash(sys_time<D>(d)); |
| #if _GLIBCXX_USE_CXX11_ABI |
| test_hash(zoned_time<D>(sys_time<D>(d))); |
| #endif |
| }; |
| |
| test(duration<int>(123)); |
| test(duration<int, std::ratio<1, 1000>>(123)); |
| test(duration<int, std::ratio<1000, 1>>(123)); |
| test(duration<double>(123.456)); |
| test(duration<arithmetic_wrapper<int>>(arithmetic_wrapper<int>(123))); |
| } |
| |
| void test04() |
| { |
| using namespace std::chrono; |
| |
| static_assert(!is_hash_poisoned<duration<int>>); |
| static_assert(!is_hash_poisoned<duration<double>>); |
| static_assert(!is_hash_poisoned<duration<arithmetic_wrapper<int>>>); |
| static_assert(!is_hash_poisoned<duration<arithmetic_wrapper<double>>>); |
| static_assert(is_hash_poisoned<duration<non_hashable_arithmetic_wrapper<int>>>); |
| static_assert(is_hash_poisoned<duration<non_hashable_arithmetic_wrapper<double>>>); |
| |
| #if _GLIBCXX_USE_CXX11_ABI |
| static_assert(!is_hash_poisoned<zoned_time<duration<int>>>); |
| static_assert(!is_hash_poisoned<zoned_time<duration<double>>>); |
| static_assert(!is_hash_poisoned<zoned_time<duration<arithmetic_wrapper<int>>>>); |
| static_assert(!is_hash_poisoned<zoned_time<duration<arithmetic_wrapper<double>>>>); |
| static_assert(is_hash_poisoned<zoned_time<duration<non_hashable_arithmetic_wrapper<int>>>>); |
| static_assert(is_hash_poisoned<zoned_time<duration<non_hashable_arithmetic_wrapper<double>>>>); |
| #endif |
| } |
| |
| int main() |
| { |
| test01(); |
| test02(); |
| test03(); |
| test04(); |
| } |