Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
MemoryBlock.cs
Go to the documentation of this file.
5using System.Text;
6
8
9[DebuggerDisplay("{GetDebuggerDisplay(),nq}")]
10internal readonly struct MemoryBlock
11{
20
21 internal unsafe readonly byte* Pointer;
22
23 internal readonly int Length;
24
25 internal unsafe MemoryBlock(byte* buffer, int length)
26 {
28 Length = length;
29 }
30
31 internal unsafe static MemoryBlock CreateChecked(byte* buffer, int length)
32 {
33 if (length < 0)
34 {
35 throw new ArgumentOutOfRangeException("length");
36 }
37 if (buffer == null && length != 0)
38 {
39 throw new ArgumentNullException("buffer");
40 }
41 return new MemoryBlock(buffer, length);
42 }
43
44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 private void CheckBounds(int offset, int byteCount)
46 {
47 if ((ulong)((long)(uint)offset + (long)(uint)byteCount) > (ulong)Length)
48 {
50 }
51 }
52
53 internal unsafe byte[]? ToArray()
54 {
55 if (Pointer != null)
56 {
57 return PeekBytes(0, Length);
58 }
59 return null;
60 }
61
62 private unsafe string GetDebuggerDisplay()
63 {
64 if (Pointer == null)
65 {
66 return "<null>";
67 }
68 int displayedBytes;
69 return GetDebuggerDisplay(out displayedBytes);
70 }
71
72 internal string GetDebuggerDisplay(out int displayedBytes)
73 {
74 displayedBytes = Math.Min(Length, 64);
75 string text = BitConverter.ToString(PeekBytes(0, displayedBytes));
76 if (displayedBytes < Length)
77 {
78 text += "-...";
79 }
80 return text;
81 }
82
83 internal unsafe string GetDebuggerDisplay(int offset)
84 {
85 if (Pointer == null)
86 {
87 return "<null>";
88 }
89 int displayedBytes;
90 string debuggerDisplay = GetDebuggerDisplay(out displayedBytes);
91 if (offset < displayedBytes)
92 {
93 return debuggerDisplay.Insert(offset * 3, "*");
94 }
95 if (displayedBytes == Length)
96 {
97 return debuggerDisplay + "*";
98 }
99 return debuggerDisplay + "*...";
100 }
101
102 internal unsafe MemoryBlock GetMemoryBlockAt(int offset, int length)
103 {
105 return new MemoryBlock(Pointer + offset, length);
106 }
107
108 internal unsafe byte PeekByte(int offset)
109 {
111 return Pointer[offset];
112 }
113
114 internal int PeekInt32(int offset)
115 {
116 uint num = PeekUInt32(offset);
117 if ((int)num != num)
118 {
120 }
121 return (int)num;
122 }
123
124 [MethodImpl(MethodImplOptions.AggressiveInlining)]
125 internal unsafe uint PeekUInt32(int offset)
126 {
128 byte* ptr = Pointer + offset;
129 return (uint)(*ptr | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24));
130 }
131
132 internal unsafe int PeekCompressedInteger(int offset, out int numberOfBytesRead)
133 {
135 byte* ptr = Pointer + offset;
136 long num = Length - offset;
137 if (num == 0L)
138 {
139 numberOfBytesRead = 0;
140 return int.MaxValue;
141 }
142 byte b = *ptr;
143 if ((b & 0x80) == 0)
144 {
145 numberOfBytesRead = 1;
146 return b;
147 }
148 if ((b & 0x40) == 0)
149 {
150 if (num >= 2)
151 {
152 numberOfBytesRead = 2;
153 return ((b & 0x3F) << 8) | ptr[1];
154 }
155 }
156 else if ((b & 0x20) == 0 && num >= 4)
157 {
158 numberOfBytesRead = 4;
159 return ((b & 0x1F) << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
160 }
161 numberOfBytesRead = 0;
162 return int.MaxValue;
163 }
164
165 [MethodImpl(MethodImplOptions.AggressiveInlining)]
166 internal unsafe ushort PeekUInt16(int offset)
167 {
169 byte* ptr = Pointer + offset;
170 return (ushort)(*ptr | (ptr[1] << 8));
171 }
172
173 internal uint PeekTaggedReference(int offset, bool smallRefSize)
174 {
175 return PeekReferenceUnchecked(offset, smallRefSize);
176 }
177
178 internal uint PeekReferenceUnchecked(int offset, bool smallRefSize)
179 {
180 if (!smallRefSize)
181 {
182 return PeekUInt32(offset);
183 }
184 return PeekUInt16(offset);
185 }
186
187 internal int PeekReference(int offset, bool smallRefSize)
188 {
189 if (smallRefSize)
190 {
191 return PeekUInt16(offset);
192 }
193 uint num = PeekUInt32(offset);
194 if (!TokenTypeIds.IsValidRowId(num))
195 {
197 }
198 return (int)num;
199 }
200
201 internal int PeekHeapReference(int offset, bool smallRefSize)
202 {
203 if (smallRefSize)
204 {
205 return PeekUInt16(offset);
206 }
207 uint num = PeekUInt32(offset);
209 {
211 }
212 return (int)num;
213 }
214
215 internal unsafe Guid PeekGuid(int offset)
216 {
217 CheckBounds(offset, sizeof(Guid));
218 byte* ptr = Pointer + offset;
220 {
221 return *(Guid*)ptr;
222 }
223 return new Guid(*ptr | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24), (short)(ptr[4] | (ptr[5] << 8)), (short)(ptr[6] | (ptr[7] << 8)), ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
224 }
225
226 internal unsafe string PeekUtf16(int offset, int byteCount)
227 {
229 byte* ptr = Pointer + offset;
231 {
232 return new string((char*)ptr, 0, byteCount / 2);
233 }
234 return Encoding.Unicode.GetString(ptr, byteCount);
235 }
236
237 internal unsafe string PeekUtf8(int offset, int byteCount)
238 {
240 return Encoding.UTF8.GetString(Pointer + offset, byteCount);
241 }
242
243 internal unsafe string PeekUtf8NullTerminated(int offset, byte[]? prefix, MetadataStringDecoder utf8Decoder, out int numberOfBytesRead, char terminator = '\0')
244 {
246 int utf8NullTerminatedLength = GetUtf8NullTerminatedLength(offset, out numberOfBytesRead, terminator);
247 return EncodingHelper.DecodeUtf8(Pointer + offset, utf8NullTerminatedLength, prefix, utf8Decoder);
248 }
249
250 internal unsafe int GetUtf8NullTerminatedLength(int offset, out int numberOfBytesRead, char terminator = '\0')
251 {
253 byte* ptr = Pointer + offset;
254 byte* ptr2 = Pointer + Length;
255 byte* ptr3;
256 for (ptr3 = ptr; ptr3 < ptr2; ptr3++)
257 {
258 byte b = *ptr3;
259 if (b == 0 || b == terminator)
260 {
261 break;
262 }
263 }
264 int result = (numberOfBytesRead = (int)(ptr3 - ptr));
265 if (ptr3 < ptr2)
266 {
267 numberOfBytesRead++;
268 }
269 return result;
270 }
271
272 internal unsafe int Utf8NullTerminatedOffsetOfAsciiChar(int startOffset, char asciiChar)
273 {
274 CheckBounds(startOffset, 0);
275 for (int i = startOffset; i < Length; i++)
276 {
277 byte b = Pointer[i];
278 if (b == 0)
279 {
280 break;
281 }
282 if (b == asciiChar)
283 {
284 return i;
285 }
286 }
287 return -1;
288 }
289
290 internal bool Utf8NullTerminatedEquals(int offset, string text, MetadataStringDecoder utf8Decoder, char terminator, bool ignoreCase)
291 {
292 int firstDifferenceIndex;
293 FastComparisonResult fastComparisonResult = Utf8NullTerminatedFastCompare(offset, text, 0, out firstDifferenceIndex, terminator, ignoreCase);
294 if (fastComparisonResult == FastComparisonResult.Inconclusive)
295 {
296 int numberOfBytesRead;
297 string text2 = PeekUtf8NullTerminated(offset, null, utf8Decoder, out numberOfBytesRead, terminator);
298 return text2.Equals(text, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
299 }
300 return fastComparisonResult == FastComparisonResult.Equal;
301 }
302
303 internal bool Utf8NullTerminatedStartsWith(int offset, string text, MetadataStringDecoder utf8Decoder, char terminator, bool ignoreCase)
304 {
305 int firstDifferenceIndex;
306 switch (Utf8NullTerminatedFastCompare(offset, text, 0, out firstDifferenceIndex, terminator, ignoreCase))
307 {
308 case FastComparisonResult.Equal:
309 case FastComparisonResult.BytesStartWithText:
310 return true;
311 case FastComparisonResult.TextStartsWithBytes:
312 case FastComparisonResult.Unequal:
313 return false;
314 default:
315 {
316 int numberOfBytesRead;
317 string text2 = PeekUtf8NullTerminated(offset, null, utf8Decoder, out numberOfBytesRead, terminator);
318 return text2.StartsWith(text, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
319 }
320 }
321 }
322
323 internal unsafe FastComparisonResult Utf8NullTerminatedFastCompare(int offset, string text, int textStart, out int firstDifferenceIndex, char terminator, bool ignoreCase)
324 {
326 byte* ptr = Pointer + offset;
327 byte* ptr2 = Pointer + Length;
328 byte* ptr3 = ptr;
329 int ignoreCaseMask = StringUtils.IgnoreCaseMask(ignoreCase);
330 int num = textStart;
331 while (num < text.Length && ptr3 != ptr2)
332 {
333 byte b = *ptr3;
334 if (b == 0 || b == terminator)
335 {
336 break;
337 }
338 char c = text[num];
339 if ((b & 0x80) == 0 && StringUtils.IsEqualAscii(c, b, ignoreCaseMask))
340 {
341 num++;
342 ptr3++;
343 continue;
344 }
345 firstDifferenceIndex = num;
346 if (c <= '\u007f')
347 {
348 return FastComparisonResult.Unequal;
349 }
350 return FastComparisonResult.Inconclusive;
351 }
352 firstDifferenceIndex = num;
353 bool flag = num == text.Length;
354 bool flag2 = ptr3 == ptr2 || *ptr3 == 0 || *ptr3 == terminator;
355 if (flag && flag2)
356 {
357 return FastComparisonResult.Equal;
358 }
359 if (!flag)
360 {
361 return FastComparisonResult.TextStartsWithBytes;
362 }
363 return FastComparisonResult.BytesStartWithText;
364 }
365
366 internal unsafe bool Utf8NullTerminatedStringStartsWithAsciiPrefix(int offset, string asciiPrefix)
367 {
369 if (asciiPrefix.Length > Length - offset)
370 {
371 return false;
372 }
373 byte* ptr = Pointer + offset;
374 for (int i = 0; i < asciiPrefix.Length; i++)
375 {
376 if (asciiPrefix[i] != *ptr)
377 {
378 return false;
379 }
380 ptr++;
381 }
382 return true;
383 }
384
385 internal unsafe int CompareUtf8NullTerminatedStringWithAsciiString(int offset, string asciiString)
386 {
388 byte* ptr = Pointer + offset;
389 int num = Length - offset;
390 for (int i = 0; i < asciiString.Length; i++)
391 {
392 if (i > num)
393 {
394 return -1;
395 }
396 if (*ptr != asciiString[i])
397 {
398 return *ptr - asciiString[i];
399 }
400 ptr++;
401 }
402 if (*ptr != 0)
403 {
404 return 1;
405 }
406 return 0;
407 }
408
409 internal unsafe byte[] PeekBytes(int offset, int byteCount)
410 {
413 }
414
415 internal int IndexOf(byte b, int start)
416 {
417 CheckBounds(start, 0);
418 return IndexOfUnchecked(b, start);
419 }
420
421 internal unsafe int IndexOfUnchecked(byte b, int start)
422 {
423 byte* ptr = Pointer + start;
424 for (byte* ptr2 = Pointer + Length; ptr < ptr2; ptr++)
425 {
426 if (*ptr == b)
427 {
428 return (int)(ptr - Pointer);
429 }
430 }
431 return -1;
432 }
433
434 internal int BinarySearch(string[] asciiKeys, int offset)
435 {
436 int num = 0;
437 int num2 = asciiKeys.Length - 1;
438 while (num <= num2)
439 {
440 int num3 = num + (num2 - num >> 1);
441 string asciiString = asciiKeys[num3];
443 if (num4 == 0)
444 {
445 return num3;
446 }
447 if (num4 < 0)
448 {
449 num2 = num3 - 1;
450 }
451 else
452 {
453 num = num3 + 1;
454 }
455 }
456 return ~num;
457 }
458
459 internal int BinarySearchForSlot(int rowCount, int rowSize, int referenceListOffset, uint referenceValue, bool isReferenceSmall)
460 {
461 int num = 0;
462 int num2 = rowCount - 1;
463 uint num3 = PeekReferenceUnchecked(num * rowSize + referenceListOffset, isReferenceSmall);
464 uint num4 = PeekReferenceUnchecked(num2 * rowSize + referenceListOffset, isReferenceSmall);
465 if (num2 == 1)
466 {
467 if (referenceValue >= num4)
468 {
469 return num2;
470 }
471 return num;
472 }
473 while (num2 - num > 1)
474 {
475 if (referenceValue <= num3)
476 {
477 if (referenceValue != num3)
478 {
479 return num - 1;
480 }
481 return num;
482 }
483 if (referenceValue >= num4)
484 {
485 if (referenceValue != num4)
486 {
487 return num2 + 1;
488 }
489 return num2;
490 }
491 int num5 = (num + num2) / 2;
492 uint num6 = PeekReferenceUnchecked(num5 * rowSize + referenceListOffset, isReferenceSmall);
493 if (referenceValue > num6)
494 {
495 num = num5;
496 num3 = num6;
497 continue;
498 }
499 if (referenceValue < num6)
500 {
501 num2 = num5;
502 num4 = num6;
503 continue;
504 }
505 return num5;
506 }
507 return num;
508 }
509
510 internal int BinarySearchReference(int rowCount, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall)
511 {
512 int num = 0;
513 int num2 = rowCount - 1;
514 while (num <= num2)
515 {
516 int num3 = (num + num2) / 2;
517 uint num4 = PeekReferenceUnchecked(num3 * rowSize + referenceOffset, isReferenceSmall);
518 if (referenceValue > num4)
519 {
520 num = num3 + 1;
521 continue;
522 }
523 if (referenceValue < num4)
524 {
525 num2 = num3 - 1;
526 continue;
527 }
528 return num3;
529 }
530 return -1;
531 }
532
533 internal int BinarySearchReference(int[] ptrTable, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall)
534 {
535 int num = 0;
536 int num2 = ptrTable.Length - 1;
537 while (num <= num2)
538 {
539 int num3 = (num + num2) / 2;
540 uint num4 = PeekReferenceUnchecked((ptrTable[num3] - 1) * rowSize + referenceOffset, isReferenceSmall);
541 if (referenceValue > num4)
542 {
543 num = num3 + 1;
544 continue;
545 }
546 if (referenceValue < num4)
547 {
548 num2 = num3 - 1;
549 continue;
550 }
551 return num3;
552 }
553 return -1;
554 }
555
556 internal void BinarySearchReferenceRange(int rowCount, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall, out int startRowNumber, out int endRowNumber)
557 {
558 int num = BinarySearchReference(rowCount, rowSize, referenceOffset, referenceValue, isReferenceSmall);
559 if (num == -1)
560 {
561 startRowNumber = -1;
562 endRowNumber = -1;
563 return;
564 }
565 startRowNumber = num;
566 while (startRowNumber > 0 && PeekReferenceUnchecked((startRowNumber - 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue)
567 {
568 startRowNumber--;
569 }
570 endRowNumber = num;
571 while (endRowNumber + 1 < rowCount && PeekReferenceUnchecked((endRowNumber + 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue)
572 {
573 endRowNumber++;
574 }
575 }
576
577 internal void BinarySearchReferenceRange(int[] ptrTable, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall, out int startRowNumber, out int endRowNumber)
578 {
579 int num = BinarySearchReference(ptrTable, rowSize, referenceOffset, referenceValue, isReferenceSmall);
580 if (num == -1)
581 {
582 startRowNumber = -1;
583 endRowNumber = -1;
584 return;
585 }
586 startRowNumber = num;
587 while (startRowNumber > 0 && PeekReferenceUnchecked((ptrTable[startRowNumber - 1] - 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue)
588 {
589 startRowNumber--;
590 }
591 endRowNumber = num;
592 while (endRowNumber + 1 < ptrTable.Length && PeekReferenceUnchecked((ptrTable[endRowNumber + 1] - 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue)
593 {
594 endRowNumber++;
595 }
596 }
597
598 internal int LinearSearchReference(int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall)
599 {
600 int i = referenceOffset;
601 for (int length = Length; i < length; i += rowSize)
602 {
603 uint num = PeekReferenceUnchecked(i, isReferenceSmall);
604 if (num == referenceValue)
605 {
606 return i / rowSize;
607 }
608 }
609 return -1;
610 }
611
612 internal bool IsOrderedByReferenceAscending(int rowSize, int referenceOffset, bool isReferenceSmall)
613 {
614 int i = referenceOffset;
615 int length = Length;
616 uint num = 0u;
617 for (; i < length; i += rowSize)
618 {
619 uint num2 = PeekReferenceUnchecked(i, isReferenceSmall);
620 if (num2 < num)
621 {
622 return false;
623 }
624 num = num2;
625 }
626 return true;
627 }
628
629 internal int[] BuildPtrTable(int numberOfRows, int rowSize, int referenceOffset, bool isReferenceSmall)
630 {
631 int[] array = new int[numberOfRows];
632 uint[] unsortedReferences = new uint[numberOfRows];
633 for (int i = 0; i < array.Length; i++)
634 {
635 array[i] = i + 1;
636 }
637 ReadColumn(unsortedReferences, rowSize, referenceOffset, isReferenceSmall);
638 Array.Sort(array, (int a, int b) => unsortedReferences[a - 1].CompareTo(unsortedReferences[b - 1]));
639 return array;
640 }
641
642 private void ReadColumn(uint[] result, int rowSize, int referenceOffset, bool isReferenceSmall)
643 {
644 int num = referenceOffset;
645 int length = Length;
646 int num2 = 0;
647 while (num < length)
648 {
649 result[num2] = PeekReferenceUnchecked(num, isReferenceSmall);
650 num += rowSize;
651 num2++;
652 }
653 }
654
655 internal bool PeekHeapValueOffsetAndSize(int index, out int offset, out int size)
656 {
657 int numberOfBytesRead;
658 int num = PeekCompressedInteger(index, out numberOfBytesRead);
659 if (num == int.MaxValue)
660 {
661 offset = 0;
662 size = 0;
663 return false;
664 }
665 offset = index + numberOfBytesRead;
666 size = num;
667 return true;
668 }
669}
static void Sort(Array array)
Definition Array.cs:2329
static string ToString(byte[] value, int startIndex, int length)
static readonly bool IsLittleEndian
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static unsafe byte[] ReadBytes(byte *buffer, int byteCount)
static unsafe string DecodeUtf8(byte *bytes, int byteCount, byte[]? prefix, MetadataStringDecoder utf8Decoder)
static int IgnoreCaseMask(bool ignoreCase)
Definition StringUtils.cs:5
static bool IsEqualAscii(int a, int b, int ignoreCaseMask)
static void ValueOverflow()
Definition Throw.cs:278
static void OutOfBounds()
Definition Throw.cs:187
static void ReferenceOverflow()
Definition Throw.cs:243
static Encoding Unicode
Definition Encoding.cs:519
static Encoding UTF8
Definition Encoding.cs:526
void ReadColumn(uint[] result, int rowSize, int referenceOffset, bool isReferenceSmall)
int PeekReference(int offset, bool smallRefSize)
unsafe ushort PeekUInt16(int offset)
unsafe MemoryBlock GetMemoryBlockAt(int offset, int length)
bool IsOrderedByReferenceAscending(int rowSize, int referenceOffset, bool isReferenceSmall)
bool Utf8NullTerminatedEquals(int offset, string text, MetadataStringDecoder utf8Decoder, char terminator, bool ignoreCase)
int BinarySearchReference(int rowCount, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall)
int PeekHeapReference(int offset, bool smallRefSize)
unsafe int IndexOfUnchecked(byte b, int start)
void BinarySearchReferenceRange(int[] ptrTable, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall, out int startRowNumber, out int endRowNumber)
int LinearSearchReference(int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall)
static unsafe MemoryBlock CreateChecked(byte *buffer, int length)
unsafe string PeekUtf16(int offset, int byteCount)
unsafe int Utf8NullTerminatedOffsetOfAsciiChar(int startOffset, char asciiChar)
unsafe int PeekCompressedInteger(int offset, out int numberOfBytesRead)
unsafe byte[] PeekBytes(int offset, int byteCount)
bool PeekHeapValueOffsetAndSize(int index, out int offset, out int size)
unsafe string GetDebuggerDisplay(int offset)
unsafe string PeekUtf8NullTerminated(int offset, byte[]? prefix, MetadataStringDecoder utf8Decoder, out int numberOfBytesRead, char terminator='\0')
int BinarySearchForSlot(int rowCount, int rowSize, int referenceListOffset, uint referenceValue, bool isReferenceSmall)
unsafe bool Utf8NullTerminatedStringStartsWithAsciiPrefix(int offset, string asciiPrefix)
unsafe int GetUtf8NullTerminatedLength(int offset, out int numberOfBytesRead, char terminator='\0')
void CheckBounds(int offset, int byteCount)
int[] BuildPtrTable(int numberOfRows, int rowSize, int referenceOffset, bool isReferenceSmall)
uint PeekReferenceUnchecked(int offset, bool smallRefSize)
int BinarySearch(string[] asciiKeys, int offset)
unsafe int CompareUtf8NullTerminatedStringWithAsciiString(int offset, string asciiString)
void BinarySearchReferenceRange(int rowCount, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall, out int startRowNumber, out int endRowNumber)
unsafe string PeekUtf8(int offset, int byteCount)
bool Utf8NullTerminatedStartsWith(int offset, string text, MetadataStringDecoder utf8Decoder, char terminator, bool ignoreCase)
int BinarySearchReference(int[] ptrTable, int rowSize, int referenceOffset, uint referenceValue, bool isReferenceSmall)
unsafe MemoryBlock(byte *buffer, int length)
unsafe uint PeekUInt32(int offset)
uint PeekTaggedReference(int offset, bool smallRefSize)
unsafe FastComparisonResult Utf8NullTerminatedFastCompare(int offset, string text, int textStart, out int firstDifferenceIndex, char terminator, bool ignoreCase)
string GetDebuggerDisplay(out int displayedBytes)