I'd like to use a std::pmr::unordered_map
with a std::pmr::monotonic_buffer_resource
. The two fit well together, because the set's nodes are stable, so I don't create a lot of holes in the buffer resource by reallocation:
std::pmr::monotonic_buffer_resource res;
std::pmr::unordered_set<T> set(&res);
That is, except for the bucket list, which needs to be reallocated when the set rehashes as it exceeds the max_load_factor()
. Assuming I can't reserve()
my way out of this, and I actually care about the holes in the buffer resource left by old bucket lists since grown, what are my options?
If I know that unordered_set
is implemented as std::vector<std::forward_list>
, as in (some versions of) MSVC, then I should be able to use a scoped_allocator
to give different allocators for the vector
and the forward_list
. But a) I can't rely on unordered_set
being a vector<forward_list>
in portable code and b) scoped_allocator
is an Allocator
whereas monotonic_buffer_resource
is a memory_resource
, an impedance mismatch that will make for very complicated initialization.
Or I could write a switch_memory_resource
that delegates to other memory_resource
s based on the size of the request. I could then use a monotonic_buffer_resource
for requests that match the size of the nodes (which, however, I cannot, portably, know, either) and default_memory_resource()
for everything else. I could probably make an educated guess that the nodes are at most sizeof(struct {void* next; size_t hash; T value;})
, add some error margin by multiplying that by two and use that as the cut-off between the two memory_resource
s, but I wonder whether there's a cleaner way?
pmr::unordered_set<pmr::string>
. Which just goes to prove that any switching on the request size is going to cause failures. I think what I was hoping for was some form of scoped-allocator support, so you'd know that at the top level, requests would only be for the bucket list, on the next for the nodes and on the third and following for thevalue_type
s. Something likemonotonic_buffer_resource mbr; scoped_memory_resource{default_memory_resource(), &mbr, &mbr};
where the last&mbr
is superfluous, like inscoped_allocator_adapter
. – Tresa