MRPT  2.0.1
internal_class_registry.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "rtti-precomp.h" // Precompiled headers
11 
12 #include <mrpt/rtti/CObject.h>
13 
14 #include <atomic>
15 #include <cstdarg>
16 #include <iostream>
17 #include <map>
18 #include <mutex>
19 
21 
22 using namespace mrpt::rtti;
23 
24 /*---------------------------------------------------------------
25  STATIC GLOBAL VARIABLES
26  ---------------------------------------------------------------*/
28 
29 // Creation on first call pattern:
31 {
32  static std::atomic<int> cnt(0);
33  return cnt;
34 }
35 
36 // Creation on first call pattern:
38 {
40  static queue_register_functions_t lst;
41  return lst;
42 }
43 
44 namespace mrpt::rtti
45 {
46 using TClassnameToRuntimeId = std::map<std::string, const TRuntimeClassId*>;
47 
48 /** A singleton with the central registry for CSerializable run-time classes:
49  * users do not use this class in any direct way.
50  * \note Class is thread-safe.
51  */
53 {
54  public:
55  /** The unique access point point to the singleton instance.
56  */
58  {
59  static CClassRegistry obj;
60  return obj;
61  }
62 
63  void Add(const std::string& className, const TRuntimeClassId& id)
64  {
65  m_being_modified = true;
66  {
67  std::unique_lock<std::mutex> lk(m_cs);
68 
69  // Sanity check: don't allow registering twice the same class name!
70  const auto it = m_ns_classes.find(className);
71  if (it != m_ns_classes.cend())
72  {
73  if (it->second != &id)
74  {
75  std::cerr << mrpt::format(
76  "[MRPT class registry] Warning: overwriting already "
77  "registered className=`%s` with different "
78  "`TRuntimeClassId`!\n",
79  className.c_str());
80  }
81  }
82  m_ns_classes[className] = &id;
83 
84  // Also register without NS (backwards compatible datasets):
85  m_no_ns_classes[stripNamespace(className)] = &id;
86  }
87  m_being_modified = false;
88  }
89 
91  const std::string& className, const bool allow_ignore_namespace)
92  {
93  // Optimization to avoid the costly lock() in virtually all situations:
94  bool has_to_unlock = false;
95  if (m_being_modified)
96  {
97  m_cs.lock();
98  has_to_unlock = true;
99  }
100  const TRuntimeClassId* ret = nullptr;
101  const auto itEntry = m_ns_classes.find(className);
102  if (itEntry != m_ns_classes.end())
103  {
104  // found:
105  ret = itEntry->second;
106  }
107  else if (allow_ignore_namespace)
108  {
109  // 2nd attempt: search for class name only:
110  const auto itEntry2 =
111  m_no_ns_classes.find(stripNamespace(className));
112  if (itEntry2 != m_no_ns_classes.end())
113  {
114  // found:
115  ret = itEntry2->second;
116  }
117  }
118  if (has_to_unlock) m_cs.unlock();
119  return ret;
120  }
121 
122  std::vector<const TRuntimeClassId*> getListOfAllRegisteredClasses()
123  {
124  std::unique_lock<std::mutex> lk(m_cs);
125 
126  std::vector<const TRuntimeClassId*> ret;
127  for (auto& registeredClasse : m_ns_classes)
128  ret.push_back(registeredClasse.second);
129  return ret;
130  }
131 
132  private:
133  static std::string stripNamespace(const std::string& n)
134  {
135  std::string ret = n;
136  const auto pos = ret.rfind("::");
137  if (pos != std::string::npos)
138  {
139  return ret.substr(pos + 2);
140  }
141  return ret;
142  }
143 
144  // This must be static since we can be called from C startup
145  // functions and it cannot be assured that classesKeeper will be
146  // initialized before other classes that call it...
148 
149  // The auxiliary copy of "m_ns_classes", w/o namespace prefixes:
151 
152  std::mutex m_cs;
153  std::atomic<bool> m_being_modified{false};
154 };
155 
156 } // namespace mrpt::rtti
157 
158 /** Register all pending classes - to be called just before de-serializing an
159  * object, for example.
160  */
162 {
163  if (!pending_class_registers_modified) return; // Quick return
164 
165  while (pending_class_registers_count() != 0)
166  {
167  TRegisterFunction ptrToPtr = nullptr;
168  pending_class_registers().get(ptrToPtr);
170 
171  // Call it:
172  if (ptrToPtr != nullptr)
173  {
174  (*ptrToPtr)();
175  }
176  }
178 }
179 
180 /*---------------------------------------------------------------
181  RegisterClass
182  ---------------------------------------------------------------*/
184 {
185  // Register it:
186  if (pNewClass && pNewClass->className)
187  {
189  std::string(pNewClass->className), *pNewClass);
190  }
191  else
192  {
193  fprintf(
194  stderr,
195  "[mrpt::rtti::registerClass] Warning: Invoked with a nullptr "
196  "classname (?).\n");
197  }
198 
199  // Automatically register all classes when the first one is registered.
201 }
202 
203 /** For internal use within mrpt sources, and only in exceptional cases
204  * (CMultiMetricMaps, CImage,...)
205  */
207  const char* customName, const TRuntimeClassId* pNewClass)
208 {
209  // Register it:
210  CClassRegistry::Instance().Add(customName, *pNewClass);
211 
212  // Automatically register all classes when the first one is registered.
214 }
215 
216 std::vector<const TRuntimeClassId*> mrpt::rtti::getAllRegisteredClasses()
217 {
219 }
220 
221 std::vector<const TRuntimeClassId*>
223  const TRuntimeClassId* parent_id)
224 {
225  std::vector<const TRuntimeClassId*> res;
226  const auto lst = mrpt::rtti::getAllRegisteredClasses();
227  for (const auto& c : lst)
228  {
229  if (c->derivedFrom(parent_id) && c != parent_id)
230  {
231  res.push_back(c);
232  }
233  }
234  return res;
235 }
236 
237 /*---------------------------------------------------------------
238  findRegisteredClass
239  ---------------------------------------------------------------*/
241  const std::string& className, const bool allow_ignore_namespace)
242 {
243  return CClassRegistry::Instance().Get(className, allow_ignore_namespace);
244 }
void registerAllPendingClasses()
Register all pending classes - to be called just before de-serializing an object, for example...
std::vector< const TRuntimeClassId * > getListOfAllRegisteredClasses()
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
std::vector< const TRuntimeClassId * > getAllRegisteredClassesChildrenOf(const TRuntimeClassId *parent_id)
Like getAllRegisteredClasses(), but filters the list to only include children clases of a given base ...
A structure that holds runtime class type information.
Definition: CObject.h:31
bool get(TRegisterFunction &ret)
Retrieve the next message in the queue, or nullptr if there is no message.
const TRuntimeClassId * Get(const std::string &className, const bool allow_ignore_namespace)
const char * className
Definition: CObject.h:34
static std::string stripNamespace(const std::string &n)
const TRuntimeClassId * findRegisteredClass(const std::string &className, const bool allow_ignore_namespace=true)
Return info about a given class by its name, or nullptr if the class is not registered.
void registerClassCustomName(const char *customName, const TRuntimeClassId *pNewClass)
Mostly for internal use within mrpt sources, to handle exceptional cases with multiple serialization ...
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:408
bool pending_class_registers_modified
Set to true if pending_class_registers() has been called after registerAllPendingClasses().
A singleton with the central registry for CSerializable run-time classes: users do not use this class...
std::map< std::string, const TRuntimeClassId * > TClassnameToRuntimeId
std::atomic< int > & pending_class_registers_count()
static CClassRegistry & Instance()
The unique access point point to the singleton instance.
void(*)() TRegisterFunction
void registerClass(const mrpt::rtti::TRuntimeClassId *pNewClass)
Register a class into the MRPT internal list of "CObject" descendents.
void Add(const std::string &className, const TRuntimeClassId &id)
std::vector< const mrpt::rtti::TRuntimeClassId * > getAllRegisteredClasses()
Returns a list with all the classes registered in the system through mrpt::rtti::registerClass.
queue_register_functions_t & pending_class_registers()



Page generated by Doxygen 1.8.14 for MRPT 2.0.1 Git: 0fef1a6d7 Fri Apr 3 23:00:21 2020 +0200 at vie abr 3 23:20:28 CEST 2020