VR-Engage  2.2
Loading...
Searching...
No Matches
attribute.h
Go to the documentation of this file.
1/******************************************************************************
2 ** Copyright (c) 2025 MAK Technologies
3 ** All rights reserved.
4 ******************************************************************************/
5
6#pragma once
7
8//! \file attribute.h
9//! \brief Provides attribute handling system for hierarchical data storage and manipulation
10
11#include "vreUtil/export.h"
12#include "vreUtil/logger.h"
16
17#include <tbb/spin_mutex.h>
18
19#include <list>
20#include <map>
21#include <chrono>
22
23namespace makVre
24{
25
26//! \brief Core attribute class for shared data storage
27//!
28//! The DtAttribute class provides a flexible system for storing data to be shared
29//! between various app systems and components. It supports type-safe access and
30//! thread-safe change notifications. Attributes are organized in a heirarchical
31//! tree structure. Attribute are identified by names, which must be unique within
32//! each node.
34{
35public:
36 //! \brief Returns a reference to the root attribute
37 //!
38 //! \return A reference to the root attribute handle
40
41public:
42 //! \brief Virtual destructor
43 virtual ~DtAttribute();
44
45 //! \brief Returns the handle for this attribute
46 //!
47 //! \return A handle to this attribute
49
50 //! \brief Returns the const handle for this attribute
51 //!
52 //! \return A const handle to this attribute
54
55 //! \brief Conversion operator to DtAttributeHandle
57
58 //! \brief Conversion operator to const DtAttributeHandle
59 operator const DtAttributeHandle() const;
60
61 //! \brief Returns the name associated with this attribute
62 //!
63 //! \return The name of this attribute
64 virtual const std::string& name() const;
65
66 //! \brief Returns the full path of this attribute in the hierarchy
67 //!
68 //! \return The full path string in dot notation
69 virtual std::string path() const;
70
71 //! \brief Returns the type of this attribute
72 //!
73 //! \return The type name as a string
74 const std::string& type() const;
75
76 //! \brief Checks if the attribute is of the specified type
77 //!
78 //! \return true if the attribute is of type T, false otherwise
79 template <typename T>
80 bool isType() const;
81
82 //! \brief Checks if the attribute is of the specified type by name
83 //!
84 //! \param type The type name to check against
85 //! \return true if the attribute is of the specified type, false otherwise
86 bool isType(const std::string& type) const;
87
88 //! \brief Checks if the attribute value is undefined
89 //!
90 //! \return true if the attribute has no defined value, false otherwise
91 bool isSet() const;
92
93 //! \brief Gets the value of the attribute
94 //!
95 //! \return The value of the attribute of type T
96 //! \note Throws an assertion if the attribute is of a different type
97 template <typename T>
98 const T& get() const;
99
100 //! \brief Gets the value of the attribute or a default value if undefined
101 //!
102 //! \param orValue The default value to return if the attribute is undefined
103 //! \return The attribute value or the default value
104 template <typename T>
105 T getOr(T orValue) const;
106
107 //! \brief Sets the value of the attribute
108 //!
109 //! If the new value differs from existing, change callbacks will be invoked.
110 //!
111 //! \param value The new value to set
112 //! \return true if the new value differs from existing
113 template <typename T>
114 bool set(const T& value);
115
116 // template <typename T>
117 // bool set(T&& value);//TODO
118
119 //! \brief Sets the value of the attribute only if it is currently undefined
120 //!
121 //! \param defaultValue The default value to set if the attribute is undefined
122 //! \return true if the value was set, false if the attribute already had a value
123 template <typename T>
124 bool setIfNot(const T& defaultValue);
125
126 template <typename T>
127 void modifyFast(std::function<bool(T& value)> modifyFunc);
128
129 template <typename T>
130 bool modify(std::function<void(T& value)> modifyFunc);
131
132 //! \brief Gets the value of a child attribute
133 //!
134 //! \param attribute The name of the child attribute
135 //! \return The value of the child attribute
136 template <typename T>
137 const T& getAttribute(const std::string& attribute) const;
138
139 //! \brief Gets the value of a child attribute or a default value if undefined
140 //!
141 //! \param attribute The name of the child attribute
142 //! \param orValue The default value to return if the attribute is undefined
143 //! \return The child attribute value or the default value
144 template <typename T>
145 T getAttributeOr(const std::string& attribute, T orValue) const;
146
147 //! \brief Sets the value of a child attribute
148 //!
149 //! If the new value differs from existing, change callbacks will be invoked.
150 //!
151 //! \param attribute The name of the child attribute
152 //! \param newValue The new value to set
153 //! \return true if the value changed
154 template <typename T>
155 bool setAttribute(const std::string& attribute, const T& newValue);
156
157 //! \brief Gets string representation of the attribute value
158 //!
159 //! \return String representation of the attribute value
160 std::string getAsString() const;
161
162 //! \brief Sets the attribute value from a string representation
163 //!
164 //! If the new value differs from existing, change callbacks will be invoked.
165 //!
166 //! \param newValue String representation of the new value
167 //! \return true if the value changed
168 bool setFromString(const std::string& newValue);
169
170 //! \brief Gets the previous value of the attribute before the last change
171 //!
172 //! \return The previous value of the attribute
173 template <typename T>
174 const T& previousValue() const;
175
176 //! \brief Unsets the attribute value
177 //!
178 //! Value is returned to an undefined, typeless state
179 //!
180 //! \return true if the attribute was unset, false otherwise
181 bool unset();
182
183 //! \brief Unsets (clears) a child attribute value
184 //!
185 //! Value is returned to an undefined, typeless state
186 //!
187 //! \param name The name of the child attribute to unset
188 //! \return true if the child attribute was unset, false otherwise
189 bool unset(const std::string& name);
190
191 //! \brief Unsets this attribute and all child attributes, recursively
192 //!
193 //! \return true if all attributes were unset successfully
195
196 //! \brief Set whether this attribute exists w/o handles assigned
197 //!
198 //! A persistent attribute will continue to exist in the attribute tree
199 //! for the lifetime of the application. A non-persistent attribute will
200 //! be deleted as soon as no handles are assigned to it. The default
201 //! condition for attributes is persistent.
202 //!
203 //! \param persistent Set true for persistent, false for non-persistent
204 void setPersistence(bool persistent);
205
206 //! \brief Sets the persistence of this attribute and all child attributes
207 //!
208 //! \ref setPersistence
209 //!
210 //! \param persistent Set true for persistent, false for non-persistent
211 void setPersistenceRecursive(bool persistent);
212
213 //! \brief Check the persistence state of this attribute
214 //!
215 //! \ref setPersistence
216 //!
217 //! \return true if attribute is persitent, false if not
218 bool isPersistent() const;
219
220 //! \brief Checks if a child attribute exists
221 //!
222 //! \return true if the child attribute exists, false otherwise
223 bool hasAttribute(const std::string& name) const;
224
225 bool contains(const DtAttributeHandle& attr) const;
226
227 bool containedBy(const DtAttributeHandle& attr) const;
228
229 //! \brief Gets a handle to a child attribute
230 //!
231 //! \param name The name of the child attribute. Name may be
232 //! a path to child subattributes in format
233 //! "ChildName.GrandChild.GreatGrandChild"
234 //! \return A handle to the child attribute
235 DtAttributeHandle attribute(const std::string& name);
236
237 //! \brief Const version of \ref attribute(const std::string&)
238 const DtAttributeHandle attribute(const std::string& name) const;
239
240 //! \brief Gets a handle to the parent attribute
241 //!
242 //! \return A handle to the parent attribute
244
245 //! \brief Gets a const handle to the parent attribute
246 //!
247 //! \return A const handle to the parent attribute
249
250 //! \brief Gets a handle to the first child attribute
251 //!
252 //! \return A handle to the first child attribute
254
255 //! \brief Gets a const handle to the first child attribute
256 //!
257 //! \return A const handle to the first child attribute
259
260 //! \brief Gets a handle to the next sibling attribute
261 //!
262 //! \return A handle to the next sibling attribute
264
265 //! \brief Gets a const handle to the next sibling attribute
266 //!
267 //! \return A const handle to the next sibling attribute
268 const DtAttributeHandle next() const;
269
270 //! \brief Gets a handle to the next sibling attribute, looping back to the first if at the end
271 //!
272 //! \return A handle to the next sibling attribute
274
275 //! \brief Gets a const handle to the next sibling attribute, looping back to the first if at the end
276 //!
277 //! \return A const handle to the next sibling attribute
279
280 void forEach(std::function<void(DtAttributeHandle)> forEachFun);
281
282 void forEach(std::function<void(const DtAttributeHandle)> forEachFun) const;
283
284 //! \brief Checks if this attribute is the root attribute
285 //!
286 //! \return true if this is the root attribute, false otherwise
287 bool isRoot() const;
288
289 //! \brief Gets the raw data pointer
290 //!
291 //! \return The raw data pointer
292 const void* raw() const;
293
294 //! \brief Locks the attribute with a key
295 //!
296 //! \param key The key to use for locking
297 //! \return true if the attribute was locked, false if it was already locked
298 bool lock(unsigned int key);
299
300 //! \brief Unlocks the attribute with a key
301 //!
302 //! \param key The key used for locking
303 //! \return true if the attribute was unlocked, false if the key was incorrect
304 bool unlock(unsigned int key);
305
306 //! \brief Checks if the attribute is locked
307 //!
308 //! \return true if the attribute is locked, false otherwise
309 bool locked() const;
310
311 //! \brief Adds a change callback for this attribute
312 //!
313 //! \param callback The callback to add
315
316 //! \brief Removes a change callback from this attribute
317 //!
318 //! \param callback The callback to remove
320
322
323 //! \brief Recursively dumps the attribute hierarchy to a table
324 //!
325 //! \param depth The current depth in the hierarchy
326 //! \return A table representation of the attribute hierarchy
327 using DumpItem = std::pair<DtAttributeHandle, std::list<std::string>>;
328 using DumpTable = std::list<DumpItem>;
329 void recursiveDumpToTable(DumpTable& output, int depth = 0) const;
330
331 //! \brief Statistics structure for tracking attribute usage
332 struct Stats
333 {
334 //! \brief Constructor initializing all counters to zero
336 : myLookups(0)
337 , myCreates(0)
338 , mySets(0)
339 , myChanges(0)
340 , myGets(0)
341 , myGetsUndefined(0)
342 {
343 }
344
345 //! \brief Time when the attribute was created
346 std::chrono::time_point<std::chrono::high_resolution_clock> myCreateTime;
347
348 //! \brief Number of attribute lookups
349 unsigned int myLookups;
350
351 //! \brief Number of attribute creations
352 unsigned int myCreates;
353
354 //! \brief Number of attribute value sets
355 unsigned int mySets;
356
357 //! \brief Number of attribute value changes
358 unsigned int myChanges;
359
360 //! \brief Number of attribute value gets
361 unsigned int myGets;
362
363 //! \brief Number of attribute value gets when undefined
364 unsigned int myGetsUndefined;
365 };
366
367 //! \brief Gets the attribute statistics
368 //!
369 //! \return The attribute statistics
370 const Stats& stats() const { return myStats; }
371
381 static std::pair<DtAttributeHandle, Trace> QueuedTrace();
382 static void CancelQueuedTrace();
383
384protected:
385 friend class DtAttributeHandle;
386
387 //! \brief Shared pointer type for attributes
388 using Ptr = std::shared_ptr<DtAttribute>;
389
390 //! \brief Weak pointer type for attributes
391 using Ref = std::weak_ptr<DtAttribute>;
392
393 //! \brief Map type for storing child attributes
394 using Map = std::map<std::string, std::pair<Ptr, Ref>>;
395 using DataPtr = std::shared_ptr<DtAttributeData>;
396 using Mutex = tbb::spin_mutex;
397
398 using CallbackList = std::list<const DtAttributeCallbackBase*>;
400 {
402 : valueChanged(false)
403 {
404 }
405
408 };
409 using CallbackThreadMap = std::map<unsigned int, CallbacksForThread>;
410
411 static Ptr create(const std::string& name, Ptr parent);
412
413 //! \brief Default constructor
415
416 //! \brief Constructor with name and parent
417 //!
418 //! \param name The name of the attribute
419 //! \param parent The parent attribute
420 DtAttribute(const std::string& name, Ptr parent);
421
422 //! \brief Gets a shared pointer to this attribute
423 //!
424 //! \return A shared pointer to this attribute
425 Ptr self() const;
426
427
428 void forEach(std::function<void(Ptr)> forEachFun);
429
430 void forEach(std::function<void(const Ptr)> forEachFun) const;
431
432 //! \brief Recursive search for child attribute at path, relative to this
433 //!
434 //! Recursive child names in path are delimited by '.', e.g. find("childName.grandChildName.greatGrandChildName")
435 //!
436 //! \param path Name or path of names of child attribute to find
437 //! \param orCreate If true, creates the attribute (and any intermediate path attributes) if not found; if false, returns null pointer when not found
438 //! \return Shared pointer to the found or created attribute, or null if not found and orCreate is false
439 Ptr find(const std::string& path, bool orCreate = false);
440
441 //! \brief Const version of \ref find(const std::string&, bool)
442 const Ptr find(const std::string& path, bool orCreate = false) const;
443
444 Ptr addAttribute(const std::string& name);
445 const Ptr addAttribute(const std::string& name) const;
446
447 //! \brief Creates data storage for the specified type
448 //!
449 //! \note This is used to initialize the attribute data
450 template <typename T>
451 void createData() const;
452
453 //! \brief Validates that the attribute data is of the specified type
454 template <typename T>
455 void validateData() const;
456
458
459 //! \brief Invokes all registered change callbacks
460 void invokeCallbacks(const Ptr& changed, unsigned int threadId);
461
463
464 //! \brief Checks if the attribute is locked
465 //!
466 //! \return true if locked and action should be prevented, false otherwise
467 bool lockCheck() const;
468
469 void doTrace() const;
470
471protected:
472 //! \brief The name of this attribute
473 std::string myName;
474
475 //! \brief The data stored in this attribute
477
478 //! \brief Flag indicating if the type was explicitly set
479 mutable bool myExplicitType;
480
481 //! \brief Mutex for thread synchronization
482 mutable Mutex myMutex;
483
484 //! \brief List of change callbacks
486
487 //! \brief Statistics for this attribute
488 mutable Stats myStats;
489
490 //! \brief Weak reference to self
491 mutable Ref mySelf;
492
493 //! \brief Shared pointer to parent
495
496 //! \brief Map of child attributes
498
499 //! \brief Iterator in parent's attribute map referring to this attribute
500 Map::iterator myItr;
501
502 //! \brief Lock key
503 unsigned int myLock;
504
505 static std::pair<Ref, Trace> TheQueuedTrace;
506 static std::pair<Ref, std::string> TheLastTrace;
507};
508
509//! \brief Type-specific attribute class
510//!
511//! This template class extends DtAttribute to provide type-specific
512//! access to attribute values. It ensures type safety when getting
513//! or setting values.
514template <typename T>
516{
517public:
518 //! \brief Verifies that the attribute is of the correct type
519 //!
520 //! \return true if the attribute is of type T, false otherwise
521 bool verifyType() const;
522
523 //! \brief Gets the value of the attribute
524 //!
525 //! \return The value of the attribute
526 const T& get() const;
527
528 //! \brief Gets the value of the attribute or a default value if undefined
529 //!
530 //! \param orValue The default value to return if the attribute is undefined
531 //! \return The attribute value or the default value
532 T getOr(T orValue) const;
533
534 //! \brief Sets the value of the attribute
535 //!
536 //! \param value The new value to set
537 //! \return true if the value was successfully set, false otherwise
538 bool set(const T& value);
539
540 // bool set(T&& value);//TODO
541
542 //! \brief Sets the value of the attribute only if it is currently undefined
543 //!
544 //! \param value The value to set if the attribute is undefined
545 //! \return true if the value was set, false if the attribute already had a value
546 bool setIfNot(const T& value);
547
548 void modifyFast(std::function<bool(T& value)> modifyFunc);
549
550 bool modify(std::function<void(T& value)> modifyFunc);
551
552 const T& previousValue() const;
553};
554
555} // namespace makVre
556
557#include "vreUtil/attribute_data.inl"
558#include "vreUtil/attribute.inl"
559#include "vreUtil/attributeHandle.inl"
560#include "vreUtil/attributeCallback.inl"
Defines data types for the attribute system in VREngage.
Provides a callback mechanism for attribute changes in the VREngage system.
Provides handle classes for safe access to attributes.
Definition attributeCallback.h:28
const T & get() const
Gets the value of the attribute.
void modifyFast(std::function< bool(T &value)> modifyFunc)
void invokeCallbacks(const Ptr &changed, unsigned int threadId)
Invokes all registered change callbacks.
const void * raw() const
Gets the raw data pointer.
void doTrace() const
bool containedBy(const DtAttributeHandle &attr) const
bool locked() const
Checks if the attribute is locked.
std::string myName
The name of this attribute.
Definition attribute.h:473
void forEach(std::function< void(const DtAttributeHandle)> forEachFun) const
std::string getAsString() const
Gets string representation of the attribute value.
DtAttributeHandle parent()
Gets a handle to the parent attribute.
DtAttributeHandle attribute(const std::string &name)
Gets a handle to a child attribute.
bool isRoot() const
Checks if this attribute is the root attribute.
const DtAttributeHandle first() const
Gets a const handle to the first child attribute.
bool setFromString(const std::string &newValue)
Sets the attribute value from a string representation.
static Ptr create(const std::string &name, Ptr parent)
Trace
Definition attribute.h:373
@ LOOKUP
Definition attribute.h:378
@ CHANGE
Definition attribute.h:376
@ OFF
Definition attribute.h:374
@ GET
Definition attribute.h:377
@ SET
Definition attribute.h:375
bool myExplicitType
Flag indicating if the type was explicitly set.
Definition attribute.h:479
const Stats & stats() const
Gets the attribute statistics.
Definition attribute.h:370
bool setIfNot(const T &defaultValue)
Sets the value of the attribute only if it is currently undefined.
DtAttributeHandle next()
Gets a handle to the next sibling attribute.
std::weak_ptr< DtAttribute > Ref
Weak pointer type for attributes.
Definition attribute.h:391
bool isType() const
Checks if the attribute is of the specified type.
const DtAttributeHandle attribute(const std::string &name) const
Const version of attribute(const std::string&)
bool contains(const DtAttributeHandle &attr) const
const DtAttributeHandle next_looping() const
Gets a const handle to the next sibling attribute, looping back to the first if at the end.
virtual const std::string & name() const
Returns the name associated with this attribute.
Ptr find(const std::string &path, bool orCreate=false)
Recursive search for child attribute at path, relative to this.
bool unset(const std::string &name)
Unsets (clears) a child attribute value.
DtAttribute()
Default constructor.
Ptr addAttribute(const std::string &name)
Map::iterator myItr
Iterator in parent's attribute map referring to this attribute.
Definition attribute.h:500
T getAttributeOr(const std::string &attribute, T orValue) const
Gets the value of a child attribute or a default value if undefined.
std::pair< DtAttributeHandle, std::list< std::string > > DumpItem
Recursively dumps the attribute hierarchy to a table.
Definition attribute.h:327
Ptr self() const
Gets a shared pointer to this attribute.
static void QueueTrace(DtAttributeHandle attribute, Trace trace)
static void CancelQueuedTrace()
void forEach(std::function< void(Ptr)> forEachFun)
virtual std::string path() const
Returns the full path of this attribute in the hierarchy.
Ref mySelf
Weak reference to self.
Definition attribute.h:491
bool setAttribute(const std::string &attribute, const T &newValue)
Sets the value of a child attribute.
const T & previousValue() const
Gets the previous value of the attribute before the last change.
bool unlock(unsigned int key)
Unlocks the attribute with a key.
void addCallback(const DtAttributeCallbackBase &callback)
Adds a change callback for this attribute.
Mutex myMutex
Mutex for thread synchronization.
Definition attribute.h:482
DtAttribute(const std::string &name, Ptr parent)
Constructor with name and parent.
tbb::spin_mutex Mutex
Definition attribute.h:396
CallbackThreadMap myChangeCallbacks
List of change callbacks.
Definition attribute.h:485
bool unset()
Unsets the attribute value.
DataPtr myData
The data stored in this attribute.
Definition attribute.h:476
bool modify(std::function< void(T &value)> modifyFunc)
bool lockCheck() const
Checks if the attribute is locked.
bool isSet() const
Checks if the attribute value is undefined.
std::map< unsigned int, CallbacksForThread > CallbackThreadMap
Definition attribute.h:409
static std::pair< Ref, std::string > TheLastTrace
Definition attribute.h:506
void checkPendingCallbacksRecursive()
std::map< std::string, std::pair< Ptr, Ref > > Map
Map type for storing child attributes.
Definition attribute.h:394
const Ptr find(const std::string &path, bool orCreate=false) const
Const version of find(const std::string&, bool)
Map myAttributes
Map of child attributes.
Definition attribute.h:497
std::shared_ptr< DtAttribute > Ptr
Shared pointer type for attributes.
Definition attribute.h:388
void createData() const
Creates data storage for the specified type.
bool unsetRecursive()
Unsets this attribute and all child attributes, recursively.
void validateData() const
Validates that the attribute data is of the specified type.
bool isType(const std::string &type) const
Checks if the attribute is of the specified type by name.
DtAttributeHandle first()
Gets a handle to the first child attribute.
Stats myStats
Statistics for this attribute.
Definition attribute.h:488
std::shared_ptr< DtAttributeData > DataPtr
Definition attribute.h:395
const DtAttributeHandle handle() const
Returns the const handle for this attribute.
void recursiveDumpToTable(DumpTable &output, int depth=0) const
bool hasAttribute(const std::string &name) const
Checks if a child attribute exists.
void setPersistence(bool persistent)
Set whether this attribute exists w/o handles assigned.
void forEach(std::function< void(const Ptr)> forEachFun) const
const T & getAttribute(const std::string &attribute) const
Gets the value of a child attribute.
friend class DtAttributeHandle
Definition attribute.h:385
const DtAttributeHandle next() const
Gets a const handle to the next sibling attribute.
std::list< DumpItem > DumpTable
Definition attribute.h:328
static DtAttributeHandle & Root()
Returns a reference to the root attribute.
DtAttributeHandle handle()
Returns the handle for this attribute.
bool isPersistent() const
Check the persistence state of this attribute.
bool lock(unsigned int key)
Locks the attribute with a key.
DtAttributeHandle next_looping()
Gets a handle to the next sibling attribute, looping back to the first if at the end.
virtual ~DtAttribute()
Virtual destructor.
static std::pair< Ref, Trace > TheQueuedTrace
Definition attribute.h:505
void setPersistenceRecursive(bool persistent)
Sets the persistence of this attribute and all child attributes.
void forEach(std::function< void(DtAttributeHandle)> forEachFun)
Ptr myParent
Shared pointer to parent.
Definition attribute.h:494
bool set(const T &value)
Sets the value of the attribute.
std::list< const DtAttributeCallbackBase * > CallbackList
Definition attribute.h:398
void removeCallback(const DtAttributeCallbackBase &callback)
Removes a change callback from this attribute.
unsigned int myLock
Lock key.
Definition attribute.h:503
const std::string & type() const
Returns the type of this attribute.
static std::pair< DtAttributeHandle, Trace > QueuedTrace()
T getOr(T orValue) const
Gets the value of the attribute or a default value if undefined.
const DtAttributeHandle parent() const
Gets a const handle to the parent attribute.
const Ptr addAttribute(const std::string &name) const
void checkPendingCallbacks()
Type-specific attribute class.
Definition attribute.h:516
bool verifyType() const
Verifies that the attribute is of the correct type.
bool set(const T &value)
Sets the value of the attribute.
void modifyFast(std::function< bool(T &value)> modifyFunc)
bool setIfNot(const T &value)
Sets the value of the attribute only if it is currently undefined.
const T & get() const
Gets the value of the attribute.
T getOr(T orValue) const
Gets the value of the attribute or a default value if undefined.
const T & previousValue() const
bool modify(std::function< void(T &value)> modifyFunc)
Defines export macros for the VREngage Utility library.
#define UTIL_DLL
Export/import macro for non-Windows platforms.
Definition export.h:39
Provides logging functionality with various severity levels and channels.
Include export definitions for this library.
Definition glsVreMessageUtil.h:49
CallbacksForThread()
Definition attribute.h:401
bool valueChanged
Definition attribute.h:406
CallbackList callbacks
Definition attribute.h:407
Statistics structure for tracking attribute usage.
Definition attribute.h:333
unsigned int myCreates
Number of attribute creations.
Definition attribute.h:352
unsigned int myGetsUndefined
Number of attribute value gets when undefined.
Definition attribute.h:364
unsigned int myGets
Number of attribute value gets.
Definition attribute.h:361
unsigned int mySets
Number of attribute value sets.
Definition attribute.h:355
Stats()
Constructor initializing all counters to zero.
Definition attribute.h:335
std::chrono::time_point< std::chrono::high_resolution_clock > myCreateTime
Time when the attribute was created.
Definition attribute.h:346
unsigned int myLookups
Number of attribute lookups.
Definition attribute.h:349
unsigned int myChanges
Number of attribute value changes.
Definition attribute.h:358