1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkObjectStore_h
19 #define itkObjectStore_h
20 
21 #include "itkObjectFactory.h"
22 #include "itkObject.h"
23 #include "itkIntTypes.h"
24 #include <vector>
25 
26 namespace itk
27 {
28 /** \class ObjectStore
29  * \brief A specialized memory management object for allocating and destroying
30  * contiguous blocks of objects.
31  *
32  * ObjectStore implements a dynamically sizeable free memory store, from which
33  * instantiated objects can be borrowed and returned without always invoking
34  * calls to new/delete.  This type of memory management is useful in situations
35  * where calls to new/delete may be expensive, such as a multithreaded
36  * environment to avoid the heap contention problem.
37  *
38  * ObjectStore is designed to grow dynamically.  Shrinking is a more difficult
39  * problem and is only done if it will not invalidate any pointers that have
40  * been "lent" to a calling application.
41  *
42  * This implementation uses a very simple, list-based scheme to manage
43  * pointers that have been borrowed and returned.  Memory overhead incurred is
44  * one pointer per object allocated.  Because of this overhead, ObjectStore is
45  * not efficient for use with small objects such as native types.
46  *
47  * Important notes on thread-safety: This object is thread-safe in the same
48  * sense that STL defines thread-safety: simultaneous operations on distinct
49  * containers are safe.  It is the user's responsibility to apply appropriate
50  * mutex locks if the same container is used across multiple threads. One (or
51  * more) ObjectStore's can be safely be created for each thread -- and may even
52  * be more efficient in terms of memory use than sharing a single ObjectStore
53  * across threads. Calls to \em new and \em delete have been placed in
54  * critical sections in case a compiler's implementation of new/delete is not
55  * thread-safe.
56  *
57  * \warning  For efficiency reasons, the ObjectStore does not guard against the
58  * same pointer being Returned() more than once. Doing this could result in
59  * serious problems.
60  * \ingroup ITKCommon
61  */
62 template< typename TObjectType >
63 class ITK_TEMPLATE_EXPORT ObjectStore:public Object
64 {
65 public:
66   ITK_DISALLOW_COPY_AND_ASSIGN(ObjectStore);
67 
68   /** Standard type alias. */
69   using Self = ObjectStore;
70   using Superclass = Object;
71   using Pointer = SmartPointer< Self >;
72   using ConstPointer = SmartPointer< const Self >;
73 
74   /** Method for creation through the object factory. */
75   itkNewMacro(Self);
76 
77   /** Run-time type information (and related methods). */
78   itkTypeMacro(ObjectStore, Object);
79 
80   /** Type of the objects in storage. */
81   using ObjectType = TObjectType;
82 
83   /** Type of list for storing pointers to free memory. */
84   using FreeListType = std::vector< ObjectType * >;
85 
86   /** Type of memory allocation strategy */
87   typedef enum { LINEAR_GROWTH = 0, EXPONENTIAL_GROWTH = 1 } GrowthStrategyType;
88 
89   /** Borrow a pointer to an object from the memory store. */
90   ObjectType * Borrow();
91 
92   /** Return a pointer to the memory store for reuse. WARNING: The ObjectStore
93    *  assumes a pointer is returned exactly once after each time it has been
94    *  borrowed. */
95   void Return(ObjectType *p);
96 
97   /** Returns the size of the container.  This is not the number of objects
98    *  available, but the total number of objects allocated. */
99   itkGetConstMacro(Size, SizeValueType);
100 
101   /** Ensures that there are at least n elements allocated in the storage
102    *  container.  Will not shrink the container, but may enlarge the
103    *   container. */
104   void Reserve(SizeValueType n);
105 
106   /** Attempts to free memory that is not in use and shrink the size of the
107    *  container.  Not guaranteed to do anything. */
108   void Squeeze();
109 
110   /** Frees all memory in the container */
111   void Clear();
112 
113   /** Set/Get the linear growth size */
114   itkSetMacro(LinearGrowthSize, SizeValueType);
115   itkGetConstMacro(LinearGrowthSize, SizeValueType);
116 
117   /** Set/Get the growth strategy. */
118   itkSetMacro(GrowthStrategy, GrowthStrategyType);
119   itkGetConstMacro(GrowthStrategy, GrowthStrategyType);
120 
121   /** Set growth strategy to exponential */
SetGrowthStrategyToExponential()122   void SetGrowthStrategyToExponential()
123   { this->SetGrowthStrategy(EXPONENTIAL_GROWTH); }
124 
125   /** Set growth strategy to linear */
SetGrowthStrategyToLinear()126   void SetGrowthStrategyToLinear()
127   { this->SetGrowthStrategy(LINEAR_GROWTH); }
128 
129 protected:
130   ObjectStore();
131   ~ObjectStore() override;
132   void PrintSelf(std::ostream & os, Indent indent) const override;
133 
134   /** Returns a new size to grow. */
135   SizeValueType GetGrowthSize();
136 
137   struct MemoryBlock {
MemoryBlockMemoryBlock138     MemoryBlock(): Begin(0) {}
139 
MemoryBlockMemoryBlock140     MemoryBlock(SizeValueType n):Size(n)
141     { Begin = new ObjectType[n];  }
142 
143     ~MemoryBlock()  = default;   // Purposely does *not* free memory
144 
DeleteMemoryBlock145     void Delete()
146     {
147       delete[] Begin;
148     }
149 
150     ObjectType *Begin;
151     SizeValueType Size{0};
152   };
153 
154 private:
155   GrowthStrategyType m_GrowthStrategy;
156 
157   SizeValueType m_Size;
158   SizeValueType m_LinearGrowthSize;
159 
160   /** Pointers to objects available for borrowing. */
161   FreeListType m_FreeList;
162 
163   /** A list of MemoryBlocks that have been allocated. */
164   std::vector< MemoryBlock > m_Store;
165 };
166 } // end namespace itk
167 
168 #ifndef ITK_MANUAL_INSTANTIATION
169 #include "itkObjectStore.hxx"
170 #endif
171 
172 #endif
173