2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
20 ==============================================================================
26 //==============================================================================
28 A smart-pointer that automatically creates and manages the lifetime of a
29 shared static instance of a class.
31 The SharedObjectType template type indicates the class to use for the shared
32 object - the only requirements on this class are that it must have a public
33 default constructor and destructor.
35 The SharedResourcePointer offers a pattern that differs from using a singleton or
36 static instance of an object, because it uses reference-counting to make sure that
37 the underlying shared object is automatically created/destroyed according to the
38 number of SharedResourcePointer objects that exist. When the last one is deleted,
39 the underlying object is also immediately destroyed. This allows you to use scoping
40 to manage the lifetime of a shared resource.
42 Note: The construction/deletion of the shared object must not involve any
43 code that makes recursive calls to a SharedResourcePointer, or you'll cause
48 // An example of a class that contains the shared data you want to use.
51 // There's no need to ever create an instance of this class directly yourself,
52 // but it does need a public constructor that does the initialisation.
55 sharedStuff = generateHeavyweightStuff();
58 Array<SomeKindOfData> sharedStuff;
65 // Multiple instances of the DataUserClass will all have the same
66 // shared common instance of MySharedData referenced by their sharedData
68 useSharedStuff (sharedData->sharedStuff);
71 // By keeping this pointer as a member variable, the shared resource
72 // is guaranteed to be available for as long as the DataUserClass object.
73 SharedResourcePointer<MySharedData> sharedData;
80 template <typename SharedObjectType
>
81 class SharedResourcePointer
84 /** Creates an instance of the shared object.
85 If other SharedResourcePointer objects for this type already exist, then
86 this one will simply point to the same shared object that they are already
87 using. Otherwise, if this is the first SharedResourcePointer to be created,
88 then a shared object will be created automatically.
90 SharedResourcePointer()
95 SharedResourcePointer (const SharedResourcePointer
&)
101 If no other SharedResourcePointer objects exist, this will also delete
102 the shared object to which it refers.
104 ~SharedResourcePointer()
106 auto& holder
= getSharedObjectHolder();
107 const SpinLock::ScopedLockType
sl (holder
.lock
);
109 if (--(holder
.refCount
) == 0)
110 holder
.sharedInstance
= nullptr;
113 /** Returns the shared object. */
114 operator SharedObjectType
*() const noexcept
{ return sharedObject
; }
116 /** Returns the shared object. */
117 SharedObjectType
& get() const noexcept
{ return *sharedObject
; }
119 /** Returns the object that this pointer references. */
120 SharedObjectType
& getObject() const noexcept
{ return *sharedObject
; }
122 /** Returns the shared object pointer. */
123 SharedObjectType
* operator->() const noexcept
{ return sharedObject
; }
125 /** Returns the number of SharedResourcePointers that are currently holding the shared object. */
126 int getReferenceCount() const noexcept
{ return getSharedObjectHolder().refCount
; }
129 struct SharedObjectHolder
132 std::unique_ptr
<SharedObjectType
> sharedInstance
;
136 static SharedObjectHolder
& getSharedObjectHolder() noexcept
138 static void* holder
[(sizeof (SharedObjectHolder
) + sizeof(void*) - 1) / sizeof(void*)] = { nullptr };
139 return *reinterpret_cast<SharedObjectHolder
*> (holder
);
142 SharedObjectType
* sharedObject
;
146 auto& holder
= getSharedObjectHolder();
147 const SpinLock::ScopedLockType
sl (holder
.lock
);
149 if (++(holder
.refCount
) == 1)
150 holder
.sharedInstance
.reset (new SharedObjectType());
152 sharedObject
= holder
.sharedInstance
.get();
155 // There's no need to assign to a SharedResourcePointer because every
156 // instance of the class is exactly the same!
157 SharedResourcePointer
& operator= (const SharedResourcePointer
&) = delete;
159 JUCE_LEAK_DETECTOR (SharedResourcePointer
)