0

I want to give hints to std::map::lower_bound.
Why isn't it even allowed?

Suppose we need to implement something like:

static constexpr int TOTAL_SIZE = 1'000'000;
std::map<int, std::string> map{};

for (int i = 0; i < TOTAL_SIZE; ++i) {
    map[i] = "some_string" + std::to_string(i);
}

const int key1 = TOTAL_SIZE / 4;
const int key2 = TOTAL_SIZE / 2; /* `key2` is greater than `key1` */

const auto hint = map.lower_bound(key1);

if (hint != map.cbegin() && std::prev(hint)->second != "excluded_string") {
    map.insert_or_assign(hint, key1, "first_string_to_insert");
    const auto second_hint = map.lower_bound(key2); // we'd rather use `hint` here!

    if (second_hint != map.cbegin() && std::prev(second_hint)->second != "other_excluded_string") {
        map.insert_or_assign(second_hint, key2, "second_string_to_insert");
    }
}

How can we do this logic optimally and without rewriting it completely? The problem is that inability to pass a hint to lower_bound (2nd one) makes us do the same lookup twice. That's 2 times worse performance!

I would be happy, if I could do something like this:

static constexpr int TOTAL_SIZE = 1'000'000;
std::map<int, std::string> map{};

for (int i = 0; i < TOTAL_SIZE; ++i) {
    map[i] = "some_string" + std::to_string(i);
}

const int key1 = TOTAL_SIZE / 4;
const int key2 = TOTAL_SIZE / 2; /* `key2` is greater than `key1` */

const auto hint = map.lower_bound(key1);

if (hint != map.cbegin() && std::prev(hint)->second != "excluded_string") {
    const auto wanted_hint = map.insert_or_assign(hint, key1, "first_string_to_insert");
    const auto second_hint = map.lower_bound(wanted_hint, key2); // like this!

    if (second_hint != map.cbegin() && std::prev(second_hint)->second != "other_excluded_string") {
        map.insert_or_assign(second_hint, key2, "second_string_to_insert");
    }
}

This would allow to run the second lower_bound in amortized O(1) instead of O(log(N)).

Please, share the ideas on how to do that.
And is there a reason std::map::lower_bound does not accept a hint?

1
  • Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on Meta Stack Overflow, or in Stack Overflow Chat. Comments continuing discussion may be removed. Commented Jul 6 at 12:01

1 Answer 1

4

hint is the probable result of the query, so you can check it before (roughly that std::prev(hint)->first < key <= hint->first with correct bound checking.

If you ask for running std::map::lower_bound on a subrange, you can use std::lower_bound but map::iterator is not adapted to find the middle of the range (even with knwoledge of std::map::iterator internal).

std::map is roughly a binary tree, so map::lower_bound can be done without computing the middle of the range, it just have to use current node, and then visit left or right child.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.