newmen/versatile-diamond

View on GitHub
engine/cpp/mc/events/multi_events_container.cpp

Summary

Maintainability
Test Coverage
#include "multi_events_container.h"

namespace vd
{

MultiEventsContainer::~MultiEventsContainer()
{
    Atom *prev = nullptr;
    for (auto &pr : _positions)
    {
        if (pr.first == prev)
        {
            _events[pr.second] = nullptr;
        }

        prev = pr.first;
    }

    for (Reaction *event : _events)
    {
        delete event; // erase memory here directly (wihtout scavenger mark)
    }
}

#ifndef NDEBUG
Reaction *MultiEventsContainer::selectEventByCoords(const int3 &crd)
{
    for (Reaction *event : _events)
    {
        UbiquitousReaction *ubiqEvent = static_cast<UbiquitousReaction *>(event);
        if (ubiqEvent->target()->lattice() && ubiqEvent->target()->lattice()->coords() == crd)
        {
            return event;
        }
    }

    assert(false); // multi event by crd was not found
    return nullptr;
}
#endif // NDEBUG

void MultiEventsContainer::add(UbiquitousReaction *event, ushort n)
{
    for (uint i = 0; i < n; ++i)
    {
        _positions.insert(std::pair<Atom *, uint>(event->target(), _events.size()));
        _events.push_back(event);
    }
}

void MultiEventsContainer::remove(Atom *target, ushort n)
{
#ifndef NDEBUG
    auto range = _positions.equal_range(target);
    assert(std::distance(range.first, range.second) >= n);
#endif // NDEBUG

    unlockedRemove(target, n);
}

uint MultiEventsContainer::removeAll(Atom *target)
{
    auto range = _positions.equal_range(target);
    uint n = std::distance(range.first, range.second);
    unlockedRemove(target, n);
    return n;
}

bool MultiEventsContainer::check(Atom *target)
{
    return _positions.find(target) != _positions.cend();
}

void MultiEventsContainer::unlockedRemove(Atom *target, uint n)
{
    for (uint i = 0; i < n; ++i)
    {
        auto currIt = _positions.find(target);
        assert(currIt != _positions.cend());

        Reaction *current = _events[currIt->second];

        UbiquitousReaction *last = exchangeToLast<UbiquitousReaction>(currIt->second);
        if (last)
        {
            uint lastIndex = _events.size();
            auto range = _positions.equal_range(last->target());

#ifndef NDEBUG
            bool found = false;
#endif // NDEBUG
            for (auto it = range.first; it != range.second; it++)
            {
                if (it->second == lastIndex)
                {
                    it->second = currIt->second;
#ifndef NDEBUG
                    found = true;
#endif // NDEBUG
                    break;
                }
            }

#ifndef NDEBUG
            assert(found);
#endif // NDEBUG
        }

        _positions.erase(currIt);

        auto range = _positions.equal_range(target);
        bool haveSame = false;
        for (auto it = range.first; it != range.second; it++)
        {
            if (_events[it->second] == current)
            {
                haveSame = true;
                break;
            }
        }

        if (!haveSame)
        {
            current->remove();
        }
    }

    assert(_events.size() == _positions.size());
}

}