#pragma once #include #include #include #include #include #include #include #include #include #include #include "common/aggregate_command.hh" #include "common/history.hh" namespace nf7 { class NodeLinkStore { public: class SwapCommand; struct Link { public: uint64_t src_id; std::string src_name; uint64_t dst_id; std::string dst_name; bool operator==(const Link& other) const noexcept { if (src_id && other.src_id && src_id != other.src_id) return false; if (dst_id && other.dst_id && dst_id != other.dst_id) return false; if (src_name.size() && other.src_name.size() && src_name != other.src_name) return false; if (dst_name.size() && other.dst_name.size() && dst_name != other.dst_name) return false; return true; } template Ar& serialize(Ar& ar) { ar(src_id, src_name, dst_id, dst_name); return ar; } }; NodeLinkStore() = default; NodeLinkStore(const NodeLinkStore&) = default; NodeLinkStore(NodeLinkStore&&) = default; NodeLinkStore& operator=(const NodeLinkStore&) = default; NodeLinkStore& operator=(NodeLinkStore&&) = default; template Ar& serialize(Ar& ar) { ar(links_); return ar; } void AddLink(Link&& lk) noexcept { links_.push_back(std::move(lk)); } void RemoveLink(const Link& lk) noexcept { links_.erase(std::remove(links_.begin(), links_.end(), lk), links_.end()); } inline std::unique_ptr CreateCommandToRemoveExpired( uint64_t id, std::span in, std::span out) noexcept; std::span items() const noexcept { return links_; } private: std::vector links_; }; class NodeLinkStore::SwapCommand : public History::Command { public: static std::unique_ptr CreateToAdd( NodeLinkStore& target, Link&& lk) noexcept { return std::make_unique(target, std::move(lk), false); } static std::unique_ptr CreateToRemove( NodeLinkStore& target, Link&& lk) noexcept { return std::make_unique(target, std::move(lk), true); } SwapCommand(NodeLinkStore& target, Link&& lk, bool added) noexcept : target_(&target), link_(std::move(lk)), added_(added) { } void Apply() noexcept override { Exec(); } void Revert() noexcept override { Exec(); } private: NodeLinkStore* const target_; Link link_; bool added_; void Exec() noexcept { added_? target_->RemoveLink(link_): target_->AddLink(Link(link_)); added_ = !added_; } }; std::unique_ptr NodeLinkStore::CreateCommandToRemoveExpired( uint64_t id, std::span in, std::span out) noexcept { std::vector> cmds; for (const auto& lk : links_) { const bool rm = (lk.src_id == id && std::find(out.begin(), out.end(), lk.src_name) == out.end()) || (lk.dst_id == id && std::find(in .begin(), in .end(), lk.dst_name) == in .end()); if (rm) cmds.push_back(SwapCommand::CreateToRemove(*this, Link(lk))); } if (cmds.empty()) return nullptr; return std::make_unique>(std::move(cmds)); } } // namespace nf7