Быстрая вставка уникального контейнера

Мне нужно хранить элементы (состояние структуры) в контейнере 2D-вектора, и каждый элемент должен быть уникальным.

Я храню такие элементы:

std::vector<std::vector<std::unique_ptr<State>>> m_container;

И у меня есть функция вставки

bool insert(State && value, std::size_t deepness);

Которая должна вставить «значение» в m_container [глубина], если значение уникально или новая глубина меньше, чем предыдущая, и в этом случае мне нужно удалить предыдущее состояние (вставляется return true).

У меня одновременно вставляются несколько потоков, у меня уже есть реализация, но я не уверен, что она лучшая, поэтому меня интересует лучший и более быстрый способ вставки или некоторые улучшения.

Моя реализация довольно длинная, поэтому я стараюсь уменьшить ее, сохраняя при этом логику.

кроме контейнера, у меня есть multimap:

std::multimap<std::size_t, std::pair<std::size_t, std::size_t>> m_multimap;

ключ: хеш состояния

пара_1: глубина

пара_2: положение государства в m_container [глубина]

У меня есть lockless_queue структуры Temp (lockless_queue m_queue), которую я вставляю сначала сюда, а затем в контейнер.

template<typename T>
class lockless_queue {
public:
    // storeing the elements
    struct node;
    struct node_ptr;

    // insert element
    template<typename... Args>
    void produce(Args&&... args);
    void produce(T && data);
    void produce(const T & data);

    // consume all elements form queue
    node_ptr consume_all();

    // queue is not empty
    operator bool() const;
};

struct Temp {
    std::unique_ptr<State> value;
    std::size_t hash;
    std::size_t deepness;
    bool exist = false;

    Temp(State * v, std::size_t hash, std::size_t deepness, bool exist);
    Temp(State && v, std::size_t deepness);

    Temp move() {
        return Temp(value.release(), hash, deepness, exist);
    }

    bool is_equal(const State & state) const;
    bool is_equal(State * state) const;
    bool is_equal(const Temp & other) const;
    bool is_equal(Temp * other) const;

    void swap(State && v, std::size_t d) {
        deepness = d;
        value.reset(new State(std::move(v)));
    }
};

Следующая функция - это функция вставки, которая вставляется в locless_queue.

bool pre_emplace(State && value, std::size_t deepness) {
    Temp temp(std::move(value), deepness);
    const auto range = m_multimap.equal_range(temp.hash);
    if (range.first == range.second) {
        m_queue.produce(std::move(temp));
        return true;
    } else {
        const auto & container = m_container;
        const auto it = std::find_if (range.first, range.second, [&temp, &container](const auto & iter) {
            return temp.is_equal(container[iter.second.first][iter.second.second].get());
        });
        if (it == range.second || deepness < it->second.first) {
            temp.exist = true;
            m_queue.produce(std::move(temp));
            return true;
        }
    }
    return false;
}

(в некоторых случаях возвращаемое значение является недопустимым, потому что очередь не уникальна, но это не проблема, я использую возвращаемое значение только для оценки количества выведенных элементов)

эта функция потребляет элементы из очереди во временную мультикарту хеша и Temp

void m_finalize_cycle(std::multimap<std::size_t, Temp> & multimap) {
    auto head = m_queue.consume_all();
    auto node = head.ptr;
    while (node != nullptr) {
        if (node->data.value == false) { node = node->next;  continue; }
        auto & temp = node->data;
        const auto range = multimap.equal_range(temp.hash);
        if (range.first == range.second) {
            multimap.emplace(std::make_pair(temp.hash, temp.move()));
        } else {
            const auto it = std::find_if (range.first, range.second, [&temp](const auto & pair) {
                return temp.is_equal(pair.second.value.get());
            });
            if (it == range.second) {
                multimap.emplace_hint(range.first, std::make_pair(temp.hash, temp.move()));
            } else if (temp.deepness < it->second.deepness) {
                it->second.value.reset(temp.value.release());
                it->second.deepness = temp.deepness;
            }
        }
        node = node->next;
    }
}

и эта функция загружает все значения Temp из предыдущего mulimep в m_container

void m_finalize_write(std::multimap<std::size_t, Temp> & multimap) {
    for (auto &[hash, temp] : multimap) {
        if (temp.exist) {
            const auto range = m_multimap.equal_range(temp.hash);
            auto & container = m_container;
            const auto it = std::find_if (range.first, range.second, [&temp, &container](const auto & iter) {
                return temp.is_equal(container[iter.second.first][iter.second.second].get());
            });
            if (it != range.second) {
                m_container.at(it->second.first).at(it->second.second).reset(nullptr);
                m_multimap.erase(it);
            }
        } else {
        }
        // extend m_container
        extend_if_needed(temp.deepness);
        m_container.at(temp.deepness).push_back(std::move(std::unique_ptr<State>(temp.value.release())));
        m_multimap.emplace(hash, std::make_pair(temp.deepness, m_container[temp.deepness].size() - 1));
    }
}

пока я вставляю элементы, я запускаю m_finalize_cycle каждые 10 микросекунд, а затем, если я закончил со вставками, я вызываю m_finalize_write.

Эта реализация мне подходит, но, к сожалению, это самая медленная часть моего кода, поэтому меня интересуют способы получше.

Похоже, у вас есть рабочий код, и вы просто пытаетесь его оптимизировать или улучшить. Может лучше спросить на Code Review SE

Tas 24.04.2018 11:42

@Tas Спасибо за совет, я тоже опубликую там свой вопрос

Sekkmer 24.04.2018 11:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
131
0

Другие вопросы по теме