ACF $AcfVersion:0$
TReferenceMember.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
11#include <icomp/IComponent.h>
15
16
17namespace icomp
18{
19
20
33template <class Interface>
35 public TAttributeMember<CReferenceAttribute>,
36 protected CInterfaceManipBase
37{
38public:
41 typedef Interface InterfaceType;
42
44
45 void Init(const IComponent* ownerPtr, const IRealAttributeStaticInfo& staticInfo);
46
51 bool IsValid() const;
52
57 bool EnsureInitialized() const;
58
62 Interface* GetPtr() const;
63
67 Interface* operator->() const;
68
69protected:
71
72private:
73 const IComponent* m_definitionComponentPtr;
74
75 mutable IComponentSharedPtr m_componentPtr;
76 mutable std::atomic<Interface*> m_interfacePtr;
77 mutable std::atomic<bool> m_isInitialized;
78
79 mutable QRecursiveMutex m_mutex;
80};
81
82
83// public methods
84
85template <class Interface>
87 :m_definitionComponentPtr(NULL),
88 m_isInitialized(false),
89 m_interfacePtr(nullptr)
90{
91}
92
93
94template <class Interface>
96{
97 QMutexLocker lock(&m_mutex);
98
99 BaseClass::InitInternal(ownerPtr, staticInfo, &m_definitionComponentPtr);
100
101 // CRITICAL: We reset the initialization flag BEFORE clearing pointers.
102 // This ordering is REQUIRED for thread-safety:
103 //
104 // If another thread checks m_isInitialized without the lock and sees:
105 // - true: The pointers are still valid (not yet cleared), safe to use
106 // - false: Thread will acquire lock and re-initialize, finding cleared state
107 //
108 // If we cleared pointers first, another thread might see m_isInitialized==true
109 // but access nullptr pointers, causing a crash.
110 //
111 // The lock ensures no thread is in EnsureInitialized() during this operation.
112 m_isInitialized = false;
113 m_interfacePtr = nullptr;
114 m_componentPtr.reset();
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 const QByteArray& componentId = BaseClass::operator*();
135
136 QByteArray baseId;
137 QByteArray subId;
138 BaseClass2::SplitId(componentId, baseId, subId);
139
140 m_componentPtr = parentPtr->GetSubcomponent(baseId);
141 if (m_componentPtr != nullptr) {
142 m_interfacePtr = BaseClass2::ExtractInterface<Interface>(m_componentPtr.get(), subId);
143
144 m_isInitialized = true;
145 }
146 else {
147 qCritical("Component %s is defined, but definition component has no parent", BaseClass::operator*().constData());
148 }
149 }
150 }
151 }
152
153 return (m_interfacePtr != NULL);
154}
155
156
157template <class Interface>
159{
160 EnsureInitialized();
161
162 return m_interfacePtr;
163}
164
165
166template <class Interface>
168{
169 EnsureInitialized();
170
171 Q_ASSERT(m_interfacePtr != NULL);
172
173 return GetPtr();
174}
175
176
177// protected methods
178
179template <class Interface>
181: BaseClass(ptr),
182 m_definitionComponentPtr(ptr.m_definitionComponentPtr),
183 m_interfacePtr(nullptr),
184 m_isInitialized(false)
185{
186 // Thread-safe copy: acquire lock on source object before copying
187 QMutexLocker lock(&ptr.m_mutex);
188 m_componentPtr = ptr.m_componentPtr;
189 m_interfacePtr = ptr.m_interfacePtr.load();
190 m_isInitialized = ptr.m_isInitialized.load();
191}
192
193
194} // namespace icomp
195
196
197inline void operator*(const icomp::TReferenceMember<void>& /*ref*/)
198{
199}
200
201
202template <class Interface>
204{
205 return *ref.GetPtr();
206}
207
208
void operator*(const icomp::TReferenceMember< void > &)
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 referenced component object.
Interface * GetPtr() const
Direct cccess to internal pointer.
Interface * operator->() const
Access to internal pointer.
bool IsValid() const
Check if this reference can be resolved.
void Init(const IComponent *ownerPtr, const IRealAttributeStaticInfo &staticInfo)
bool EnsureInitialized() const
Ensure that initlization process is closed.
CInterfaceManipBase BaseClass2
TAttributeMember< CReferenceAttribute > BaseClass
#define NULL
Definition istd.h:74
Package with interfaces and class used for components concept.
std::shared_ptr< IComponent > IComponentSharedPtr
Definition IComponent.h:71