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