Date: Fri, 17 Apr 2026 18:22:12 +0200
Resending, as the previous mail did not include the mailing list.
All questions and suggestions are addressed below.
> Not really. If you have a fixed non-cryptographic hash function,
> I think it's practical to construct a set of keys that will cause
> so many collisions that nobody would call that O(1). A decade ago
> or so, people noticed that hashes are vulnerable to such targeted
> attacks, causing a denial-of-service vector for Internet-facing
> services that put user-supplied data into hash tables.
You are referring to pathological datasets. They do exist indeed, and they
should be strongly considered
in the design of unordered associative containers. For the intended use
case this remains a run-time
concern. Since the keys are compile time constants, an adversary cannot
craft an attack vector at
run-time.
Run-time of the containers can be probed during compilation, but can also
be part of the interface, see
my following answers.
> So, why don't we just standardize "frozen" or something similar?
Indeed frozen provides a great interface, very in line with the stdlib.
What frozen does not provide yet is a guaranteed interface and portability
without a external libraries.
It can however serve as a good guideline.
> Having a "constexpr" replacement for GNU gperf (perfect hash
> function calculation) seems to be exactly what constant evaluation
> was made for.
Indeed this could be one direction. A compile time hashing facility
provides the lowest level of abstraction
for the problem I am trying to solve. We can look at the problem space
roughly at 3 three layers:
1. Hash construction
2. Storage and solution layout (data structure, linear probing, ...)
3. User facing container
A compile time hashing facility removes all abstraction and gives maximum
control for the user at layer 1.
The proposed std::static_unordered_set sits at layer 3., the highest level
of abstraction. The question is
which interface is the more suitable.
What speaks for the compile time facility are clearly the degree of control
it gives the user.
The container on the other hand would be the more ergonomic solution for
most users. It would provide
a familiar interface through the stdlib and abstract away the complexity of
hash-functions, similar to
what the containers std::set and std::unordered_set do to the complexity
they have under the hood.
However, the two solutions can also integrate. The container should not
depend on the compile
time facility below. The hash is a template parameter, hence the user can
use a customized compile
time hash facility if wanted. But the solution can still draw from the
strengths of a provided compile time
hash solution by providing a default implementation.
The point of such a solution has been raised in P3372R2 already, I cite in
the following:
> Unordered containers needs a hashing facility. But default provided
> std::hash can’t be made constexpr
> friendly as Cpp17Hash requirements <http://eel.is/c++draft/tab:cpp17.hash>
> states its result is guaranteed to be consistent only within duration
> of the program. Intention is to allow salting the hash to avoid cache
> poisoning attacks. The requirement
> is in a direct conflict with calculating the hash within constant
> evaluation. One possible solution would be
> creating a std::stable_hash facility without such requirement. But this
> is a can of worms outside of
> scope of this paper and I’m not brave enough to open it.
>
Using the container would provide the ergonomics for the typical use case
of most users, who want a fast
lookup, without directly exposing the complexity underneath. A design like
std::static_unordered_set<Key, N, Hash>
allows to choose strategies between compile time efficiency, size of
underlying container, and run-time cost, without
directly exposing the implementation choices directly. The compile time
hashing facility (something like gperf) provides
the user the tools for a more custom strategy if desired.
Am Di., 14. Apr. 2026 um 21:35 Uhr schrieb Jens Maurer <jens.maurer_at_[hidden]
>:
>
>
> On 4/14/26 18:53, Robert Baumgartner wrote:
> >> What doesn't work, for your use-case, using each of these approaches?
> >
> > frozen -> no guaranteed interface, no standard availability, adds an
> external dependency. The standard library should
> > provide guaranteed portable solutions without external dependencies.
>
> So, why don't we just standardize "frozen" or something similar?
>
> Having a "constexpr" replacement for GNU gperf (perfect hash
> function calculation) seems to be exactly what constant evaluation
> was made for.
>
> > The primary design
> > would use open addressing with collision handling, just like a runtime
> std::unordered_set.
> > O(1) at runtime is guaranteed through immutability of the array, hence
> fixed load factor.
>
> Not really. If you have a fixed non-cryptographic hash function,
> I think it's practical to construct a set of keys that will cause
> so many collisions that nobody would call that O(1). A decade ago
> or so, people noticed that hashes are vulnerable to such targeted
> attacks, causing a denial-of-service vector for Internet-facing
> services that put user-supplied data into hash tables.
>
> Jens
>
>
All questions and suggestions are addressed below.
> Not really. If you have a fixed non-cryptographic hash function,
> I think it's practical to construct a set of keys that will cause
> so many collisions that nobody would call that O(1). A decade ago
> or so, people noticed that hashes are vulnerable to such targeted
> attacks, causing a denial-of-service vector for Internet-facing
> services that put user-supplied data into hash tables.
You are referring to pathological datasets. They do exist indeed, and they
should be strongly considered
in the design of unordered associative containers. For the intended use
case this remains a run-time
concern. Since the keys are compile time constants, an adversary cannot
craft an attack vector at
run-time.
Run-time of the containers can be probed during compilation, but can also
be part of the interface, see
my following answers.
> So, why don't we just standardize "frozen" or something similar?
Indeed frozen provides a great interface, very in line with the stdlib.
What frozen does not provide yet is a guaranteed interface and portability
without a external libraries.
It can however serve as a good guideline.
> Having a "constexpr" replacement for GNU gperf (perfect hash
> function calculation) seems to be exactly what constant evaluation
> was made for.
Indeed this could be one direction. A compile time hashing facility
provides the lowest level of abstraction
for the problem I am trying to solve. We can look at the problem space
roughly at 3 three layers:
1. Hash construction
2. Storage and solution layout (data structure, linear probing, ...)
3. User facing container
A compile time hashing facility removes all abstraction and gives maximum
control for the user at layer 1.
The proposed std::static_unordered_set sits at layer 3., the highest level
of abstraction. The question is
which interface is the more suitable.
What speaks for the compile time facility are clearly the degree of control
it gives the user.
The container on the other hand would be the more ergonomic solution for
most users. It would provide
a familiar interface through the stdlib and abstract away the complexity of
hash-functions, similar to
what the containers std::set and std::unordered_set do to the complexity
they have under the hood.
However, the two solutions can also integrate. The container should not
depend on the compile
time facility below. The hash is a template parameter, hence the user can
use a customized compile
time hash facility if wanted. But the solution can still draw from the
strengths of a provided compile time
hash solution by providing a default implementation.
The point of such a solution has been raised in P3372R2 already, I cite in
the following:
> Unordered containers needs a hashing facility. But default provided
> std::hash can’t be made constexpr
> friendly as Cpp17Hash requirements <http://eel.is/c++draft/tab:cpp17.hash>
> states its result is guaranteed to be consistent only within duration
> of the program. Intention is to allow salting the hash to avoid cache
> poisoning attacks. The requirement
> is in a direct conflict with calculating the hash within constant
> evaluation. One possible solution would be
> creating a std::stable_hash facility without such requirement. But this
> is a can of worms outside of
> scope of this paper and I’m not brave enough to open it.
>
Using the container would provide the ergonomics for the typical use case
of most users, who want a fast
lookup, without directly exposing the complexity underneath. A design like
std::static_unordered_set<Key, N, Hash>
allows to choose strategies between compile time efficiency, size of
underlying container, and run-time cost, without
directly exposing the implementation choices directly. The compile time
hashing facility (something like gperf) provides
the user the tools for a more custom strategy if desired.
Am Di., 14. Apr. 2026 um 21:35 Uhr schrieb Jens Maurer <jens.maurer_at_[hidden]
>:
>
>
> On 4/14/26 18:53, Robert Baumgartner wrote:
> >> What doesn't work, for your use-case, using each of these approaches?
> >
> > frozen -> no guaranteed interface, no standard availability, adds an
> external dependency. The standard library should
> > provide guaranteed portable solutions without external dependencies.
>
> So, why don't we just standardize "frozen" or something similar?
>
> Having a "constexpr" replacement for GNU gperf (perfect hash
> function calculation) seems to be exactly what constant evaluation
> was made for.
>
> > The primary design
> > would use open addressing with collision handling, just like a runtime
> std::unordered_set.
> > O(1) at runtime is guaranteed through immutability of the array, hence
> fixed load factor.
>
> Not really. If you have a fixed non-cryptographic hash function,
> I think it's practical to construct a set of keys that will cause
> so many collisions that nobody would call that O(1). A decade ago
> or so, people noticed that hashes are vulnerable to such targeted
> attacks, causing a denial-of-service vector for Internet-facing
> services that put user-supplied data into hash tables.
>
> Jens
>
>
Received on 2026-04-17 16:22:27
