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