Free Electron
Relay.h
Go to the documentation of this file.
1 /* Copyright (C) 2003-2021 Free Electron Organization
2  Any use of this software requires a license. If a valid license
3  was not distributed with this file, visit freeelectron.org. */
4 
5 /** @file */
6 
7 #ifndef __datatool_Relay_h__
8 #define __datatool_Relay_h__
9 
10 #define FE_RELAY_ASSERT TRUE //* for unmatched gets and sets
11 #define FE_RELAY_SAFE (FE_CODEGEN<=FE_DEBUG) //* query records safely
12 
13 #define FE_RELAY_STORE_DEBUG TRUE
14 #define FE_RELAY_DEBUG (FE_RELAY_STORE_DEBUG && FE_CODEGEN<FE_DEBUG)
15 
16 #include <sstream>
17 
18 namespace fe
19 {
20 namespace ext
21 {
22 
23 /**************************************************************************//**
24  @brief Default for BASE Relay template argument
25 
26  The use of this class as BASE in Relay indicates no inclusion.
27 *//***************************************************************************/
28 class FE_DL_EXPORT NoRelay
29 {
30  public:
31  enum
32  {
33  e_size=0
34  };
35 
36 static
37 const char* typeAt(U32 index) { return NULL; }
38 static
39 const char* nameAt(U32 index) { return NULL; }
40 
41  void initializeRecursively(Record&) {}
42 };
43 
44 /**************************************************************************//**
45  @brief Generic interface to the Relay template
46 *//***************************************************************************/
47 class FE_DL_EXPORT CoreRelay
48 {
49  public:
50 virtual ~CoreRelay(void) {}
51 virtual Record createRecord(void) =0;
52 virtual Record createRecordAndBind(void) =0;
53 virtual void bind(sp<Scope> spScope) =0;
54 };
55 
56 /**************************************************************************//**
57  @brief Counted wrapper for a CoreRelay
58 *//***************************************************************************/
59 class FE_DL_EXPORT CountedRelay: public Counted
60 {
61  public:
62  CountedRelay(CoreRelay* pRelay):
63 #if FE_COUNTED_TRACK
64  m_name("CountedRelay"),
65 #endif
66  m_pRelay(pRelay) {}
67 
68 virtual ~CountedRelay(void) { delete m_pRelay; }
69 
70  CoreRelay* relay(void) { return m_pRelay; }
71 
72 #if FE_COUNTED_TRACK
73 const String& name(void) const { return m_name; }
74  private:
75  String m_name;
76 #endif
77 
78  private:
79  CoreRelay* m_pRelay;
80 };
81 
82 
83 /**************************************************************************//**
84  @brief Collection of accessors for a Record
85 
86  A Relay is somewhat like a C++ class with only virtual data members.
87 
88  A Relay can inherit attributes from one other Relay through the
89  optional BASE template parameter.
90  Any number of Relays can be chained together in this manner.
91 
92  Usage is usually done by deriving from Relay into a simple subclass:
93  @code
94  namespace
95  {
96  static const char* gs_myAttributes[]=
97  {
98  "F32", "MyF32",
99  "I32", "MyI32"
100  };
101  }
102 
103  class MyRelay: public fe::Relay<2,MyRelay>
104  {
105  public:
106  enum
107  {
108  e_myF32,
109  e_myI32,
110  e_size
111  };
112  static
113  const char* layoutName(void) { return "base"; }
114  static
115  const char** attributes(void) { return gs_myAttributes; }
116  };
117  @endcode
118  Because of the anonymous namespace, this can be defined as such in a
119  shared header.
120 
121  The enumeration is purely for the convenience of users of your relay.
122  The enumeration's entries should be aligned with the rows in the
123  attribute array.
124 *//***************************************************************************/
125 template<int SIZE,typename TYPE,typename BASE=NoRelay>
126 class FE_DL_EXPORT Relay: public CoreRelay
127 {
128  public:
129  enum
130  {
131  e_totalSize=BASE::e_size+SIZE
132  };
133 
134  Relay(void) { FEASSERT(TYPE::e_size==BASE::e_size+SIZE); }
135 virtual ~Relay(void) {}
136 
137  /** @brief Bind all accessors to a given record
138 
139  A Relay can be rebound to different records,
140  but caution is neccessary if you switch to a
141  record in a different Scope. */
142  WeakRecord bind(WeakRecord record);
143 
144 virtual void bind(sp<Scope> spScope);
145 
146  /// @brief Check if the bound Record supports the attribute
147  BWORD check(U32 index) const;
148 
149  /// @brief Verify that the attribute is the given type
150  template<typename T>
151  BWORD checkType(U32 index) const;
152 
153  /// @brief Return a reference to the entry without checking
154  template<typename T>
155  T& access(U32 index) const;
156 
157  /** @brief Return the value of an entry, if supported
158 
159  Since there is no function argument that uses the
160  typename, you have to supply the template argument
161  explicitly. */
162  template<typename T>
163  T safeGet(U32 index) const;
164 
165  /** @brief Return the value of an entry, bypassing checks
166 
167  Since there is no function argument that uses the
168  typename, you have to supply the template argument
169  explicitly. */
170  template<typename T>
171  T get(U32 index) const;
172 
173  /// @brief Set the value of an entry, if supported
174  template<typename T>
175  void safeSet(U32 index,T value);
176 
177  /// @brief Set the value of an entry, bypassing checks
178  template<typename T>
179  void set(U32 index,T value);
180 
181  /** @brief Returns a string representation of the
182  entry's state */
183  String print(U32 index) const;
184 
185  /// @brief Logs all entries with state
186  void dump(void) const;
187 
188  /** @brief Create a new Record
189 
190  In addition to creating the record in the scope,
191  this calls any Relay-based initialization. */
192 virtual Record createRecord(void);
193 
194  /// @brief (convenience) Create and bind a new Record
195 virtual Record createRecordAndBind(void) { return bind(createRecord()); }
196 
197  /// @brief Returns the currently bound scope
198  sp<Scope> scope(void) { return m_hpScope; }
199 
200  /** @brief Returns a Layout with the attributes of
201  this relay */
202  sp<Layout> layout(void);
203 
204  /// @brief Returns the currently bound record
205  WeakRecord& record(void) { return m_record; }
206 
207  /** @brief Populate the given Layout with this Relay's
208  attributes */
209 static void populate(sp<Layout>& rspLayout);
210 
211  /// @brief Returns the attribute's type
212 static
213 const char* typeAt(U32 index);
214 
215  /// @brief Returns the attribute's name
216 static
217 const char* nameAt(U32 index);
218 
219  void initializeRecursively(Record& rRecord);
220 
221  protected:
222  /** @brief Construct and insert a Component
223  into the given slot
224 
225  The @em componentName is passed to Registry::create().
226  */
227  void createAndSetComponent(U32 index,String componentName);
228 
229  /** @brief Construct and insert a RecordGroup Component
230  into the given slot */
231  void createAndSetRecordGroup(U32 index);
232 
233  private:
234  void prepare(void);
235 
236  /** @brief Create or extend a layout
237 
238  The layout is populated by attributes of this relay. */
239  sp<Layout> createLayout(void);
240 
241 virtual void initialize(void) {}
242 
243  WeakRecord m_record;
244 mutable Accessor<I32> m_pAccessorArray[e_totalSize];
245  hp<Scope> m_hpScope;
246  hp<Layout> m_hpLayout;
247 
248 #if FE_RELAY_STORE_DEBUG
249  // just to look at in the debugger
250  String m_debugCache[e_totalSize];
251 #endif
252 };
253 
254 template<int SIZE,typename TYPE,typename BASE>
256 {
257  m_record=record;
258 #if FE_RELAY_SAFE
259  if(record.isValid())
260  {
261  sp<Scope> spScope=record.layout()->scope();
262  if(m_hpScope!=spScope && spScope.isValid())
263  {
264  if(m_hpScope.isValid())
265  feLog("Relay::bind Record changed scope\n");
266  m_hpScope=spScope;
267  prepare();
268  }
269  }
270 #else
271  if(!m_hpScope.isValid())
272  {
273  m_hpScope=record.layout()->scope();
274  prepare();
275  }
276 #endif
277  return m_record;
278 }
279 
280 template<int SIZE,typename TYPE,typename BASE>
281 inline void Relay<SIZE,TYPE,BASE>::bind(sp<Scope> spScope)
282 {
283  m_hpScope=spScope;
284  layout();
285 }
286 
287 template<int SIZE,typename TYPE,typename BASE>
288 inline BWORD Relay<SIZE,TYPE,BASE>::check(U32 index) const
289 {
290  return m_pAccessorArray[index].check(m_record);
291 }
292 
293 template<int SIZE,typename TYPE,typename BASE>
294 template<typename T>
295 inline BWORD Relay<SIZE,TYPE,BASE>::checkType(U32 index) const
296 {
297  sp<Attribute> spAttribute=m_hpScope->findAttribute(nameAt(index));
298  sp<BaseType> spBaseType=spAttribute->type();
299  if(spBaseType->typeinfo().ref() != typeid(T))
300  {
301  feLog("Relay<>::checkType %s is %s not %s\n",
302  nameAt(index),
303  spBaseType->typeinfo().ref().name(),
304  typeid(T).name());
305 #if FE_RELAY_ASSERT
306  FEASSERT(FALSE);
307 #endif
308  return FALSE;
309  }
310  return TRUE;
311 }
312 
313 template<int SIZE,typename TYPE,typename BASE>
314 template<typename T>
315 inline T& Relay<SIZE,TYPE,BASE>::access(U32 index) const
316 {
317 #if FE_RELAY_SAFE
318 #if FE_RELAY_DEBUG
319  const_cast< Relay<SIZE,TYPE,BASE>* >(this)
320  ->m_debugCache[index]=print(index);
321  checkType<T>(index);
322 #endif
323  return *(((Accessor<T>*)&m_pAccessorArray[index])
324  ->queryAttribute(m_record));
325 #else
326  return (*reinterpret_cast<Accessor<T>*>
327  (&m_pAccessorArray[index]))(m_record);
328 #endif
329 }
330 
331 template<int SIZE,typename TYPE,typename BASE>
332 template<typename T>
333 inline T Relay<SIZE,TYPE,BASE>::safeGet(U32 index) const
334 {
335 #if FE_RELAY_SAFE && FE_RELAY_DEBUG
336  checkType<T>(index);
337 #endif
338  T* pValue=NULL;
339  if(m_record.isValid() &&
340  (pValue=(reinterpret_cast<Accessor<T>*>
341  (&m_pAccessorArray[index]))->queryAttribute(m_record)))
342  {
343 #if FE_RELAY_DEBUG
344  const_cast< Relay<SIZE,TYPE,BASE>* >(this)->m_debugCache[index]=
345  print(index);
346 // feLog("Relay<>::safeGet(%d) %d \"%s\"\n",index,*pValue,
347 // m_debugCache[index].c_str());
348 // dump();
349 #endif
350  return *pValue;
351  }
352 
353  return T(0);
354 }
355 
356 template<int SIZE,typename TYPE,typename BASE>
357 template<typename T>
358 inline T Relay<SIZE,TYPE,BASE>::get(U32 index) const
359 {
360 #if FE_RELAY_SAFE
361 #if FE_RELAY_ASSERT
362  if(!check(index))
363  {
364  feLog("Relay<>::get(%s) failed\n",nameAt(index));
365  FEASSERT(FALSE);
366  }
367 #endif
368 
369  return safeGet<T>(index);
370 #else
371  return (*reinterpret_cast<Accessor<T>*>
372  (&m_pAccessorArray[index]))(m_record);
373 #endif
374 }
375 
376 template<int SIZE,typename TYPE,typename BASE>
377 template<typename T>
378 inline void Relay<SIZE,TYPE,BASE>::safeSet(U32 index,T value)
379 {
380 #if FE_RELAY_SAFE && FE_RELAY_DEBUG
381  checkType<T>(index);
382 #endif
383  T* pValue=NULL;
384  if(m_record.isValid() && (pValue=reinterpret_cast<T*>
385  (m_pAccessorArray[index].queryAttribute(m_record))))
386  {
387  *pValue=value;
388 #if FE_RELAY_DEBUG
389  m_debugCache[index]=print(index);
390 // feLog("Relay<>::safeSet(%d,%d) \"%s\"\n",index,value,
391 // m_debugCache[index].c_str());
392 // dump();
393 #endif
394  }
395 }
396 
397 template<int SIZE,typename TYPE,typename BASE>
398 template<typename T>
399 inline void Relay<SIZE,TYPE,BASE>::set(U32 index,T value)
400 {
401 #if FE_RELAY_SAFE
402 #if FE_RELAY_ASSERT
403  if(!check(index))
404  {
405  feLog("Relay<>::set(%s) failed\n",nameAt(index));
406  FEASSERT(FALSE);
407  }
408 #endif
409  safeSet(index,value);
410 #else
411  (*reinterpret_cast<Accessor<T>*>
412  (&m_pAccessorArray[index]))(m_record)=value;
413 #endif
414 }
415 
416 template<int SIZE,typename TYPE,typename BASE>
417 inline String Relay<SIZE,TYPE,BASE>::print(U32 index) const
418 {
419  if(!m_hpScope.isValid())
420  return "<no scope>";
421  if(!check(index))
422  return "<absent>";
423  void* pVoid=(void*)static_cast< Accessor<I32> >
424  (m_pAccessorArray[index]).queryAttribute(m_record);
425  sp<Attribute> spAttribute=m_hpScope->findAttribute(nameAt(index));
426  sp<BaseType> spBaseType=spAttribute->type();
427  sp<BaseType::Info> spInfo=spBaseType->getInfo();
428  return spInfo->print(pVoid);
429 }
430 
431 template<int SIZE,typename TYPE,typename BASE>
432 inline void Relay<SIZE,TYPE,BASE>::dump(void) const
433 {
434  for(U32 index=0;index<e_totalSize;index++)
435  feLog("%2d %-16s %-16s %s\n",index,typeAt(index),
436  nameAt(index),print(index).c_str());
437 }
438 
439 template<int SIZE,typename TYPE,typename BASE>
441 {
442  if(!m_hpScope.isValid())
443  feX("Relay::createRecord","no scope bound (%s)\n",TYPE::layoutName());
444  Record record=m_hpScope->createRecord(layout());
445 
446  TYPE relay;
447  relay.initializeRecursively(record);
448  return record;
449 }
450 
451 template<int SIZE,typename TYPE,typename BASE>
453 {
454  if(!m_hpScope.isValid())
455  return sp<Layout>(NULL);
456  if(!m_hpLayout.isValid())
457  m_hpLayout=createLayout();
458  return m_hpLayout;
459 }
460 
461 template<int SIZE,typename TYPE,typename BASE>
462 inline const char* Relay<SIZE,TYPE,BASE>::typeAt(U32 index)
463 {
464  if(index<BASE::e_size)
465  return BASE::typeAt(index);
466  else
467  return TYPE::attributes()[(index-BASE::e_size)*2];
468 }
469 
470 template<int SIZE,typename TYPE,typename BASE>
471 inline const char* Relay<SIZE,TYPE,BASE>::nameAt(U32 index)
472 {
473  if(index<BASE::e_size)
474  return BASE::nameAt(index);
475  else
476  return TYPE::attributes()[(index-BASE::e_size)*2+1];
477 }
478 
479 template<int SIZE,typename TYPE,typename BASE>
481 {
482  BASE base;
483  base.initializeRecursively(rRecord);
484  bind(rRecord);
485  initialize();
486 }
487 
488 template<int SIZE,typename TYPE,typename BASE>
490  String componentName)
491 {
492  sp<Component>& rspComponent=access< sp<Component> >(index);
493  rspComponent=scope()->registry()->create(componentName);
494  FEASSERT(rspComponent.isValid());
495  rspComponent->setName(nameAt(index));
496 }
497 
498 template<int SIZE,typename TYPE,typename BASE>
500 {
501  sp<RecordGroup>& rspRecordGroup=access< sp<RecordGroup> >(index);
502  rspRecordGroup=new RecordGroup();
503  FEASSERT(rspRecordGroup.isValid());
504 // rspRecordGroup->setName(nameAt(index));
505 }
506 
507 template<int SIZE,typename TYPE,typename BASE>
508 inline void Relay<SIZE,TYPE,BASE>::prepare(void)
509 {
510  if(!m_hpScope.isValid())
511  return;
512  for(U32 index=0;index<e_totalSize;index++)
513  m_pAccessorArray[index].initialize(m_hpScope,nameAt(index));
514 }
515 
516 template<int SIZE,typename TYPE,typename BASE>
518 {
519  if(!rspLayout.isValid())
520  feLog("Relay::populate layout not valid\n");
521 
522  sp<Scope> spScope=rspLayout->scope();
523  for(U32 index=0;index<e_totalSize;index++)
524  {
525 // feLog("support %s %s\n",typeAt(index),nameAt(index));
526  spScope->support(nameAt(index),typeAt(index));
527  }
528 
529  //* TODO should we check for repeats (psuedo virtual base)
530  for(U32 index=0;index<e_totalSize;index++)
531  rspLayout->populate(nameAt(index));
532 }
533 
534 template<int SIZE,typename TYPE,typename BASE>
536 {
537  if(!m_hpScope.isValid())
538  feLog("Relay::createLayout scope not valid\n");
539 
540  sp<Layout> spLayout=m_hpScope->declare(TYPE::layoutName());
541 
542  populate(spLayout);
543  prepare();
544  return spLayout;
545 }
546 
547 } /* namespace ext */
548 } /* namespace fe */
549 
550 #endif /* __datatool_Relay_h__ */
A heterogenous collection of records.
Definition: RecordGroup.h:35
Counted wrapper for a CoreRelay.
Definition: Relay.h:59
void set(U32 index, T value)
Set the value of an entry, bypassing checks.
Definition: Relay.h:399
Heap-based support for classes participating in fe::ptr <>
Definition: Counted.h:35
sp< Attribute > support(const String &mayHave, const String &ofType)
Add a support for a Attribute with name and type of name ofType.
Definition: Scope.cc:818
kernel
Definition: namespace.dox:3
Generic interface to the Relay template.
Definition: Relay.h:47
bool queryAttribute(const RecordSB &r, T *&data)
Return true if the attribute exists in record.
Definition: Accessor.h:574
const sp< LayoutSB > & layout(void) const
Return the Layout.
Definition: WeakRecordSB.h:251
hp< Registry > registry(void) const
Get the Registry that created this component.
Definition: Component.cc:219
BWORD check(U32 index) const
Check if the bound Record supports the attribute.
Definition: Relay.h:288
void createAndSetComponent(U32 index, String componentName)
Construct and insert a Component into the given slot.
Definition: Relay.h:489
WeakRecord bind(WeakRecord record)
Bind all accessors to a given record.
Definition: Relay.h:255
static const char * nameAt(U32 index)
Returns the attribute&#39;s name.
Definition: Relay.h:471
BWORD checkType(U32 index) const
Verify that the attribute is the given type.
Definition: Relay.h:295
static void populate(sp< Layout > &rspLayout)
Populate the given Layout with this Relay&#39;s attributes.
Definition: Relay.h:517
void safeSet(U32 index, T value)
Set the value of an entry, if supported.
Definition: Relay.h:378
sp< Component > create(const String &a_pattern, BWORD quiet=FALSE) const
Instantiate a Component of the given named implementation.
Definition: Registry.cc:628
T safeGet(U32 index) const
Return the value of an entry, if supported.
Definition: Relay.h:333
void dump(void) const
Logs all entries with state.
Definition: Relay.h:432
Safe handle for shared pointer.
Definition: Handled.h:61
virtual Record createRecord(void)
Create a new Record.
Definition: Relay.h:440
Automatically reference-counted string container.
Definition: String.h:128
sp< Layout > layout(void)
Returns a Layout with the attributes of this relay.
Definition: Relay.h:452
Reference to an instance of a Layout.
Definition: RecordSB.h:35
sp< Scope > scope(void)
Returns the currently bound scope.
Definition: Relay.h:198
static const char * typeAt(U32 index)
Returns the attribute&#39;s type.
Definition: Relay.h:462
bool isValid(void) const
Return true if the record points to the original valid state block.
Definition: WeakRecordSB.h:181
T get(U32 index) const
Return the value of an entry, bypassing checks.
Definition: Relay.h:358
String print(U32 index) const
Returns a string representation of the entry&#39;s state.
Definition: Relay.h:417
WeakRecord & record(void)
Returns the currently bound record.
Definition: Relay.h:205
Default for BASE Relay template argument.
Definition: Relay.h:28
T & access(U32 index) const
Return a reference to the entry without checking.
Definition: Relay.h:315
Collection of accessors for a Record.
Definition: Relay.h:126
sp< Layout > createLayout(void)
Create or extend a layout.
Definition: Relay.h:535
virtual Record createRecordAndBind(void)
(convenience) Create and bind a new Record
Definition: Relay.h:195
void createAndSetRecordGroup(U32 index)
Construct and insert a RecordGroup Component into the given slot.
Definition: Relay.h:499
Non-persistent reference to an instance of a Layout.
Definition: WeakRecordSB.h:17