|
||||
File indexing completed on 2025-01-18 10:01:42
0001 0002 // Copyright 2020, Jefferson Science Associates, LLC. 0003 // Subject to the terms in the LICENSE file found in the top-level directory. 0004 0005 #pragma once 0006 0007 #include <string> 0008 #include <sstream> 0009 #include <set> 0010 #include <vector> 0011 #include <cassert> 0012 #include <typeinfo> 0013 0014 #include <JANA/Utils/JTypeInfo.h> 0015 #include <JANA/JLogger.h> 0016 #include <JANA/JException.h> 0017 0018 /// The JObject class is a base class for all data classes. 0019 /// (See JFactory for algorithm classes.) 0020 0021 /// The JOBJECT_PUBLIC macro is used to generate the correct className() overrides for a JObject subclass 0022 #define JOBJECT_PUBLIC(T) \ 0023 static const std::string static_className() {return #T;} \ 0024 const std::string className() const override {return #T;} \ 0025 0026 0027 struct JObjectMember { 0028 /// A plain-old data structure for describing one member of a JObject 0029 std::string name; // E.g. "E_tot" 0030 std::string type; // E.g. "float" 0031 std::string value; // E.g. "22.2e-2" 0032 std::string description; // E.g. "GeV" 0033 }; 0034 0035 class JObjectSummary { 0036 /// A container data structure for collecting information about JObjects. This is meant to be 0037 /// used by tools for debugging/visualizing/introspecting. The information for each member is 0038 /// collected by JObject::Summarize(). 0039 0040 std::vector<JObjectMember> m_fields; 0041 0042 public: 0043 /// get_fields() returns a copy of all JObjectMember information collected so far. 0044 std::vector<JObjectMember> get_fields() const { 0045 return m_fields; 0046 } 0047 0048 /// add() is used to insert a new row of JObjectMember data 0049 template <typename T> 0050 void add(const T& x, const char* name, const char* format, const char* description="") { 0051 0052 char buffer[256]; 0053 snprintf(buffer, 256, format, x); 0054 m_fields.push_back({name, JTypeInfo::builtin_typename<T>(), buffer, description}); 0055 } 0056 0057 /// add() is used to insert a new row of JObjectMember data 0058 void add(const JObjectMember &objectMember){ 0059 m_fields.push_back(objectMember); 0060 } 0061 }; 0062 0063 class JObject{ 0064 public: 0065 JObject() = default; 0066 virtual ~JObject() = default; 0067 0068 virtual const std::string className() const { 0069 /// className returns a string representation of the name of this class. 0070 /// This won't automatically do the right thing -- in each JObject subclass, 0071 /// the user either needs to use the JOBJECT_PUBLIC macro, 0072 /// or override this method while keeping the same method body. 0073 return JTypeInfo::demangle<decltype(*this)>(); 0074 } 0075 0076 // Associated objects 0077 inline void AddAssociatedObject(const JObject *obj); 0078 inline void AddAssociatedObjectAutoDelete(JObject *obj, bool auto_delete=true); 0079 inline void RemoveAssociatedObject(const JObject *obj); 0080 inline void ClearAssociatedObjects(void); 0081 inline bool IsAssociated(const JObject* locObject) const {return (associated.find(locObject) != associated.end());} 0082 0083 template<class T> const T* GetSingle() const; 0084 template<class T> std::vector<const T*> Get() const; 0085 0086 // JANA1 compatibility getters 0087 template<typename T> 0088 void GetSingle(const T* &ptrs, std::string classname="") const; 0089 0090 template<typename T> 0091 void GetT(std::vector<const T*> &ptrs) const; 0092 0093 template<typename T> 0094 void Get(std::vector<const T*> &ptrs, std::string classname="", int max_depth=1000000) const; 0095 0096 template<typename T> 0097 void GetAssociatedAncestors(std::set<const JObject*> &already_checked, 0098 int &max_depth, 0099 std::set<const T*> &objs_found, 0100 std::string classname="") const; 0101 0102 0103 0104 // Convert to strings with pretty formatting for printing 0105 virtual void Summarize(JObjectSummary& summary) const; 0106 0107 protected: 0108 std::set<const JObject*> associated; 0109 std::set<JObject*> auto_delete; 0110 }; 0111 0112 0113 //-------------------------- 0114 // AddAssociatedObject 0115 //-------------------------- 0116 void JObject::AddAssociatedObject(const JObject *obj) 0117 { 0118 /// Add a JObject to the list of associated objects 0119 assert(obj!=NULL); 0120 associated.insert(obj); 0121 } 0122 0123 //-------------------------- 0124 // AddAssociatedObjectAutoDelete 0125 //-------------------------- 0126 void JObject::AddAssociatedObjectAutoDelete(JObject *obj, bool auto_delete) 0127 { 0128 /// Add a JObject to the list of associated objects. If the auto_delete 0129 /// flag is true, then automatically delete it when this object is 0130 /// deleted. Otherwise, this behaves identically to the AddAssociatedObject 0131 /// method. 0132 /// 0133 /// Note that if the object is removed via RemoveAssociatedObject(...) 0134 /// then the object is NOT deleted. BUT, if the entire list of associated 0135 /// objects is cleared via ClearAssociatedObjects, then the object will 0136 /// be deleted. 0137 0138 AddAssociatedObject(obj); 0139 if(auto_delete) this->auto_delete.insert(obj); 0140 } 0141 0142 //-------------------------- 0143 // RemoveAssociatedObject 0144 //-------------------------- 0145 void JObject::RemoveAssociatedObject(const JObject *obj) 0146 { 0147 /// Remove the specified JObject from the list of associated 0148 /// objects. This will NOT delete the object even if the 0149 /// object was added with the AddAssociatedObjectAutoDelete(...) 0150 /// method with the auto_delete flag set. 0151 0152 auto iter = associated.find(obj); 0153 0154 if(iter!=associated.end()){ 0155 associated.erase(iter); 0156 } 0157 } 0158 0159 //-------------------------- 0160 // ClearAssociatedObjects 0161 //-------------------------- 0162 void JObject::ClearAssociatedObjects(void) 0163 { 0164 /// Remove all associated objects from the associated objects list. 0165 /// This will also delete any objects that were added via the 0166 /// AddAssociatedObjectAutoDelete(...) method with the auto_delete 0167 /// flag set. 0168 0169 // Clear pointers to associated objects 0170 associated.clear(); 0171 0172 // Delete objects in the auto_delete list 0173 for( auto p : auto_delete ) delete p; 0174 auto_delete.clear(); 0175 } 0176 0177 0178 template<class T> 0179 const T* JObject::GetSingle() const { 0180 /// This is a convenience method that can be used to get a pointer to the single associated object of type T. 0181 /// If no object is found, this will return nullptr. 0182 /// If multiple objects are found, this will throw a JException. 0183 0184 const T* last_found = nullptr; 0185 for (auto obj : associated) { 0186 auto t = dynamic_cast<const T*>(obj); 0187 if (t != nullptr) { 0188 if (last_found == nullptr) { 0189 last_found = t; 0190 } 0191 else { 0192 throw JException("JObject::GetSingle(): Multiple objects found."); 0193 } 0194 } 0195 } 0196 if (last_found == nullptr) { 0197 // If nothing found, attempt matching by strings. 0198 // Why? Because dl and RTTI aren't playing nicely together; 0199 // each plugin might assign a different typeid to the same class. 0200 std::string classname = JTypeInfo::demangle<T>(); 0201 for (auto obj : associated) { 0202 if (obj->className() == classname) { 0203 if (last_found == nullptr) { 0204 last_found = reinterpret_cast<const T*>(obj); 0205 } 0206 else { 0207 throw JException("JObject::GetSingle(): Multiple objects found."); 0208 } 0209 } 0210 } 0211 } 0212 return last_found; 0213 } 0214 0215 template<typename T> 0216 std::vector<const T*> JObject::Get() const { 0217 /// Returns a vector of pointers to all associated objects of type T. 0218 0219 std::vector<const T*> results; 0220 for (auto obj : associated) { 0221 const T* t = dynamic_cast<const T*>(obj); 0222 if (t != nullptr) { 0223 results.push_back(t); 0224 } 0225 } 0226 if (results.empty()) { 0227 // If nothing found, attempt matching by strings. 0228 // Why? Because dl and RTTI aren't playing nicely together; 0229 // each plugin might assign a different typeid to the same class. 0230 0231 std::string classname = JTypeInfo::demangle<T>(); 0232 for (auto obj : associated) { 0233 if (obj->className() == classname) { 0234 results.push_back(reinterpret_cast<const T*>(obj)); 0235 } 0236 } 0237 } 0238 return results; 0239 } 0240 0241 inline void JObject::Summarize(JObjectSummary& summary) const 0242 { 0243 /// A virtual method which allows the user to display the contents of 0244 /// a JObject in a formatted, structured way. This is optional, but recommended. 0245 0246 /// Fill in the JObjectSummary container with information for each 0247 /// member variable of the JObject using JObjectSummary::add(...). 0248 /// This accepts a reference to the variable itself, the variable name, 0249 /// a printf-style format string, and an optional description string which is 0250 /// good for communicating things like units. 0251 0252 /// For convenience, we provide a NAME_OF macro, which will turn the member 0253 /// variable name into a string, rather than having the user write it out manually. 0254 /// This is useful if you use automatic refactoring tools, which otherwise 0255 /// might allow the variable name and the stringified name to get out of sync. 0256 0257 summary.add((unsigned long) this, "JObject", "0x%08x"); 0258 } 0259 0260 0261 /// The following have been added purely for compatibility with JANA1, in order to make 0262 /// porting halld_recon more tractable. 0263 0264 template<class T> 0265 void JObject::GetSingle(const T* &t, std::string classname) const 0266 { 0267 /// This is a convenience method that can be used to get a pointer to the single 0268 /// associate object of type T. 0269 /// 0270 /// The objects are chosen by matching their class names 0271 /// (obtained via JObject::className()) either 0272 /// to the one provided in classname or to T::static_className() 0273 /// if classname is an empty string. 0274 /// 0275 /// If no object of the specified type is found, a NULL pointer is 0276 /// returned. 0277 0278 t = NULL; 0279 0280 if(classname=="")classname=T::static_className(); 0281 0282 //map<const JObject*, string>::const_iterator iter = associated.begin(); 0283 //for(; iter!=associated.end(); iter++){ 0284 for( auto obj : associated ){ 0285 if( classname == obj->className() ){ 0286 t = dynamic_cast<const T*>(obj); 0287 if(t!=NULL)return; 0288 } 0289 } 0290 } 0291 0292 template<typename T> 0293 void JObject::GetT(std::vector<const T*> &ptrs) const 0294 { 0295 /// Fill the given vector with pointers to the associated 0296 /// JObjects of the type on which the vector is based. This is 0297 /// similar to the Get() method except objects are selected 0298 /// by attempting a dynamic_cast to type const T*. This allows 0299 /// one to select a list of all objects who have a type T 0300 /// somewhere in their inheritance chain. 0301 /// 0302 /// A potential issue with this method is that the dynamic_cast 0303 /// does not always work correctly for objects created via a 0304 /// plugin when the cast occurs outside of the plugin or 0305 /// vice versa. 0306 /// 0307 /// The contents of ptrs are cleared upon entry. 0308 0309 ptrs.clear(); 0310 0311 //map<const JObject*, string>::const_iterator iter = associated.begin(); 0312 //for(; iter!=associated.end(); iter++){ 0313 for( auto obj : associated ){ 0314 const T *ptr = dynamic_cast<const T*>(obj); 0315 if(ptr != NULL)ptrs.push_back(ptr); 0316 } 0317 } 0318 0319 0320 template<typename T> 0321 void JObject::Get(std::vector<const T*> &ptrs, std::string classname, int max_depth) const 0322 { 0323 /// Fill the given vector with pointers to the associated objects of the 0324 /// type on which the vector is based. The objects are chosen by matching 0325 /// their class names (obtained via JObject::className()) either to the 0326 /// one provided in classname or to T::static_className() if classname is 0327 /// an empty string. Associations will be searched to a level of max_depth 0328 /// to find all objects of the requested type. By default, max_depth is 0329 /// set to a very large number so that all associations are found. To 0330 /// limit the search to only objects directly associated with this one, 0331 /// set max_depth to either "0" or "1". 0332 /// 0333 /// The contents of ptrs are cleared upon entry. 0334 0335 if(classname=="")classname=T::static_className(); 0336 0337 // Use the GetAssociatedAncestors method which may call itself 0338 // recursively to search all levels of association (at or 0339 // below this object. Objects for which this is an associated 0340 // object are not checked for). 0341 std::set<const JObject*> already_checked; 0342 std::set<const T*> objs_found; 0343 int my_max_depth = max_depth; 0344 GetAssociatedAncestors(already_checked, my_max_depth, objs_found, classname); 0345 0346 // Copy results into caller's container 0347 ptrs.clear(); 0348 ptrs.insert(ptrs.end(), objs_found.begin(), objs_found.end()); 0349 // set<const T*>::iterator it; 0350 // for(it=objs_found.begin(); it!=objs_found.end(); it++){ 0351 // ptrs.push_back(*it); 0352 // } 0353 } 0354 0355 template<typename T> 0356 void JObject::GetAssociatedAncestors(std::set<const JObject*> &already_checked, int &max_depth, std::set<const T*> &objs_found, std::string classname) const 0357 { 0358 /// Get associated objects of the specified type (either "T" or classname). 0359 /// Check also for associated objects of any associated objects 0360 /// to a level of max_depth associations. This method calls itself 0361 /// recursively so care is taken to only check the associated objects 0362 /// of each object encountered only once. 0363 /// 0364 /// The "already_checked" parameter should be passed in as an empty container 0365 /// that is used to keep track of which objects had their direct associations 0366 /// checked. "max_depth" indicates the maximum level of associations to check 0367 /// (n.b. both "0" and "1" means only check direct associations.) This must 0368 /// be passed as a reference to an existing int since it is modified in order 0369 /// to keep track of the current depth in the recursive calls. Set max_depth 0370 /// to a very high number (like 1000000) to check all associations. The 0371 /// "objs_found" container will contain the actual associated objects found. 0372 /// The objects are chosen by matching their class names (obtained via 0373 /// JObject::className()) either to the one provided in "classname" or to 0374 /// T::static_className() if classname is an empty string. 0375 0376 if(already_checked.find(this) == already_checked.end()) already_checked.insert(this); 0377 0378 if(classname=="")classname=T::static_className(); 0379 max_depth--; 0380 0381 //map<const JObject*, string>::const_iterator iter = associated.begin(); 0382 for( auto obj : associated ){ 0383 0384 // Add to list if appropriate 0385 if( classname == obj->className() ){ 0386 objs_found.insert( dynamic_cast<const T*>(obj) ); 0387 } 0388 0389 // Check this object's associated objects if appropriate 0390 if(max_depth<=0) continue; 0391 if(already_checked.find(obj) != already_checked.end()) continue; 0392 already_checked.insert(obj); 0393 obj->GetAssociatedAncestors(already_checked, max_depth, objs_found, classname); 0394 } 0395 0396 max_depth++; 0397 } 0398 0399
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |