1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkHeap.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkHeap.h"
16 #include "vtkCommonMiscModule.h" // For export macro
17 #include "vtkObjectFactory.h"
18 #include <cstddef>
19
20 vtkStandardNewMacro(vtkHeap);
21
vtkGetLongAlignment()22 static size_t vtkGetLongAlignment()
23 {
24 struct vtkTestAlignLong
25 {
26 char pad;
27 long x;
28 };
29
30 return offsetof(vtkTestAlignLong, x);
31 }
32
33 class VTKCOMMONMISC_EXPORT vtkHeapBlock
34 {
35 public:
36 char* Data;
37 vtkHeapBlock* Next;
38 size_t Size; // Variable size guards against block size changing from SetBlockSize()
39 // or large requests greater than the standard block size.
40
vtkHeapBlock(size_t size)41 vtkHeapBlock(size_t size)
42 : Next(nullptr)
43 , Size(size)
44 {
45 this->Data = new char[size];
46 }
~vtkHeapBlock()47 ~vtkHeapBlock() { delete[] this->Data; }
48 };
49
vtkHeap()50 vtkHeap::vtkHeap()
51 {
52 this->BlockSize = 256000;
53 this->NumberOfBlocks = 0;
54 this->NumberOfAllocations = 0;
55 this->Alignment = vtkGetLongAlignment();
56 this->First = nullptr;
57 this->Last = nullptr;
58 this->Current = nullptr;
59 this->Position = 0;
60 }
61
~vtkHeap()62 vtkHeap::~vtkHeap()
63 {
64 this->CleanAll();
65 }
66
SetBlockSize(size_t _arg)67 void vtkHeap::SetBlockSize(size_t _arg)
68 {
69 vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting BlockSize to "
70 << static_cast<int>(_arg));
71 if (this->BlockSize != _arg)
72 {
73 this->BlockSize = _arg;
74 this->Modified();
75 }
76 }
77
AllocateMemory(size_t n)78 void* vtkHeap::AllocateMemory(size_t n)
79 {
80 if (n % this->Alignment) // 4-byte word alignment
81 {
82 n += this->Alignment - (n % this->Alignment);
83 }
84
85 size_t blockSize = (n > this->BlockSize ? n : this->BlockSize);
86 this->NumberOfAllocations++;
87
88 if (!this->Current || (this->Position + n) >= this->Current->Size)
89 {
90 this->Add(blockSize);
91 }
92
93 char* ptr = this->Current->Data + this->Position;
94 this->Position += n;
95
96 return ptr;
97 }
98
99 // If a Reset() was invoked, then we reuse memory (i.e., the list of blocks)
100 // or allocate it as necessary. Otherwise a block is allocated and placed into
101 // the list of blocks.
Add(size_t blockSize)102 void vtkHeap::Add(size_t blockSize)
103 {
104 this->Position = 0; // reset to the beginning of the block
105
106 if (this->Current && this->Current != this->Last &&
107 this->Current->Next->Size >= blockSize) // reuse
108 {
109 this->Current = this->Current->Next;
110 }
111
112 else // allocate a new block
113 {
114 this->NumberOfBlocks++;
115 vtkHeapBlock* block = new vtkHeapBlock(blockSize);
116
117 if (!this->Last)
118 {
119 this->First = block;
120 this->Current = block;
121 this->Last = block;
122 return;
123 }
124
125 this->Last->Next = block;
126 this->Last = block;
127 this->Current = block;
128 }
129 }
130
CleanAll()131 void vtkHeap::CleanAll()
132 {
133 this->Current = this->First;
134 if (!this->Current)
135 {
136 return;
137 }
138 while (this->DeleteAndNext())
139 {
140 ;
141 }
142 this->First = this->Current = this->Last = nullptr;
143 this->Position = 0;
144 }
145
DeleteAndNext()146 vtkHeapBlock* vtkHeap::DeleteAndNext()
147 {
148 if (this->Current)
149 {
150 vtkHeapBlock* tmp = this->Current;
151 this->Current = this->Current->Next;
152 delete tmp;
153 return this->Current;
154 }
155 else
156 {
157 return nullptr;
158 }
159 }
160
Reset()161 void vtkHeap::Reset()
162 {
163 this->Current = this->First;
164 this->Position = 0;
165 }
166
StringDup(const char * str)167 char* vtkHeap::StringDup(const char* str)
168 {
169 char* newStr = static_cast<char*>(this->AllocateMemory(strlen(str) + 1));
170 strcpy(newStr, str);
171 return newStr;
172 }
173
PrintSelf(ostream & os,vtkIndent indent)174 void vtkHeap::PrintSelf(ostream& os, vtkIndent indent)
175 {
176 this->Superclass::PrintSelf(os, indent);
177
178 os << indent << "Block Size: " << static_cast<int>(this->BlockSize) << "\n";
179 os << indent << "Number of Blocks: " << this->NumberOfBlocks << "\n";
180 os << indent << "Number of Allocations: " << this->NumberOfAllocations << "\n";
181 os << indent << "Current bytes allocated: "
182 << ((this->NumberOfBlocks - 1) * static_cast<int>(this->BlockSize) +
183 static_cast<int>(this->Position))
184 << "\n";
185 }
186