110 #include <unordered_map>
111 #include <unordered_set>
114 #include "../base/functional.h"
115 #include "../base/logger.h"
133 template <
typename FilterT>
140 std::unordered_map<NodeImpl*, NodeImpl::ReqRespCallback>;
207 [[nodiscard]]
bool has_impl()
const;
362 template <
typename CallbackMapT,
typename CallbackT>
363 void traverse_internal_callback(
const CallbackMapT& map,
const CallbackT& callback);
365 bool has_called_{
false};
366 bool ignore_called_{
false};
368 mutable std::recursive_mutex mtx_;
375 NodeImpl* first_impl_{
nullptr};
396 template <
typename FilterT>
399 using Map = std::map<FilterT, std::weak_ptr<Object>>;
400 using Set = std::unordered_set<Object*>;
426 template <
typename ObjectT>
427 [[nodiscard]] std::shared_ptr<ObjectT>
get_object(
const FilterT& filter);
443 mutable std::mutex mtx_;
452 template <
typename FilterT>
454 std::lock_guard lock(mtx_);
458 return impl_list_.emplace(impl).second;
461 template <
typename FilterT>
463 std::lock_guard lock(mtx_);
465 if VUNLIKELY (impl_list_.erase(impl) == 0) {
469 if (first_impl_ == impl) {
470 first_impl_ = impl_list_.empty() ? nullptr : *impl_list_.begin();
473 server_connect_callback_map_.erase(impl);
474 sub_connect_callback_map_.erase(impl);
475 req_resp_callback_map_.erase(impl);
476 msg_callback_map_.erase(impl);
477 intra_msg_callback_map_.erase(impl);
478 status_callback_map_.erase(impl);
482 template <
typename FilterT>
484 std::lock_guard lock(mtx_);
488 template <
typename FilterT>
490 std::lock_guard lock(mtx_);
491 return impl_list_.find(impl) != impl_list_.end();
494 template <
typename FilterT>
496 std::lock_guard lock(mtx_);
497 return !impl_list_.empty();
500 template <
typename FilterT>
503 std::lock_guard lock(this->mtx_);
504 return server_connect_callback_map_.try_emplace(impl, std::move(callback)).second;
507 template <
typename FilterT>
510 std::lock_guard lock(this->mtx_);
511 return sub_connect_callback_map_.try_emplace(impl, std::move(callback)).second;
514 template <
typename FilterT>
516 std::lock_guard lock(this->mtx_);
517 return req_resp_callback_map_.try_emplace(impl, std::move(callback)).second;
520 template <
typename FilterT>
522 std::lock_guard lock(this->mtx_);
523 return msg_callback_map_.try_emplace(impl, std::move(callback)).second;
526 template <
typename FilterT>
529 std::lock_guard lock(this->mtx_);
530 return intra_msg_callback_map_.try_emplace(impl, std::move(callback)).second;
533 template <
typename FilterT>
535 std::lock_guard lock(this->mtx_);
536 return status_callback_map_.try_emplace(impl, std::move(callback)).second;
539 template <
typename FilterT>
541 std::lock_guard lock(this->mtx_);
542 return server_connect_callback_map_.empty();
545 template <
typename FilterT>
547 std::lock_guard lock(this->mtx_);
548 return sub_connect_callback_map_.empty();
551 template <
typename FilterT>
553 std::lock_guard lock(this->mtx_);
554 return req_resp_callback_map_.empty();
557 template <
typename FilterT>
559 std::lock_guard lock(this->mtx_);
560 return msg_callback_map_.empty();
563 template <
typename FilterT>
565 std::lock_guard lock(this->mtx_);
566 return intra_msg_callback_map_.empty();
569 template <
typename FilterT>
571 std::lock_guard lock(this->mtx_);
572 return status_callback_map_.empty();
575 template <
typename FilterT>
577 this->traverse_internal_callback(server_connect_callback_map_, callback);
580 template <
typename FilterT>
582 this->traverse_internal_callback(sub_connect_callback_map_, callback);
585 template <
typename FilterT>
587 this->traverse_internal_callback(req_resp_callback_map_, callback);
590 template <
typename FilterT>
592 this->traverse_internal_callback(msg_callback_map_, callback);
595 template <
typename FilterT>
597 this->traverse_internal_callback(intra_msg_callback_map_, callback);
600 template <
typename FilterT>
602 this->traverse_internal_callback(status_callback_map_, callback);
605 template <
typename FilterT>
608 template <
typename FilterT>
611 template <
typename FilterT>
616 template <
typename FilterT>
618 ignore_called_ =
true;
621 template <
typename FilterT>
622 template <
typename CallbackMapT,
typename CallbackT>
624 std::lock_guard lock(mtx_);
626 this->ignore_called_ =
false;
627 this->has_called_ =
false;
629 for (
const auto& [impl, target_callback] : map) {
630 callback(impl, target_callback);
633 this->ignore_called_ =
false;
635 this->has_called_ =
true;
640 template <
typename FilterT>
642 std::lock_guard lock(mtx_);
643 return set_.count(ptr) > 0;
646 template <
typename FilterT>
647 template <
typename ObjectT>
649 static_assert(std::is_base_of_v<Object, ObjectT>,
"ObjectT must be derived from AbstractObject");
650 std::shared_ptr<ObjectT> obj;
652 std::unique_lock lock(mtx_);
654 const auto& deleter = [
this, filter](ObjectT* obj) {
656 std::lock_guard lock(mtx_);
660 auto iter = map_.find(filter);
662 if VUNLIKELY (iter != map_.end() && iter->second.expired()) {
670 auto iter = map_.find(filter);
672 if (iter != map_.end()) {
673 obj = std::static_pointer_cast<ObjectT>(iter->second.lock());
684 auto* obj_ptr =
new ObjectT(filter);
687 auto [it, inserted] = map_.try_emplace(filter, std::weak_ptr<Object>());
690 obj = std::static_pointer_cast<ObjectT>(it->second.lock());
693 if (inserted || !obj) {
696 it = map_.try_emplace(filter, std::weak_ptr<Object>()).first;
699 obj = std::shared_ptr<ObjectT>(obj_ptr, deleter);
701 set_.emplace(obj_ptr);
710 template <
typename FilterT>
713 template <
typename FilterT>
Lazily allocates and caches AbstractObject instances keyed by FilterT.
Definition: abstract_factory.h:397
virtual ~AbstractFactory()
Destroys the factory and releases the cache.
bool has_object(Object *ptr) const
Tests whether ptr corresponds to a live object created by this factory.
Definition: abstract_factory.h:641
AbstractFactory()
Constructs an empty factory.
std::shared_ptr< ObjectT > get_object(const FilterT &filter)
Looks up or creates the ObjectT registered against filter.
Definition: abstract_factory.h:648
Tiny mix-in that exposes the backend-native handle behind a node.
Definition: node_impl.h:123
Topic-scoped fan-out store of NodeImpl peers and their callbacks.
Definition: abstract_factory.h:134
bool add_impl(NodeImpl *impl)
Registers impl as an active peer on this topic.
Definition: abstract_factory.h:453
std::unordered_map< NodeImpl *, NodeImpl::ConnectCallback > ConnectCallbackMap
Connect handlers per impl.
Definition: abstract_factory.h:138
bool req_resp_map_is_empty() const
Reports whether the request/response dictionary is empty.
Definition: abstract_factory.h:552
NodeImpl * get_first_impl() const
Returns the most recently registered peer.
Definition: abstract_factory.h:483
bool register_msg_callback(NodeImpl *impl, NodeImpl::MsgCallback &&callback)
Stores callback as the serialised-message handler for impl.
Definition: abstract_factory.h:521
bool server_connect_map_is_empty() const
Reports whether the server-connect dictionary is empty.
Definition: abstract_factory.h:540
void traverse_server_connect_callback(const FindConnectCallback &callback)
Walks the server-connect dictionary and invokes callback for every entry.
Definition: abstract_factory.h:576
bool register_req_resp_callback(NodeImpl *impl, NodeImpl::ReqRespCallback &&callback)
Stores callback as the request/response handler for impl.
Definition: abstract_factory.h:515
std::unordered_map< NodeImpl *, NodeImpl::ReqRespCallback > ReqRespCallbackMap
Req/resp callbacks, keyed by impl.
Definition: abstract_factory.h:140
bool has_called() const
Definition: abstract_factory.h:612
bool sub_connect_map_is_empty() const
Reports whether the subscriber-connect dictionary is empty.
Definition: abstract_factory.h:546
bool remove_impl(NodeImpl *impl)
Removes impl from the peer set and forgets every associated callback.
Definition: abstract_factory.h:462
bool register_server_connect_callback(NodeImpl *impl, NodeImpl::ConnectCallback &&callback)
Stores callback as the server-side connect handler for impl.
Definition: abstract_factory.h:501
std::unordered_set< NodeImpl * > ImplList
Set of currently registered NodeImpl peers.
Definition: abstract_factory.h:136
bool status_map_is_empty() const
Reports whether the transport-status dictionary is empty.
Definition: abstract_factory.h:570
std::unordered_map< NodeImpl *, NodeImpl::StatusCallback > StatusCallbackMap
Status callbacks per impl.
Definition: abstract_factory.h:143
bool register_sub_connect_callback(NodeImpl *impl, NodeImpl::ConnectCallback &&callback)
Stores callback as the subscriber-side connect handler for impl.
Definition: abstract_factory.h:508
bool register_intra_msg_callback(NodeImpl *impl, NodeImpl::IntraMsgCallback &&callback)
Stores callback as the intra-process message handler for impl.
Definition: abstract_factory.h:527
bool msg_map_is_empty() const
Reports whether the serialised-message dictionary is empty.
Definition: abstract_factory.h:558
void ignore_called()
Definition: abstract_factory.h:617
void traverse_intra_msg_callback(const FindIntraMsgCallback &callback)
Walks the intra-process dictionary and invokes callback for every entry.
Definition: abstract_factory.h:596
std::unordered_map< NodeImpl *, NodeImpl::IntraMsgCallback > IntraMsgCallbackMap
Intra-message callbacks.
Definition: abstract_factory.h:142
void traverse_status_callback(const FindStatusCallback &callback)
Walks the transport-status dictionary and invokes callback for every entry.
Definition: abstract_factory.h:601
void traverse_sub_connect_callback(const FindConnectCallback &callback)
Walks the subscriber-connect dictionary and invokes callback for every entry.
Definition: abstract_factory.h:581
bool has_impl() const
Indicates whether at least one peer has been registered.
Definition: abstract_factory.h:495
void traverse_req_resp_callback(const FindReqRespCallback &callback)
Walks the request/response dictionary and invokes callback for every entry.
Definition: abstract_factory.h:586
std::unordered_map< NodeImpl *, NodeImpl::MsgCallback > MsgCallbackMap
Message callbacks, keyed by impl.
Definition: abstract_factory.h:141
bool is_contains_impl(NodeImpl *impl) const
Tests whether impl is currently part of the peer set.
Definition: abstract_factory.h:489
bool intra_msg_map_is_empty() const
Reports whether the intra-process message dictionary is empty.
Definition: abstract_factory.h:564
~AbstractObject() override
void traverse_msg_callback(const FindMsgCallback &callback)
Walks the serialised-message dictionary and invokes callback for every entry.
Definition: abstract_factory.h:591
bool register_status_callback(NodeImpl *impl, NodeImpl::StatusCallback &&callback)
Stores callback as the transport-status handler for impl.
Definition: abstract_factory.h:534
Copyable type-erased callable analogue of std::function with a tunable SBO and pool spill.
Definition: functional.h:131
Backbone of every transport-specific VLink node implementation.
Definition: node_impl.h:163
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174
Foundational base classes shared by every transport-backed VLink node.