boostorg / unordered

Boost.org unordered module
http://boost.org/libs/unordered
Boost Software License 1.0
61 stars 55 forks source link

[FR] Mutable access to stateful hashers and comparators #233

Open psiha opened 8 months ago

psiha commented 8 months ago

(like the implementation table_core class template provides) I have an exotic use case where the state of the two subject objects references an external 'master' object which can potentially get moved around in memory/has an unstable reference (say as if stored in a std::vector) yet when I need to use the unordered container in question I know for certain that the 'master' object is 'pinned' - and would like to simply then update the reference stored in the hasher...

Yes - this opens up the can of worms of enabling the user the change the hasher in such a way that it potentially changes the hashes it returns - but this is already possible just not as easily (exactly by storing references in hashers) - so simply demand that hashes and comparators be [[ gnu::const ]] or else UB...?

cmazakas commented 8 months ago

If I understand you correctly, I think you mean something like this:

#include <boost/unordered/unordered_flat_map.hpp>
#include <memory>
#include <vector>
#include <iostream>

struct master_object {
    int x_=1337;
};

struct state {
    master_object*& pobj_;
};

template<class T>
struct unified {
    std::shared_ptr<state> p_;

    bool operator()(T const& lhs, T const& rhs) const {
        return lhs == rhs;
    }

    std::size_t operator()(T const&) const noexcept {
        std::cout <<
            p_->pobj_->x_ 
            << std::endl;
        return 0;
    }
};

int main() {
    using map_type =
        boost::unordered_flat_map<int, int, unified<int>, unified<int>>;

    std::vector<master_object> objects(256);
    auto pobj = objects.data() + 127;
    pobj->x_ = 7331;

    auto pstate = std::make_shared<state>(pobj);

    map_type map(0, {pstate}, {pstate});

    map.emplace(1,2);

    objects.resize(1024);
    pobj = objects.data() + 552;
    pobj->x_ = 1234;

    map.emplace(2,3);

    return map.empty() ? 255 : 0;
}

Otherwise, I might need to see some pseudocode to properly understand the request.

psiha commented 7 months ago

If I understand you correctly, I think you mean something like this:

Sort of but not quite:

I currently do something like: image and it works as expected.

cmazakas commented 7 months ago

Can you provide a https://godbolt.org/ link that demonstrates your issue/what you're trying to accomplish?

Here's a dummy template that already has Boost setup: https://godbolt.org/z/WG1hzhY8M