On Fri, 21 Nov 2025 at 10:23, Tomasz Kamiński <[email protected]> wrote: > > This patch implements P2592R3 Hashing support for std::chrono value classes. > > To avoid the know issues with current hashing of integer types (see PR104945), > we use chrono::__int_hash function that hash the bytes of representation, > instead of hash<T>, as the later simply cast to value. Currently _Hash_impl > it used, but we should consider replacing it (see PR55815) before C++26 ABI > is made stable. The function is declared inside <chrono> header and chrono > namespace, to make sure that only chrono components would be affected by > such change. Finally, chrono::__int_hash is made variadic, to support > combining hashes of multiple integers. > > To reduce the number of calls to hasher (defined out of line), the calendar > types are packed into single unsigned integer value. This is done by > chrono::__hash helper, that calls: > * chrono::__as_int to cast the value of single component, to unsigned integer > with size matching the one used by internal representation: unsigned short > for year/weekday_indexed, and unsigned char in all other cases, > * chrono::__pack_ints to pack integers (if more than one) into single integer > by performing bit shift operations, > * chrono::__int_hash to hash the value produced by above. > > Hashing of duration, time_point, and zoned_time only hashes the value and > ignores any difference in the period, i.e. hashes of nanoseconds(2) and > seconds(2) are the same. This does not affect the usages inside unordered > containers, as the arguments are converted to key type first. To address > that period::num and period::denum could be included in the hash, however > such approach will not make hashes of equal durations (2000ms, 2s), so > they would remain unusable for precomputed hashes. In consequence, > including period in hash, would only increase runtime cost, withou any > clear benefits. > > Futhermore, chrono::__int_hash is used when the duration representation > is integral type, and for other types (floating point due special handling > of +/-0.0 and user defined types) we delegate to hash specialization. > This is automatically picked up by time_point, that delegates to hasher > of duration. Similarly for leap_second that is specified to use integer > durations, we simply hash representations of date() and value(). Finally > zoned_time in addition to handling integer durations as described above, > we also use __int_hash for const time_zone* (if used), as hash<T*> have > similar problems as hash specialization for integers. This is limited > only to _TimeZonePtr being const time_zone* (default), as user can define > hash specializations for raw pointers to they zones. > > As accessing the representation for duration requires calling count() > method that returns a copy of representation by value, the noexcept > specification of the hasher needs to take into consideration copy > constructor of duration. Similar reasoning applies for time_since_epoch > for time_points, and get_sys_time, get_time_zone for zoned_time. > For all this cases we use internal __is_nothrow_copy_hashable concept. > > Finally support for zoned_time is provided only for CXX11 string ABI, > __cpp_lib_chrono feature test macro cannot be bumped if COW string are used. > To indicate presence of hasher for remaining types this patch also bumps > the internal __glibcxx_chrono_cxx20 macro, and uses it as guard to new > features. > > libstdc++-v3/ChangeLog: > > * include/bits/version.def (chrono, chrono_cxx20): Bump values. > * include/bits/version.h: Regenerate. > * include/std/chrono (__is_nothrow_copy_hashable) > (chrono::__pack_ints, chrono::__as_int, chrono::__int_hash) > (chrono::__hash): Define. > (std::hash): Define partial specialization for duration, time_point, > and zoned_time, and full specializations for calendar types and > leap_second. > (std::__is_fast_hash): Define partial specializations for duration, > time_point, zoned_time. > * testsuite/std/time/hash.cc: New test. > > Co-authored-by: Giuseppe D'Angelo <[email protected]> > Signed-off-by: Tomasz Kamiński <[email protected]> > Signed-off-by: Giuseppe D'Angelo <[email protected]> > --- > v5: > - add paragraph in commit description explaning, why period is not > included in hash > - remove code required for handling cv-qualified rep, we can add > them if necessary,
The C++26 draft is quite explicit: "The specialization hash<chrono::duration<Rep, Period>> is enabled (22.10.19) if and only if hash<Rep> is enabled." So hash<duration<R, P>> should not use hash<remove_cv_t<R>>, and therefore hash<duration<const int>> should be disabled.
