ACF $AcfVersion:0$
TMultiReferenceMember.h
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later OR GPL-2.0-or-later OR GPL-3.0-or-later OR LicenseRef-ACF-Commercial
2#pragma once
3
4// Standard includes
5#include <atomic>
6
7// Qt includes
8#include <QtCore/QMutex>
9
10// ACF includes
14
15
16namespace icomp
17{
18
19
33template <class Interface>
34class TMultiReferenceMember: public TMultiAttributeMember<CMultiReferenceAttribute>, public CInterfaceManipBase
35{
36public:
39 typedef Interface InterfaceType;
40
42
43 void Init(const IComponent* ownerPtr, const IRealAttributeStaticInfo& staticInfo);
44
49 bool IsValid() const;
50
55 bool EnsureInitialized() const;
56
61 Interface* operator[](int index) const;
62
63protected:
65
66private:
67 const IComponent* m_definitionComponentPtr;
68
69 struct Component
70 {
71 IComponentSharedPtr componentPtr;
72 Interface* interfacePtr = nullptr;
73 };
74
75
76 typedef QVector<Component> Components;
77 mutable Components m_components;
78
79 mutable std::atomic<bool> m_isInitialized;
80
81 mutable QRecursiveMutex m_mutex;
82};
83
84
85// public methods
86
87template <class Interface>
89 :m_definitionComponentPtr(NULL),
90 m_isInitialized(false)
91{
92}
93
94
95template <class Interface>
97{
98 QMutexLocker lock(&m_mutex);
99
100 BaseClass::InitInternal(ownerPtr, staticInfo, &m_definitionComponentPtr);
101
102 // CRITICAL: We reset the initialization flag BEFORE clearing data.
103 // This ordering is REQUIRED for thread-safety:
104 //
105 // If another thread checks m_isInitialized without the lock and sees:
106 // - true: The data is still valid (not yet cleared), safe to use
107 // - false: Thread will acquire lock and re-initialize, finding cleared state
108 //
109 // If we cleared data first, another thread might see m_isInitialized==true
110 // but access partially cleared or invalid data in m_components.
111 //
112 // The lock ensures no thread is in EnsureInitialized() during this operation.
113 m_isInitialized = false;
114 m_components.clear();
115}
116
117
118template <class Interface>
120{
121 return EnsureInitialized();
122}
123
124
125template <class Interface>
127{
128 if (!m_isInitialized){
129 QMutexLocker lock(&m_mutex);
130
131 if (!m_isInitialized && (m_definitionComponentPtr != NULL) && BaseClass::IsValid()) {
132 const ICompositeComponent* parentPtr = dynamic_cast<const ICompositeComponent*>(m_definitionComponentPtr->GetParentComponent());
133 if (parentPtr != NULL) {
134 int attributesCount = BaseClass::GetCount();
135
136 m_components.resize(attributesCount);
137
138 for (int i = 0; i < attributesCount; ++i) {
139 const QByteArray& componentId = BaseClass::operator[](i);
140
141 QByteArray baseId;
142 QByteArray subId;
143 BaseClass2::SplitId(componentId, baseId, subId);
144
145 IComponentSharedPtr componentPtr = parentPtr->GetSubcomponent(baseId);
146
147 m_components[i].componentPtr = componentPtr;
148 m_components[i].interfacePtr = BaseClass2::ExtractInterface<Interface>(componentPtr.get(), subId);
149 }
150
151 m_isInitialized = true;
152 }
153 else {
154 qCritical("Components are is defined, but definition component has no parent");
155 }
156 }
157 }
158
159 return m_isInitialized;
160}
161
162
163template <class Interface>
165{
166 Q_ASSERT(index >= 0);
167
168 if (EnsureInitialized()){
169 Q_ASSERT(index < int(m_components.size()));
170
171 return m_components[index].interfacePtr;
172 }
173
174 return NULL;
175}
176
177
178// protected methods
179
180template <class Interface>
182: BaseClass(ptr),
183 m_definitionComponentPtr(ptr.m_definitionComponentPtr),
184 m_isInitialized(false)
185{
186 // Thread-safe copy: acquire lock on source object before copying
187 QMutexLocker lock(&ptr.m_mutex);
188 m_components = ptr.m_components;
189 m_isInitialized = ptr.m_isInitialized.load();
190}
191
192
193} // namespace icomp
194
195
Main component interface.
Definition IComponent.h:32
Composite component interface.
virtual IComponentSharedPtr GetSubcomponent(const QByteArray &componentId) const =0
Get access to subcomponent using its ID.
Interface adding to attribute static info functionality existing only for real attributes.
Pointer to component attribute.
Pointer to list of referenced component objects.
bool IsValid() const
Check if this reference can be resolved.
TMultiAttributeMember< CMultiReferenceAttribute > BaseClass
void Init(const IComponent *ownerPtr, const IRealAttributeStaticInfo &staticInfo)
Interface * operator[](int index) const
Access to interface of component at specified index.
bool EnsureInitialized() const
Ensure that initlization process is closed.
#define NULL
Definition istd.h:74
Package with interfaces and class used for components concept.
std::shared_ptr< IComponent > IComponentSharedPtr
Definition IComponent.h:71