BufferSegment.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System;
  2. using Best.HTTP.Shared.PlatformSupport.Text;
  3. namespace Best.HTTP.Shared.PlatformSupport.Memory
  4. {
  5. /// <summary>
  6. /// Represents a segment (a continuous section) of a byte array, providing functionalities to
  7. /// work with a portion of the data without copying.
  8. /// </summary>
  9. [Best.HTTP.Shared.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
  10. public readonly struct BufferSegment
  11. {
  12. internal const int ToStringMaxDumpLength = 128;
  13. /// <summary>
  14. /// Represents an empty buffer segment.
  15. /// </summary>
  16. public static readonly BufferSegment Empty = new BufferSegment(null, 0, 0);
  17. /// <summary>
  18. /// The underlying data of the buffer segment.
  19. /// </summary>
  20. public readonly byte[] Data;
  21. /// <summary>
  22. /// The starting offset of the segment within the data.
  23. /// </summary>
  24. public readonly int Offset;
  25. /// <summary>
  26. /// The number of bytes in the segment that contain valid data.
  27. /// </summary>
  28. public readonly int Count;
  29. /// <summary>
  30. /// Initializes a new instance of the BufferSegment struct.
  31. /// </summary>
  32. /// <param name="data">The data for the buffer segment.</param>
  33. /// <param name="offset">The starting offset of the segment.</param>
  34. /// <param name="count">The number of bytes in the segment.</param>
  35. public BufferSegment(byte[] data, int offset, int count)
  36. {
  37. this.Data = data;
  38. this.Offset = offset;
  39. this.Count = count;
  40. }
  41. /// <summary>
  42. /// Converts the buffer segment to an AutoReleaseBuffer to use it in a local using statement.
  43. /// </summary>
  44. /// <returns>A new AutoReleaseBuffer instance containing the data of the buffer segment.</returns>
  45. public AutoReleaseBuffer AsAutoRelease() => new AutoReleaseBuffer(this);
  46. /// <summary>
  47. /// Creates a new segment starting from the specified offset.
  48. /// </summary>
  49. /// <remarks>The new segment will reference the same underlying byte[] as the original, without creating a copy of the data.</remarks>
  50. /// <param name="newOffset">The starting offset of the new segment.</param>
  51. /// <returns>A new buffer segment that references the same underlying data.</returns>
  52. public BufferSegment Slice(int newOffset) => new BufferSegment(this.Data, newOffset, this.Count - (newOffset - this.Offset));
  53. /// <summary>
  54. /// Creates a new segment with the specified offset and count.
  55. /// </summary>
  56. /// <remarks>The new segment will reference the same underlying byte[] as the original, without creating a copy of the data.</remarks>
  57. /// <param name="offset">The starting offset of the new segment.</param>
  58. /// <param name="count">The number of bytes in the new segment.</param>
  59. /// <returns>A new buffer segment that references the same underlying data.</returns>
  60. public BufferSegment Slice(int offset, int count) => new BufferSegment(this.Data, offset, count);
  61. /// <summary>
  62. /// Copyies the buffer's content to the received array.
  63. /// </summary>
  64. /// <param name="to">The array the data will be copied into.</param>
  65. public void CopyTo(byte[] to) => Array.Copy(this.Data, this.Offset, to, 0, this.Count);
  66. public override bool Equals(object obj)
  67. {
  68. if (obj == null || !(obj is BufferSegment))
  69. return false;
  70. return Equals((BufferSegment)obj);
  71. }
  72. public bool Equals(BufferSegment other) => this.Data == other.Data && this.Offset == other.Offset && this.Count == other.Count;
  73. public bool Equals(AutoReleaseBuffer other) => this.Data == other.Data && this.Offset == other.Offset && this.Count == other.Count;
  74. public override int GetHashCode() => (this.Data != null ? this.Data.GetHashCode() : 0) * 21 + this.Offset + this.Count;
  75. public static bool operator ==(BufferSegment left, BufferSegment right) => left.Equals(right);
  76. public static bool operator !=(BufferSegment left, BufferSegment right) => !left.Equals(right);
  77. public static bool operator ==(BufferSegment left, AutoReleaseBuffer right) => left.Equals(right);
  78. public static bool operator !=(BufferSegment left, AutoReleaseBuffer right) => !left.Equals(right);
  79. public static implicit operator byte[](BufferSegment left) => left.Data;
  80. public override string ToString()
  81. {
  82. var sb = StringBuilderPool.Get(this.Count + 5);
  83. sb.Append("[BufferSegment ");
  84. if (this.Count > 0)
  85. {
  86. sb.AppendFormat("Offset: {0:N0} ", this.Offset);
  87. sb.AppendFormat("Count: {0:N0} ", this.Count);
  88. sb.Append("Data: [");
  89. if (this.Count > 0)
  90. {
  91. int dumpCount = Math.Min(this.Count, ToStringMaxDumpLength);
  92. sb.AppendFormat("{0:X2}", this.Data[this.Offset]);
  93. for (int i = 1; i < dumpCount; ++i)
  94. sb.AppendFormat(", {0:X2}", this.Data[this.Offset + i]);
  95. if (this.Count > dumpCount)
  96. sb.Append(", ...");
  97. }
  98. sb.Append("]]");
  99. }
  100. else
  101. sb.Append(']');
  102. return StringBuilderPool.ReleaseAndGrab(sb);
  103. }
  104. }
  105. }