You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For my specific use case I require being able to change the key for a given element without changing it's index in the underlying array. As far as I can tell this isn't possible with the current API.
So I wrote a change_key function which takes the iterator of the element you want to change and a new key for it. If the new key already exists it doesn't make any change and returns the existing new key iterator, otherwise it returns the now updated iterator with it's new key.
I amalgamated the function from sections of emplace and erase, I wrote a few tests for it and it seems to work correctly. No idea if it's ideal optimisation wise but this is what it looks like
template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
auto change_key(iterator it, Key const& new_key) -> std::pair<iterator, bool>
{
auto const value_idx_to_change = static_cast<value_idx_type>(it - cbegin());
auto new_hash = mixed_hash(new_key);
auto new_bucket_idx = bucket_idx_from_hash( new_hash );
auto dist_and_fingerprint = dist_and_fingerprint_from_hash( new_hash );
while (true) {
auto* bucket = &at(m_buckets, new_bucket_idx);
if (dist_and_fingerprint == bucket->m_dist_and_fingerprint) {
if (m_equal(new_key, get_key(m_values[bucket->m_value_idx]))) {
return {begin() + static_cast<difference_type>(bucket->m_value_idx), false};
}
} else if (dist_and_fingerprint > bucket->m_dist_and_fingerprint) {
// remove old key from buckets
auto old_hash = mixed_hash(get_key(*it));
auto old_bucket_idx = bucket_idx_from_hash(old_hash);
while(at(m_buckets, old_bucket_idx).m_value_idx != value_idx_to_change)
{
old_bucket_idx = next(old_bucket_idx);
}
// shift down until either empty or an element with correct spot is found
auto next_bucket_idx = next(old_bucket_idx);
while(at(m_buckets, next_bucket_idx).m_dist_and_fingerprint >= Bucket::dist_inc * 2)
{
at(m_buckets, old_bucket_idx) = {dist_dec(at(m_buckets, next_bucket_idx).m_dist_and_fingerprint),
at(m_buckets, next_bucket_idx).m_value_idx};
old_bucket_idx = std::exchange(next_bucket_idx, next(next_bucket_idx));
}
at(m_buckets, old_bucket_idx) = {};
// place new key, with existing value idx
place_and_shift_up({dist_and_fingerprint, value_idx_to_change}, new_bucket_idx);
it->first = new_key;
return {it, true};
}
dist_and_fingerprint = dist_inc(dist_and_fingerprint);
new_bucket_idx = next(new_bucket_idx);
}
}
Basically I wanted to know if the function implementation looks sensible to you. You are free to add it to the project if if you think it would be useful. Thanks
The text was updated successfully, but these errors were encountered:
For my specific use case I require being able to change the key for a given element without changing it's index in the underlying array. As far as I can tell this isn't possible with the current API.
So I wrote a change_key function which takes the iterator of the element you want to change and a new key for it. If the new key already exists it doesn't make any change and returns the existing new key iterator, otherwise it returns the now updated iterator with it's new key.
I amalgamated the function from sections of emplace and erase, I wrote a few tests for it and it seems to work correctly. No idea if it's ideal optimisation wise but this is what it looks like
Basically I wanted to know if the function implementation looks sensible to you. You are free to add it to the project if if you think it would be useful. Thanks
The text was updated successfully, but these errors were encountered: