DLG4::VolumeBuilders
A fluent interface for Geant4 geometry definition.
Loading...
Searching...
No Matches
Classes | Public Member Functions | List of all members
Linkable< T > Class Template Reference

#include <Linkable.hh>

Classes

struct  false_template
 

Public Member Functions

 Linkable ()
 
 ~Linkable ()
 
 Linkable (const Linkable< T > &other)
 
 Linkable (Linkable< T > &other, std::true_type)
 
 Linkable (const T &other)
 
template<typename U = T>
std::enable_if_t<!std::is_pointer_v< U >, U * > operator-> () const
 
template<typename U = T>
std::enable_if_t< std::is_pointer_v< U >, std::remove_pointer_t< U > * > operator-> () const
 
template<typename U = T>
std::enable_if_t<!std::is_pointer_v< U >, U & > operator* () const
 
template<typename U = T>
std::enable_if_t< std::is_pointer_v< U >, std::remove_pointer_t< U > & > operator* () const
 
const Linkable< T > & operator= (const Linkable< T > &other) const
 
Linkableoperator= (const T &other) const
 
void LinkToRaw (T *ptr)
 
void Link (Linkable< T > &other)
 
void ShareLink (std::shared_ptr< T > other)
 
template<typename... Args, std::enable_if_t< !(std::conjunction_v< std::is_same< std::decay_t< Args >, Linkable< T > >... >), int > = 0>
void ConstructAndLink (Args &&... args)
 
 operator bool () const noexcept
 
T * get_mutable () const
 
const T * get () const
 
void make_persistent ()
 
 operator T* () const
 

Detailed Description

template<typename T>
class DLG4::Linkable< T >
* Created by Douglas S. Leonard on 6/10/25.  All rights Reserved
* See related files for license, if any is provided.
*
* A transitive view of another  Linkable<T> or, as a root link, an owning T copy or non-owning T* view.  Data access is value semantics, immutability control (of the links).
* Every link can be set only once, but once linked the view transitively controls the linked Linkable, including its link command, so it's possible
* to call Link more than once from a single Linkable but not to relink or to acquire more than one concrete resource.

* Links can be thought of as a view linking toward a single root (downlink) source. The root may be in an unlinked state,  or may
* have a non-owning or owning shared pointer to data.   Links to other links are always effectively non-owning.  While the data itself is internally linked via shared
* via shared pointer, the link stack itself becomes invalid if another link is deleted, making it unsafe to operate on at that point. It's better
* to think of links like raw pointers in this regard.  Multiple links can be made from other linkables to a single source or source link.  Every individual link can only only be set once.

* If the root itself is not linked, all objects on the tree will behave as not linked, because
* there is still no source, and any object in the tree can call link to link the root to another link
* or to a source.  Once the root is linked to a source, all objects in the tree are linked to a source and cannot be
* be relinked.  Other objects can be still be linked to linkables in the tree, and then having a source, will also be fully linked.

*
* Copy and assignment work on the contents, not the internal pointer.
* It provides value-like semantics even for heap/pointer objects, and
* with const Linkable, you can only Link  once, but it doesn't have to be in an initializer!
*
* Makes relinking more deliberate, even in ctor initializers.
*
* Const refers to pointer.  It does NOT protect the contents of the object.
* Use ex: Linkable<const int> to make CONTENTS const.
* This is consistent with shared pointer behavior, but note operator= here acts on contents,
*  and CAN modify them unless T itself is a const type.
*
* Gaurantees:
* -Will NEVER modify the shared_ptr itself without an explicit Link(..) call or SET_LINK parameter
* -Will never CREATE a shared_ptr that ties to an exisiting shared_ptr without the same.
*   because the copy ctor creates a new ptr from a deep copy.
* -No concern for accidentally re-initializing to something that can be changed elsewhere (bugs!).
* -copy ctor and assignment semantics both follow value semantics, behaving like a T
*   more than like a shred pointer.
*   Just use it like a T, EXCEPT when you explicitly link.
*
* Heap Object (pointers) Safety:
* For heap objects O you usually want a Linkable<O> NOT a Linkable<O*>
* The Linkable O is internally an O* and can be initialized from an O* but
* because it acts like an O, you cannot modify the stored pointer.
* Unless you re-link (impossible with const) you will always access the memory.
*
*   

Definition at line 133 of file Linkable.hh.

Constructor & Destructor Documentation

◆ Linkable() [1/4]

template<typename T >
Linkable ( )
inline

Default constructor.

Definition at line 143 of file Linkable.hh.

144 : ref_() {
145 }

◆ ~Linkable()

template<typename T >
~Linkable ( )
inline

Definition at line 148 of file Linkable.hh.

148 {
149 std::lock_guard<std::recursive_mutex> lock(s_link_mutex);
150 // remove ourselves from the backlinks of the downlink
151 // this prevents corrupt backlink propagation after we are deleted.
152 if (downlink_) {
153 auto &parent_backlinks = downlink_->backlinks_;
154 auto it = std::remove(parent_backlinks.begin(), parent_backlinks.end(), this);
155 if (it != parent_backlinks.end()) {
156 parent_backlinks.erase(it, parent_backlinks.end());
157 }
158 }
159 // remove downlinks from our backlinks
160 // Does this orphan chains?:
161 // If we have a ref, link to will error anyway
162 // If we don't have a ref, we just become the root.
163 // No harm. Nothing linked, nothing lost.
164 // But backlinks become detatched from each other, have different views.
165 // So relink to the first backlink, making it the root.
166 Linkable<T> *first_link = nullptr;
167 for (auto *child : backlinks_) {
168 if (child->downlink_ == this) {
169 if (bool is_first_link = false; !is_first_link) {
170 first_link = child;
171 child->downlink_ = nullptr;
172 } else {
173 child->downlink_ = first_link;
174 }
175 }
176 }
177 backlinks_.clear();
178 //if this matters, something is already very wrong. But it can help unmask that.
179 }

