1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // ---------------------------------------------------------------------------
8 // Utilities to write native data to images, that can be read by the NativeFormat.Reader class
9 // ---------------------------------------------------------------------------
16 // To reduce differences between C# and C++ versions
19 #define UInt16 uint16_t
20 #define UInt32 uint32_t
21 #define UInt64 uint64_t
23 #include <clr_std/vector>
25 namespace NativeFormat
34 friend class NativeWriter;
35 friend class NativeSection;
38 int m_iteration; // Iteration that the offset is valid for
40 static const int NotPlaced = -1;
41 static const int Placed = -2;
45 : m_offset(Vertex::NotPlaced), m_iteration(-1)
51 virtual void Save(NativeWriter * pWriter) = 0;
55 assert(m_offset >= 0);
60 class NativeSection : vector<Vertex *>
62 friend class NativeWriter;
65 Vertex * Place(Vertex * pVertex);
69 Vertex * pVertex = *(end() - 1);
72 assert(pVertex->m_offset == Vertex::Placed);
73 pVertex->m_offset = Vertex::NotPlaced;
81 vector<NativeSection *> m_Sections;
91 vector<byte> m_Buffer;
93 SavePhase m_phase; // Current save phase
94 int m_offsetAdjustment; // Cumulative offset adjustment compared to previous iteration
95 int m_paddingSize; // How much padding was used
104 NativeSection * NewSection()
106 NativeSection * pSection = new NativeSection();
107 m_Sections.push_back(pSection);
111 void WriteByte(byte b)
113 m_Buffer.push_back(b);
116 void WriteUInt16(UInt16 value)
118 WriteByte((byte)value);
119 WriteByte((byte)(value>>8));
122 void WriteUInt32(UInt32 value)
124 WriteByte((byte)value);
125 WriteByte((byte)(value>>8));
126 WriteByte((byte)(value>>16));
127 WriteByte((byte)(value>>24));
130 void WritePad(unsigned size)
141 return m_phase == Growing;
144 void UpdateOffsetAdjustment(int offsetDelta)
149 m_offsetAdjustment = min(m_offsetAdjustment, offsetDelta);
152 m_offsetAdjustment = max(m_offsetAdjustment, offsetDelta);
159 void RollbackTo(int offset)
161 m_Buffer.erase(m_Buffer.begin() + offset, m_Buffer.end());
164 void RollbackTo(int offset, int offsetAdjustment)
166 m_offsetAdjustment = offsetAdjustment;
170 void PatchByteAt(int offset, byte value)
172 m_Buffer[offset] = value;
176 // Same encoding as what's used by CTL
178 void WriteUnsigned(unsigned d);
179 static unsigned GetUnsignedEncodingSize(unsigned d);
181 template <typename T>
182 void WriteUnsigned(T d)
184 WriteUnsigned((unsigned)d);
187 void WriteSigned(int i);
189 void WriteRelativeOffset(Vertex * pVal);
191 int GetExpectedOffset(Vertex * pVal);
193 int GetCurrentOffset(Vertex * pVal)
195 if (pVal->m_iteration != m_iteration)
197 return pVal->m_offset;
200 void SetCurrentOffset(Vertex * pVal)
202 pVal->m_iteration = m_iteration;
203 pVal->m_offset = GetCurrentOffset();
206 int GetCurrentOffset()
208 return (int)m_Buffer.size();
211 int GetNumberOfIterations()
218 return m_paddingSize;
221 vector<byte>& Save();
226 // Data structure building blocks
229 class UnsignedConstant : public Vertex
234 UnsignedConstant(unsigned value)
239 virtual void Save(NativeWriter * pWriter)
241 pWriter->WriteUnsigned(m_value);
246 // Sparse array. Good for random access based on index
248 class VertexArray : public Vertex
250 vector<Vertex *> m_Entries;
252 NativeSection * m_pSection;
253 vector<Vertex *> m_Blocks;
255 static const int _blockSize = 16;
257 // Current size of index entry
258 int m_entryIndexSize; // 0 - uint8, 1 - uint16, 2 - uint32
260 class VertexLeaf : public Vertex
266 virtual void Save(NativeWriter * pWriter);
269 class VertexTree : public Vertex
275 virtual void Save(NativeWriter * pWriter);
278 Vertex * ExpandBlock(size_t index, int depth, bool place, bool * pLeaf);
281 VertexArray(NativeSection * pSection)
282 : m_pSection(pSection)
286 void Set(int index, Vertex * pElement)
288 while ((size_t)index >= m_Entries.size())
289 m_Entries.push_back(nullptr);
291 m_Entries[index] = pElement;
296 virtual void Save(NativeWriter * pWriter);
300 // Hashtable. Good for random access based on hashcode + key
302 class VertexHashtable : public Vertex
307 : offset(-1), hashcode(0), pVertex(NULL)
311 Entry(unsigned hashcode, Vertex * pVertex)
312 : offset(0), hashcode(hashcode), pVertex(pVertex)
322 vector<Entry> m_Entries;
324 // How many entries to target per bucket. Higher fill factor means smaller size, but worse runtime perf.
327 // Number of buckets choosen for the table. Must be power of two. 0 means that the table is still open for mutation.
330 // Current size of index entry
331 int m_entryIndexSize; // 0 - uint8, 1 - uint16, 2 - uint32
333 void ComputeLayout();
336 static const int DefaultFillFactor = 13;
338 VertexHashtable(int fillFactor = DefaultFillFactor)
342 m_nFillFactor = fillFactor;
345 void Append(unsigned hashcode, Vertex * pElement)
347 // The table needs to be open for mutation
348 assert(m_nBuckets == 0);
350 m_Entries.push_back(Entry(hashcode, pElement));
353 virtual void Save(NativeWriter * pWriter);