GithubHelp home page GithubHelp logo

Comments (6)

Tessil avatar Tessil commented on May 12, 2024

Hello,

Thank you very much for the report. I effectively completely missed that when implementing the backward shift deletion.

I started the implementation of a fix in the fix_issue_20 branch. I still have to check a bit if everything works fine and improve the documentation before merging the changes.

Basically I check if I wrap around during the backward shift deletion and if it's the case i just return end().

Thibaut

from robin-map.

martinus avatar martinus commented on May 12, 2024

I think simply checking for a wrap around is not enough. E.g when you insert 3 elements at location 30, 2 elements are at the end and one will wrap around. When erasing the second to last, backward shift will wrap around but there is still one element left to be iterated

from robin-map.

Tessil avatar Tessil commented on May 12, 2024

Effectively I went a bit too fast with the proposed solution, it will not work in multiple cases. I'll check this evening to see how we can do that.

from robin-map.

Tessil avatar Tessil commented on May 12, 2024

Hi,

I checked a bit and currently I see the following possible solutions:

  • Keeping the same behaviour as std::unordered_map.
    • Don't wrap around, we just add a buffer at the end of the buckets (that is not counted in the bucket_count) to store the elements that would have wrapped around. We rehash the hash table if the buffer gets full regardless of the current load factor. The problem is the risk of memory DoS attacks as an attacker may force the hash table to rehash by inserting elements at the end.
    • When creating an iterator, add a reference to the last current element of the hash table except on erase where we propagate the reference to the returned iterator. If on erase we see that the element of the iterator is the same as the reference to the last element in the iterator we return end() after erasing it instead of the next element.
    • When calling begin(), return the first element that was not wrapped around. When incrementing the iterator, wrap around and continue until the last wrapped element
  • Different behaviour compare to std::unordered_map.
    • Leave it as it is and document the difference. When using erase in a loop it's usually to erase an element that meets a condition (e.g. if(it->first % 2 == 0) it = erase(it);) and not erase everything that come after an element.
    • Just don't return anything, we just change the return type to void. Not really viable as erasing while iterating can be quite useful.

The problem is more complex than expected and I have to think a bit if I can find another solution or which solution to pick-up.

Thibaut

from robin-map.

martinus avatar martinus commented on May 12, 2024

I also thought about adding an overflow buffer at the end. This might have a slight performance advantage because less need to & (tablesize-1). The DoS attack could also be mitigated with a hash that e.g. uses the this pointer, then the positions become less predictable.

Your iterator idea brings me to a new idea: How about instead of a reference, add a counter of the number of remaining items. begin() sets the counter to size(), and end() sets the counter to 0. Each ++it or it = erase(it) decrease the counter, comparing iterators just need to compare the counter. That needs no specil wrap-around handling, and begin() and end() stay fast operations

from robin-map.

Tessil avatar Tessil commented on May 12, 2024

Adding a counter would also be possible but the problem is that you also need to initialize it in other methods than begin(). For example on insertion you need to return an iterator to the inserted element, how can you get the remaining size until end() efficiently?

I also realised that a reference to the last element is not really possible either as it may be invalidated. It also has the same problem as with a counter, how do you efficiently get a reference to the last element in some methods? You could eventually maintain a pointer to the last element in the class and update it on each insert/erase. But it's getting quite complex.

from robin-map.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.