15#include "sparta/utils/StringManager.hpp"
60 #define REGISTER_FOR_THIS(func) \
61 registerForThis<typename std::remove_reference<decltype(*this)>::type, \
62 &std::remove_reference<decltype(*this)>::type::func>(this);
69 #define DEREGISTER_FOR_THIS(func) \
70 deregisterForThis<typename std::remove_reference<decltype(*this)>::type, \
71 &std::remove_reference<decltype(*this)>::type::func>(this);
74 class MirrorNotificationSource;
181 ObservationStateCallbackPrivateInterface::registerObservationStateChangeCallback_(ns_,
this);
187 if (tree_node_weak_ptr_.expired() ==
false) {
188 ObservationStateCallbackPrivateInterface::deregisterObservationStateChangeCallback_(ns_,
this);
205 uint32_t observers)
const
207 callback_(ns, observers);
213 void dump(std::ostream& o)
const {
214 o <<
"<ObservationStateCallback type=" <<
static_cast<int>(type_) <<
" node=";
215 if(tree_node_weak_ptr_.expired()){
218 o << tree_node_weak_ptr_.lock()->getLocation();
233 ns.registerObservationStateChangeCallback_(cbobject);
240 ns.deregisterObservationStateChangeCallback_(cbobject);
274 const std::string& name,
275 const std::string& group,
277 const std::string& desc,
278 const std::string* notification_name_id,
279 const std::type_info& notification_tinfo) :
280 TreeNode(name, group, group_idx, desc),
286 if(
nullptr == parent){
288 <<
getLocation() <<
" must be constructed with a parent";
293 if(
nullptr == notification_name_id){
295 <<
getLocation() <<
" cannot be constructed with a null notification_name_id";
305 determineObs_Nodes_();
313 const std::string& name,
314 const std::string& group,
316 const std::string& desc,
317 const std::string& notification_name,
318 const std::type_info& notification_tinfo) :
320 StringManager::getStringManager().internString(notification_name),
353 << nm <<
"\" is a reserved word. ";
357 if(nm.size() > 0 && nm[0] ==
'_'){
359 << nm <<
"\" begins with an '_' which is not permitted";
362 if(nm.find(
"__") != std::string::npos){
364 << nm <<
"\" contains two adjacent underscores which is not permitted";
369 << nm <<
"\" begins with a '" << nm[nm.size()-1] <<
"' character which is not permitted. "
370 <<
"A Notification name must not begin with a decimal digit.";
374 if(pos != std::string::npos){
376 << nm <<
"\" contains a '" << nm[pos] <<
"', which is not permitted. "
377 <<
"A Notification name must contain only alphanumeric characters and underscores.";
500 const std::string* name_id,
515 dels_.push_back(*del);
521 if(not was_observed){
530 const std::string* name_id,
541 auto delitr = std::find(
dels_.begin(),
dels_.end(), *del);
542 if(delitr !=
dels_.end()){
549 bool remaining =
false;
551 if(d.getObservationPoint() == obs_node){
556 if(
false == remaining){
574 const std::string*
id,
575 const std::string*& match)
const override {
589 virtual std::string
stringize(
bool pretty=
false)
const override {
591 std::stringstream ss;
601 virtual void onAddedAsChild_() noexcept override final {
602 determineObs_Nodes_();
615 void determineObs_Nodes_() {
626 node = node->getParent();
641 void getPossibleNotifications_(std::vector<NotificationInfo>& infos)
const override {
648 void registerObservationStateChangeCallback_(ObservationStateCallback*
const hook) {
650 sparta_assert(in_observation_state_change_callback_ ==
false,
651 "cannot add observation state change callbacks from within a callback");
655 sparta_assert(std::find(obs_state_change_cbs_.begin(), obs_state_change_cbs_.end(), hook) == obs_state_change_cbs_.end(),
656 "Internal notification hook " << *hook
657 <<
" was installed a second time to notification source " << *
this);
660 obs_state_change_cbs_.emplace_back(hook);
666 void deregisterObservationStateChangeCallback_(ObservationStateCallback*
const hook) {
668 sparta_assert(in_observation_state_change_callback_ ==
false,
669 "cannot remove observation state change callbacks from within a callback");
671 const auto itr = std::find(obs_state_change_cbs_.begin(), obs_state_change_cbs_.end(), hook);
675 "Internal notification hook " << *hook
676 <<
" was not found while attemptint to deregister it from notification source " << *
this);
679 obs_state_change_cbs_.erase(itr);
689 sparta_assert(in_observation_state_change_callback_ ==
false,
690 "cannot recursively invoke observation state change callbacks from within a "
691 "callback. User may be changing Notification Observers in response to "
692 "changes in observation state. This is not allowed");
694 in_observation_state_change_callback_ =
true;
698 for(ObservationStateCallback
const * cb : obs_state_change_cbs_){
699 if(cb->getType() == to_call){
704 in_observation_state_change_callback_ =
false;
709 in_observation_state_change_callback_ =
false;
720 std::vector<ObservationStateCallback*> obs_state_change_cbs_;
730 bool in_observation_state_change_callback_ =
false;
742 template <
typename NotificationDataT>
767 const std::string& name,
768 const std::string& group,
770 const std::string& desc,
771 const std::string* notification_name_id) :
773 desc, notification_name_id,
774 typeid(NotificationDataT))
776 static_assert(std::is_same<
777 typename std::remove_cv<
778 typename std::remove_reference<
779 typename std::remove_pointer<NotificationDataT>::type
784 "NotificationDataT must NOT be a const, volatile, pointer, or reference"
785 "type. It violates at least one of these restrictions");
793 const std::string& name,
794 const std::string& group,
796 const std::string& desc,
797 const std::string& notification_name) :
803 StringManager::getStringManager().internString(notification_name))
810 const std::string& name,
811 const std::string& desc,
812 const std::string* notification_name_id) :
818 notification_name_id)
825 const std::string& name,
826 const std::string& desc,
827 const std::string& notification_name) :
833 StringManager::getStringManager().internString(notification_name))
840 const std::string& group,
842 const std::string& desc,
843 const std::string* notification_name_id) :
849 notification_name_id)
856 const std::string& group,
858 const std::string& desc,
859 const std::string& notification_name) :
865 StringManager::getStringManager().internString(notification_name))
924 template <
typename T,
void (T::*TMethod)(const TreeNode&, const TreeNode&, const_data_type&)>
930 template <
typename T,
void (T::*TMethod)(const_data_type&)>
943 template <
typename T,
void (T::*TMethod)(const TreeNode&, const TreeNode&, const_data_type&)>
949 template <
typename T,
void (T::*TMethod)(const_data_type&)>
1002 void setFormatString(
const std::string& format_str)
1009 auto specs = parseFormatSpecifiers_(format_str);
1010 if (!parsed_specs_.empty())
1016 parsed_specs_ = specs;
1019 format_str_ = format_str;
1022 bool hasFormatString()
const {
1023 return !format_str_.empty();
1033 template <
typename... Args>
1037 "setFormatString() must be called before postNotification() on " <<
getLocation());
1039 constexpr std::array<SpecType,
sizeof...(Args)> expected_types { specTypeFor_<Args>()... };
1041 if(parsed_specs_.size() !=
sizeof...(Args)){
1043 << format_str_ <<
"\" for " <<
getLocation() <<
" has " << parsed_specs_.size()
1044 <<
" specifier(s) but " <<
sizeof...(Args) <<
" argument(s) were given";
1047 for(std::size_t i = 0; i < parsed_specs_.size(); ++i){
1048 if(parsed_specs_[i] != expected_types[i]){
1051 <<
" has a type mismatch at specifier index " << i;
1056 const std::array<std::function<void(std::ostringstream&)>,
sizeof...(Args)> streamers {
1057 [&args](std::ostringstream& o){ o << args; }...
1060 std::ostringstream oss;
1061 std::size_t arg_idx = 0;
1062 for(std::size_t i = 0; i < format_str_.size(); ++i){
1063 if(format_str_[i] !=
'%'){
1064 oss << format_str_[i];
1068 const char spec = format_str_[++i];
1072 streamers[arg_idx++](oss);
1080 enum class SpecType { STRING, INT };
1083 template <
typename T>
1084 static constexpr SpecType specTypeFor_()
1086 using PlainT =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1087 if constexpr (std::is_integral<PlainT>::value && !std::is_same<PlainT, bool>::value){
1088 return SpecType::INT;
1090 return SpecType::STRING;
1095 static std::vector<SpecType> parseFormatSpecifiers_(
const std::string& format_str)
1097 std::vector<SpecType> specs;
1098 for(std::size_t i = 0; i < format_str.size(); ++i){
1099 if(format_str[i] !=
'%'){
1103 if(i + 1 >= format_str.size()){
1104 throw SpartaException(
"Sprintf format string \"")
1105 << format_str <<
"\" ends with a lone '%' character";
1108 const char spec = format_str[++i];
1111 specs.push_back(SpecType::STRING);
1114 specs.push_back(SpecType::INT);
1119 throw SpartaException(
"Sprintf format string \"")
1120 << format_str <<
"\" contains unsupported specifier '%" << spec
1121 <<
"'. Only %s and %i are supported";
1127 std::string format_str_;
1128 std::vector<SpecType> parsed_specs_;
1139 template<
typename NotificationDataT>
1142 typedef std::vector<NotificationSourceBase*> SrcList;
1160 const std::string& name,
1161 const std::string& group,
1163 const std::string& desc,
1164 const std::string* notification_name_id):
1166 notification_name_id,
1167 typeid(NotificationDataT))
1175 const std::string& name,
1176 const std::string& group,
1178 const std::string& desc,
1179 const std::string& notification_name) :
1183 typeid(NotificationDataT))
1188 const std::string& name,
1189 const std::string& desc,
1190 const std::string& notification_name) :
1196 StringManager::getStringManager().internString(notification_name))
1214 const uint32_t prev_size = concretes_.size();
1215 findMatchingSourcesBelowNode_(*node, concretes_);
1219 if (concretes_.size() - prev_size == 0)
1222 ex <<
getName() <<
"\" was unable to bind to any real NotificationSources"
1223 <<
" found under the nodes provided to addLink().";
1256 findMatchingSourcesBelowNode_(*n, bases);
1262 void notificationObserverAdded_(
const std::type_info& tinfo,
1263 const std::string* name_id,
1265 const delegate* del)
override final
1267 if (del->revealsOrigin())
1269 SpartaException ex(
"Cannot register for notification \"");
1270 ex << *name_id <<
"\"" <<
" because this notification source "
1271 <<
"is only shadowing a private concrete notification source. "
1272 <<
"The callback signature type would reveal access to a private node "
1273 <<
"and be misleading. We do not support this feature at this time.";
1277 if (concretes_.size() == 0)
1279 SpartaException ex (
"Cannot register for notification \"");
1280 ex << *name_id <<
"\" because this is a MirrorNotificationSource "
1281 <<
"that is not linked to any concrete sources. It is possible you "
1282 <<
"are registering for the notification too early and should be registering "
1283 <<
"during onBindTreeLate_()";
1286 for(
auto concrete : concretes_)
1288 concrete->notificationObserverAdded_(tinfo, name_id,
1294 void notificationObserverRemoved_(
const std::type_info& tinfo,
1295 const std::string* name_id,
1297 const delegate* del)
override final
1299 if (concretes_.size() == 0)
1301 SpartaException ex (
"Cannot deregister for notification \"");
1302 ex << *name_id <<
"\" because this is a MirrorNotificationSource "
1303 <<
"that is not linked to any concrete sources. It is possible you "
1304 <<
"are deregistering for the notification too early and should be registering "
1305 <<
"during onBindTreeLate_()";
1309 for(
auto concrete : concretes_)
1311 concrete->notificationObserverRemoved_(tinfo, name_id,
1317 bool canGenerateNotification_(
const std::type_info& tinfo,
1318 const std::string*
id,
1319 const std::string*& match)
const override final
1321 if (concretes_.size() == 0)
1325 bool can_generate =
true;
1326 for (
auto noti_src : concretes_)
1328 can_generate &= noti_src->canGenerateNotification_(tinfo,
id, match);
1330 return can_generate;
1339 void validateNode_() const override final
1341 if (concretes_.size() == 0)
1343 SpartaException ex(
"Unbound MirrorNotificationSource ");
1344 ex <<
getName() <<
" was never bound to concrete notification sources.";
1350 virtual std::string stringize(
bool pretty=
false) const override final {
1352 std::stringstream ss;
1356 ss << concretes_.size() <<
" sources ";
1358 catch (SpartaException&)
1360 ss <<
"[UNAVAILABLE]";
1368 inline std::ostream&
operator<<(std::ostream& o,
const NotificationSourceBase::ObservationStateCallback& osc)
1374 inline std::ostream&
operator<<(std::ostream& o,
const NotificationSourceBase::ObservationStateCallback* osc)
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
#define RESERVED_WORDS
Reserved words in Python language, Python builtins, and other reservations. TreeNode names and groups...
#define ALPHANUM_CHARS
Enables tracing of TreeNode lifetimes in a set of output txt files.
#define DIGIT_CHARS
Digit characters (for valid TreeNode groups)
essentially a pass through notification source that is a placeholder in a shadow tree.
MirrorNotificationSource(TreeNode *parent, const std::string &name, const std::string &group, TreeNode::group_idx_type group_idx, const std::string &desc, const std::string *notification_name_id)
MirrorNotificationSource.
void addLink(TreeNode *node, const std::string &label) override final
MirrorNotificationSource(TreeNode *parent, const std::string &name, const std::string &group, TreeNode::group_idx_type group_idx, const std::string &desc, const std::string ¬ification_name)
Alternate construct that accepts a notification name string instead of an interned string pointer.
Controlled interface to NotificationSourceBase for regiistering and deregistering observation state c...
Callback for observation-state of a NotificationSourceBase.
void operator()(NotificationSourceBase const &ns, uint32_t observers) const
Invoked the callback function.
void dump(std::ostream &o) const
Dump string description to an ostream.
ObservationStateChange getType() const
Get tyhe type of change associated with this callback instance.
A TreeNode that generates a single specific type of notification which propagates up a tree of TreeNo...
virtual ~NotificationSourceBase()
Destructor.
static void validateNotificationName(const std::string &nm)
Validates the given notification name string.
bool observed_
Cached value of obs_nodes_.size() > 0 for faster queries.
friend class ObservationStateCallbackInterface
Allow controlled interaction with some members of this class.
bool canGenerateNotification_(const std::type_info &tinfo, const std::string *id, const std::string *&match) const override
Implements TreeNode::canGenerateNotification. Node subclasses which will post notifications must impl...
const std::string & getNotificationName() const
Returns the notification name string for slow string comparison or printing.
ObservationStateChange
Various hook types for which one can register internal callbacks on this notificaiton source.
@ SOLE_OBSERVER_REGISTERING
A sole observer is being registered to observe this notification source. This is a transition from 0 ...
@ OBSERVER_REGISTERING
An observer is being registered to observe this notification source. This may be the first,...
@ SOLE_OBSERVER_DEREGISTERING
A sole observer is being de-registered from observing this notification source. This is a transition ...
@ OBSERVER_DEREGISTERING
An observer is being de-registered from observing this notification source. This may be the first,...
uint32_t getNumObservers() const
Returns the number of delegates affected by postings of this notification.
std::vector< TreeNode * > obs_nodes_
Vector of TreeNodes at which the notification that this node can generate is being observed.
bool observed() const noexcept
Is this NotificationSourceBase being observed at this node or an ancestor of any distance.
virtual void notificationObserverRemoved_(const std::type_info &tinfo, const std::string *name_id, TreeNode *obs_node, const delegate *del) override
NotificationSourceBase(TreeNode *parent, const std::string &name, const std::string &group, TreeNode::group_idx_type group_idx, const std::string &desc, const std::string *notification_name_id, const std::type_info ¬ification_tinfo)
NotificationSourceBase.
virtual std::string stringize(bool pretty=false) const override
Create a string representation of this node.
std::function< void(NotificationSourceBase const &, uint32_t)> callback_t
Observation state change callback function signature.
const std::type_info & noti_tinfo_
Type of notification data.
virtual void notificationObserverAdded_(const std::type_info &tinfo, const std::string *name_id, TreeNode *obs_node, const delegate *del) override
uint64_t getNumPosts() const
Returns the number of notifications posted by this node.
NotificationSourceBase(TreeNode *parent, const std::string &name, const std::string &group, TreeNode::group_idx_type group_idx, const std::string &desc, const std::string ¬ification_name, const std::type_info ¬ification_tinfo)
Alternate construct that accepts a notification name string instead of an interned string pointer.
friend class MirrorNotificationSource
uint32_t getNumObservationPoints() const
Returns the number of observation points affecting this notification source.
const std::string getNotificationTypeName() const
Gets the demangled name of the C++ notification type which this NotificationSource can emit.
const std::vector< TreeNode * > & getObservationPoints() const
Returns the vector of observation points on this notification source.
const std::type_info & getNotificationType() const
Returns std::type_info from typeid() on the notification data type which this NotificationSource can ...
uint64_t num_posts_
Number of messages posted whether observed or not.
const std::string * noti_id_
Name of notification generated. Should be similar to node name.
std::vector< delegate > dels_
Vector of delegates directly observing this notification source.
const std::string * getNotificationID() const
Returns notification ID (string pointer from Notification ID interned in sparta::StringManager)
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
void deregisterForThis(T *obj)
Deregisters a callback method that was registered with registerForThis.
~NotificationSource()
Destructor.
void postNotification(const NotificationDataT &data) const
Post with reference to data with parent as message origin.
void registerForThis(T *obj)
Registers a callback method to listen for the notification generated by this NotificationSource....
NotificationDataT data_type
Type of notification data generated by this instance.
NotificationSource(TreeNode *parent, const std::string &name, const std::string &group, TreeNode::group_idx_type group_idx, const std::string &desc, const std::string *notification_name_id)
NotificationSource.
NotificationDataT const const_data_type
Const qualified data type.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Accepts a sprintf-style format string like "%s_%i.json" and uses the arguments given to postNotificat...
void postNotification(Args... args) const
Formats the current format string (see setFormatString) with args and posts the resulting std::string...
Manages string internment for SPARTA. This allows strings to be compared by pointer once interned.
static StringManager & getStringManager()
Returns the StringManager singleton.
Temporary delegate for notificaiton invokation until the implementation is working....
Node in a composite tree representing a sparta Tree item.
std::string getLocation() const override final
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
static bool notificationCategoryMatch(const std::string *query_id, const std::string *node_id)
Checks if two notification categories match where one is an actual category.
void registerForNotification(T *obj, const std::string &name, bool ensure_possible=true)
Registers a callback method to listen for all notifications having the specified data type DataT and ...
TreeNode()=delete
Not default-constructable.
const ChildrenVector getChildren() const
Gets a vector of all children of this node in any group in the order in which they were added to this...
void addChild(TreeNode *child, bool inherit_phase=true)
Adds a TreeNode to this node as a child.
uint32_t group_idx_type
Index within a group.
void deregisterForNotification(T *obj, const std::string &name)
Removes at most one registration made with registerForNotification.
WeakPtr getWeakPtr()
Gets a weak pointer to this TreeNode. This weak pointer is guaranteed to expire when this TreeNode is...
static TreeNode * getVirtualGlobalNode()
Gets the virtual global node singleton. This node can have no parent and no children....
static constexpr group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
std::vector< delegate > DelegateVector
Vector of delegates representing a list of observers to notify.
const std::string & getName() const override
Gets the name of this node.
void setExpectedParent_(const TreeNode *parent)
Tracks a node as an expected parent without actually adding this node as a child. This is used almost...
std::weak_ptr< const TreeNode > ConstWeakPtr
Weak pointer to a const TreeNode. Acquire with getWeakPtr.
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo
std::string demangle(const std::string &name) noexcept
Demangles a C++ symbol.
Type for indicating that ANY notification source type should be included in a search performed by loc...