From 999d6c0317fec4c8ab9c415a072ea1e38c4b33d0 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 19 Nov 2024 03:11:30 +0200 Subject: [PATCH] Update hash_append.adoc --- doc/hash2/reference/hash_append.adoc | 60 +++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/doc/hash2/reference/hash_append.adoc b/doc/hash2/reference/hash_append.adoc index f0b76c2..93b2133 100644 --- a/doc/hash2/reference/hash_append.adoc +++ b/doc/hash2/reference/hash_append.adoc @@ -44,6 +44,30 @@ constexpr void hash_append( Hash& h, Flavor const& f, T const& v ); Appends the representation of `v` to the message stored in `h`. +Effects: :: +* If `is_contiguously_hashable::value` is `true`, calls `h.update(&v, sizeof(v))`; +* If `std::is_integral::value` is `true`, obtains a byte representation of `v` in the byte order requested by `Flavor::byte_order`, then calls `h.update(p, n)` where `p` is the address of that representation and `n` is `sizeof(v)`; +* If `std::is_pointer::value` is `true`, calls `hash_append(h, f, reinterpret_cast(v))`; +* If `std::is_floating_point::value` is true, first replaces `v` with positive zero if it's negative zero, then calls `hash_append(h, f, std::bit_cast(v))`, where `U` is an unsigned integer type with the same size as `T`; +* If `T` is `std::nullptr_t`, calls `hash_append(h, f, static_cast(v))`; +* If `T` is an array type `U[N]`, calls `hash_append_range(h, f, v + 0, v + N)`; +* If `tag_invoke(hash_append_tag(), h, f, v)` is a valid expression, calls `tag_invoke(hash_append_tag(), h, f, v)`; +* If `std::is_enum::value` is `true`, calls `hash_append(h, f, w)`, where `w` is `v` converted to the underlying type of `T`; +* If `boost::container_hash::is_unordered_range::value` is `true`, calls `hash_append_unordered_range(h, f, v.begin(), v.end())`; +* If `boost::container_hash::is_contiguous_range::value` is `true` and + - `has_constant_size::value` is `true`, calls `hash_append_range(h, f, v.data(), v.data() + v.size())`; + - `has_constant_size::value` is `false`, calls `hash_append_sized_range(h, f, v.data(), v.data() + v.size())`; +* If `boost::container_hash::is_range::value` is `true` and + - `has_constant_size::value` is `true`, calls `hash_append_range(h, f, v.begin(), v.end())`; + - `has_constant_size::value` is `false`, calls `hash_append_sized_range(h, f, v.begin(), v.end())`; +* If `boost::container_hash::is_tuple_like::value` is `true`, calls `hash_append(h, f, w)` for each tuple element `w`; +* If `boost::container_hash::is_described_class::value` is `true`, calls `hash_append(h, f, b)` for each base class subobject `b` of `v`, then `hash_append(h, f, m)` for each member subobject `m` of `v`; +* Otherwise, the result is a compile-time error. + +Remarks: :: + In case the above description would result in no calls being made (e.g. for a range of constant size zero, or a described `struct` with no bases and members), + a call to `hash_append(h, f, '\x00')` is made to satisfy the requirement that `hash_append` always results in at least one call to `Hash::update`. + ## hash_append_range ``` @@ -57,14 +81,11 @@ Requires: :: `It` must be an _iterator_ type. `[first, last)` must be a valid _iterator range_. Effects: :: - * If `It` is `T*` and `is_contiguously_hashable::value` is `true`, calls `h.update( first, (last - first) * sizeof(T) );`. - * Otherwise, for each iterator `i` in `[first, last)`, calls `hash_append(h, f, v);`, where `v` is `*i`, implicitly converted to `std::iterator_traits::value_type const&`. + * If `It` is `T*` and `is_contiguously_hashable::value` is `true`, calls `h.update(first, (last - first) * sizeof(T));`. + * Otherwise, for each element `v` in the range denoted by `[first, last)`, calls `hash_append(h, f, v);`. Remarks: :: -+ -If `hash_append_range` is called in a constant expression, the contiguously hashable optimization is only applied for `unsigned char*` and `unsigned char const*`. -+ -`*i` is converted to a reference to the iterator `value_type` to handle the case when its `reference` is a proxy type, for example, when the iterator is `std::vector::iterator`. + If `hash_append_range` is called in a constant expression, the contiguously hashable optimization is only applied for `unsigned char*` and `unsigned char const*`. ## hash_append_size @@ -75,6 +96,12 @@ constexpr void hash_append_size( Hash& h, Flavor const& f, T const& v ); Appends the representation of `v`, converted to `Flavor::size_type`, to the message stored in `h`. +Requires: :: + `T` must be an integral type. + +Effects: :: + Equivalent to `hash_append(h, f, static_cast(v));` + ## hash_append_sized_range ``` @@ -84,6 +111,12 @@ constexpr void hash_append_sized_range( Hash& h, Flavor const& f, It first, It l Appends the representations of the elements of the range `[first, last)`, followed by the size of the range, to the message stored in `h`. +Requires: :: + `It` must be an _iterator_ type. `[first, last)` must be a valid _iterator range_. + +Effects: :: + Equivalent to `hash_append_range(h, f, first, last); hash_append(h, f, m);`, where `m` is `std::distance(first, last)`. + ## hash_append_unordered_range ``` @@ -93,6 +126,21 @@ constexpr void hash_append_unordered_range( Hash& h, Flavor const& f, It first, Constructs a value from the representations of the elements of the range `[first, last)`, in a way such that their order doesn't affect the result, then appends that value, followed by the size of the range, to the message stored in `h`. +Requires: :: + `It` must be an _iterator_ type. `[first, last)` must be a valid _iterator range_. + +Effects: :: ++ +For each element `v` in the range denoted by `[first, last)`, obtains a hash value `r` by doing ++ +``` +Hash h2(h); +hash_append(h2, f, v); +auto r = h2.result(); +``` ++ +and then combines the so obtained `r` values in a way that is not sensitive to their order, producing a combined value `q`. Calls `hash_append(h, f, q)`, followed by `hash_append(h, f, m)`, where `m` is `std::distance(first, last)`. + ## hash_append_tag ```