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