#include "./internal_mfs_contexts.hpp" #include "./message_fragment_store.hpp" #include #include #include #include static bool isLess(const std::vector& lhs, const std::vector& rhs) { size_t i = 0; for (; i < lhs.size() && i < rhs.size(); i++) { if (lhs[i] < rhs[i]) { return true; } else if (lhs[i] > rhs[i]) { return false; } // else continue } // here we have equality of common lenths // we define smaller arrays to be less return lhs.size() < rhs.size(); } bool Message::Contexts::ContactFragments::insert(ObjectHandle frag) { if (sorted_frags.contains(frag)) { return false; } // both sorted arrays are sorted ascending // so for insertion we search for the last index that is <= and insert after it // or we search for the first > (or end) and insert before it <--- // since equal fragments are UB, we can assume they are only > or < size_t begin_index {0}; { // begin const auto pos = std::find_if( sorted_begin.cbegin(), sorted_begin.cend(), [frag](const Object a) -> bool { const auto begin_a = frag.registry()->get(a).begin; const auto begin_frag = frag.get().begin; if (begin_a > begin_frag) { return true; } else if (begin_a < begin_frag) { return false; } else { // equal ts, we need to fall back to id (id can not be equal) return isLess(frag.get().v, frag.registry()->get(a).v); } } ); begin_index = std::distance(sorted_begin.cbegin(), pos); // we need to insert before pos (end is valid here) sorted_begin.insert(pos, frag); } size_t end_index {0}; { // end const auto pos = std::find_if_not( sorted_end.cbegin(), sorted_end.cend(), [frag](const Object a) -> bool { const auto end_a = frag.registry()->get(a).end; const auto end_frag = frag.get().end; if (end_a > end_frag) { return true; } else if (end_a < end_frag) { return false; } else { // equal ts, we need to fall back to id (id can not be equal) return isLess(frag.get().v, frag.registry()->get(a).v); } } ); end_index = std::distance(sorted_end.cbegin(), pos); // we need to insert before pos (end is valid here) sorted_end.insert(pos, frag); } sorted_frags.emplace(frag, InternalEntry{begin_index, end_index}); // now adjust all indicies of fragments coming after the insert position for (size_t i = begin_index + 1; i < sorted_begin.size(); i++) { sorted_frags.at(sorted_begin[i]).i_b = i; } for (size_t i = end_index + 1; i < sorted_end.size(); i++) { sorted_frags.at(sorted_end[i]).i_e = i; } return true; } bool Message::Contexts::ContactFragments::erase(Object frag) { auto frags_it = sorted_frags.find(frag); if (frags_it == sorted_frags.end()) { return false; } assert(sorted_begin.size() == sorted_end.size()); assert(sorted_begin.size() > frags_it->second.i_b); sorted_begin.erase(sorted_begin.begin() + frags_it->second.i_b); sorted_end.erase(sorted_end.begin() + frags_it->second.i_e); sorted_frags.erase(frags_it); return true; } Object Message::Contexts::ContactFragments::prev(Object frag) const { // uses range begin to go back in time auto it = sorted_frags.find(frag); if (it == sorted_frags.end()) { return entt::null; } const auto src_i = it->second.i_b; if (src_i > 0) { return sorted_begin[src_i-1]; } return entt::null; } Object Message::Contexts::ContactFragments::next(Object frag) const { // uses range end to go forward in time auto it = sorted_frags.find(frag); if (it == sorted_frags.end()) { return entt::null; } const auto src_i = it->second.i_e; if (src_i+1 < sorted_end.size()) { return sorted_end[src_i+1]; } return entt::null; }