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 "vtkCommonMiscModule.h" // For export macro
16 #include "vtkHeap.h"
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):Next(nullptr),Size(size)
42 {this->Data = new char [size];}
~vtkHeapBlock()43 ~vtkHeapBlock()
44 {delete [] this->Data;}
45 };
46
vtkHeap()47 vtkHeap::vtkHeap()
48 {
49 this->BlockSize = 256000;
50 this->NumberOfBlocks = 0;
51 this->NumberOfAllocations = 0;
52 this->Alignment = vtkGetLongAlignment();
53 this->First = nullptr;
54 this->Last = nullptr;
55 this->Current = nullptr;
56 this->Position = 0;
57 }
58
~vtkHeap()59 vtkHeap::~vtkHeap()
60 {
61 this->CleanAll();
62 }
63
SetBlockSize(size_t _arg)64 void vtkHeap::SetBlockSize(size_t _arg)
65 {
66 vtkDebugMacro(
67 << this->GetClassName() << " (" << this << "): setting BlockSize to "
68 << static_cast<int>(_arg));
69 if (this->BlockSize != _arg)
70 {
71 this->BlockSize = _arg;
72 this->Modified();
73 }
74 }
75
AllocateMemory(size_t n)76 void* vtkHeap::AllocateMemory(size_t n)
77 {
78 if ( n%this->Alignment ) //4-byte word alignment
79 {
80 n += this->Alignment - (n%this->Alignment);
81 }
82
83 size_t blockSize = (n > this->BlockSize ? n : this->BlockSize );
84 this->NumberOfAllocations++;
85
86 if ( ! this->Current ||
87 (this->Position + n) >= this->Current->Size )
88 {
89 this->Add(blockSize);
90 }
91
92 char *ptr = this->Current->Data + this->Position;
93 this->Position += n;
94
95 return ptr;
96 }
97
98 // If a Reset() was invoked, then we reuse memory (i.e., the list of blocks)
99 // or allocate it as necessary. Otherwise a block is allocated and placed into
100 // the list of blocks.
Add(size_t blockSize)101 void vtkHeap::Add(size_t blockSize)
102 {
103 this->Position = 0; //reset to the beginning of the block
104
105 if ( this->Current && this->Current != this->Last &&
106 this->Current->Next->Size >= blockSize ) //reuse
107 {
108 this->Current = this->Current->Next;
109 }
110
111 else //allocate a new block
112 {
113 this->NumberOfBlocks++;
114 vtkHeapBlock* block = new vtkHeapBlock(blockSize);
115
116 if (!this->Last)
117 {
118 this->First = block;
119 this->Current = block;
120 this->Last = block;
121 return;
122 }
123
124 this->Last->Next = block;
125 this->Last = block;
126 this->Current = block;
127 }
128 }
129
CleanAll()130 void vtkHeap::CleanAll()
131 {
132 this->Current = this->First;
133 if (!this->Current) { return; }
134 while (this->DeleteAndNext())
135 {
136 ;
137 }
138 this->First = this->Current = this->Last = nullptr;
139 this->Position = 0;
140 }
141
DeleteAndNext()142 vtkHeapBlock* vtkHeap::DeleteAndNext()
143 {
144 if (this->Current)
145 {
146 vtkHeapBlock* tmp = this->Current;
147 this->Current = this->Current->Next;
148 delete tmp;
149 return this->Current;
150 }
151 else
152 {
153 return nullptr;
154 }
155 }
156
Reset()157 void vtkHeap::Reset()
158 {
159 this->Current = this->First;
160 this->Position = 0;
161 }
162
StringDup(const char * str)163 char* vtkHeap::StringDup(const char* str)
164 {
165 char *newStr = static_cast<char*>(this->AllocateMemory(strlen(str)+1));
166 strcpy(newStr,str);
167 return newStr;
168 }
169
PrintSelf(ostream & os,vtkIndent indent)170 void vtkHeap::PrintSelf(ostream& os, vtkIndent indent)
171 {
172 this->Superclass::PrintSelf(os,indent);
173
174 os << indent << "Block Size: " << static_cast<int>(this->BlockSize) << "\n";
175 os << indent << "Number of Blocks: " << this->NumberOfBlocks << "\n";
176 os << indent << "Number of Allocations: " << this->NumberOfAllocations << "\n";
177 os << indent << "Current bytes allocated: "
178 << ((this->NumberOfBlocks-1)*static_cast<int>(this->BlockSize) +
179 static_cast<int>(this->Position)) << "\n";
180 }
181
182