◆ Linkable() [2/4]

template<typename T >
Linkable ( const Linkable< T > &  other)
inline

Copy constructor does deep copy, not link This is safest and default.

Definition at line 183 of file Linkable.hh.

183 :
184 ref_(std::make_shared<T>(*other.ref_)) {
185 }

◆ Linkable() [3/4]

template<typename T >
Linkable ( Linkable< T > &  other,
std::true_type   
)
inline

The EXPLICIT linking copy ctor.

Definition at line 188 of file Linkable.hh.

188 {
189 ref_ = nullptr;
190 LinkTreeTo(other);
191 }

◆ Linkable() [4/4]

template<typename T >
Linkable ( const T &  other)
inlineexplicit

Copy constructor does deep copy, not link This is safest and default.

Definition at line 195 of file Linkable.hh.

196 : ref_(std::make_shared<T>(other)) {
197 }

Member Function Documentation

◆ ConstructAndLink()

template<typename T >
template<typename... Args, std::enable_if_t< !(std::conjunction_v< std::is_same< std::decay_t< Args >, Linkable< T > >... >), int > = 0>
void ConstructAndLink ( Args &&...  args)
inline

Link and own a T and link to it.

Definition at line 278 of file Linkable.hh.

278 {
279 auto data = std::make_shared<T>(std::forward<Args>(args)...);
280 LinkTreeTo(data);
281 }

◆ get()

template<typename T >
const T * get ( ) const
inline

Definition at line 291 of file Linkable.hh.

291 {
292 return ref_.get();
293 };

◆ get_mutable()

template<typename T >
T * get_mutable ( ) const
inline

Definition at line 287 of file Linkable.hh.

287 {
288 return ref_.get();
289 };

◆ Link()

template<typename T >
void Link ( Linkable< T > &  other)
inline

Reset Link to another Linakble:

Definition at line 254 of file Linkable.hh.

254 {
255 LinkTreeTo(other);
256 }

◆ LinkToRaw()

template<typename T >
void LinkToRaw ( T *  ptr)
inline

Link to an existing T object via pointer (non-owning)

Definition at line 243 of file Linkable.hh.

243 {
244 auto data = std::shared_ptr<T>(ptr, [](T *)
245 {
246 /* do nothing */
247 });
248 LinkTreeTo(data);
249 }

◆ make_persistent()

template<typename T >
void make_persistent ( )
inline

Definition at line 295 of file Linkable.hh.

295 {
296 std::lock_guard<std::mutex> lock(s_registry_mutex);
297 black_hole.push_back(ref_);
298 }
std::vector< std::shared_ptr< void > > black_hole
Definition Linkable.hh:69
std::mutex s_registry_mutex
Definition Linkable.hh:70

◆ operator bool()

template<typename T >
operator bool ( ) const
inlineexplicitnoexcept

Definition at line 283 of file Linkable.hh.

283 {
284 return static_cast<bool>(ref_);
285 }

◆ operator T*()

template<typename T >
operator T* ( ) const
inline

Definition at line 307 of file Linkable.hh.

307 {
308 if (!ref_) {
309 throw std::runtime_error("Attempt to convert empty Linkable to T*");
310 }
311 return ref_.get(); // Return a copy of the contained object
312 }

◆ operator*() [1/2]

template<typename T >
template<typename U = T>
std::enable_if_t<!std::is_pointer_v< U >, U & > operator* ( ) const
inline

operator* for non-pointer T: returns reference to T

Definition at line 219 of file Linkable.hh.

219 {
220 return *ref_;
221 }

◆ operator*() [2/2]

template<typename T >
template<typename U = T>
std::enable_if_t< std::is_pointer_v< U >, std::remove_pointer_t< U > & > operator* ( ) const
inline

operator* for pointer T: returns reference to the pointed-to object

Definition at line 226 of file Linkable.hh.

226 {
227 return **ref_;
228 }

◆ operator->() [1/2]

template<typename T >
template<typename U = T>
std::enable_if_t<!std::is_pointer_v< U >, U * > operator-> ( ) const
inline

-> foward For non-pointer T

Definition at line 205 of file Linkable.hh.

205 {
206 return ref_.get();
207 }

◆ operator->() [2/2]

template<typename T >
template<typename U = T>
std::enable_if_t< std::is_pointer_v< U >, std::remove_pointer_t< U > * > operator-> ( ) const
inline

operator-> forward For pointer T

Definition at line 212 of file Linkable.hh.

212 {
213 return *ref_;
214 }

◆ operator=() [1/2]

template<typename T >
const Linkable< T > & operator= ( const Linkable< T > &  other) const
inline

Allow CONTENT update (not reference) through assignment This is allowed even for const wrapper.

Definition at line 232 of file Linkable.hh.

232 {
233 *ref_ = *(other.ref_);
234 return *this; // return const ref to self.
235 }

◆ operator=() [2/2]

template<typename T >
Linkable & operator= ( const T &  other) const
inline

Definition at line 237 of file Linkable.hh.

237 {
238 *ref_ = other;
239 return *this;
240 }

◆ ShareLink()

template<typename T >
void ShareLink ( std::shared_ptr< T >  other)
inline

Definition at line 263 of file Linkable.hh.

263 {
264 if (!other) {
265 throw std::invalid_argument("\n Error in Linkable::Link: null pointer passed.\n");
266 }
267 auto data = other;
268 LinkTreeTo(data);
269 }

The documentation for this class was generated from the following file: