Repository navigation
Expand file tree
/
Copy pathByteStringView.cs
More file actions
76 lines (69 loc) · 3.67 KB
/
Copy pathByteStringView.cs
File metadata and controls
76 lines (69 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// New managed compatibility support; not an upstream source port.
// Licensed under the Apache License, Version 2.0. See licenses/TypeScript-LICENSE.txt.
#nullable enable
namespace TypeScript.Scanner;
// Go string slicing shares immutable storage. The backing is privately owned UTF8/WTF8 or arbitrary bytes; offsets remain
// bytes, not Unicode scalar positions. FromOwnedBytes transfers immutable ownership.
internal readonly struct ByteStringView
{
private readonly byte[]? backing;
private readonly int offset;
public int Length { get; }
public bool IsDefault => backing is null;
public ReadOnlyMemory<byte> Memory => backing.AsMemory(offset, Length);
private ByteStringView(byte[]? backing, int offset, int length) =>
(this.backing, this.offset, Length) = (backing, offset, length);
// Legacy raw Go strings are an explicit compatibility ingress. Source-file
// loading/parser ownership uses byte arrays directly, without this projection.
public static implicit operator ByteStringView(string? text) => FromGoBytes(text);
internal static ByteStringView FromGoBytes(string? text) => text is null
? default : FromOwnedBytes(text.Length == 0 ? Array.Empty<byte>() : GoString.Bytes(text));
// Builder prefixes are append-only. The mutable builder never overwrites
// this region, and Reset detaches; only the immutable header escapes.
internal static ByteStringView FromBuilderSlice(Slice<byte> bytes)
{
if (!System.Runtime.InteropServices.MemoryMarshal.TryGetArray(bytes.AsMemory(), out var memory))
throw new InvalidOperationException("Builder text requires an array owner");
return new(memory.Array, memory.Offset, memory.Count);
}
internal static ByteStringView FromUnicode(string text) => FromOwnedBytes(System.Text.Encoding.UTF8.GetBytes(text));
internal static ByteStringView FromOwnedBytes(byte[]? bytes) => new(bytes, 0, bytes?.Length ?? 0);
internal static ByteStringView CopyFrom(byte[] bytes)
{
ArgumentNullException.ThrowIfNull(bytes);
return CopyFrom(bytes.AsSpan());
}
internal static ByteStringView CopyFrom(ReadOnlySpan<byte> bytes) => FromOwnedBytes(bytes.ToArray());
public char this[int index]
{
get
{
if ((uint)index >= (uint)Length)
throw new ArgumentOutOfRangeException(nameof(index));
return (char)backing![offset + index];
}
}
public ReadOnlySpan<byte> AsSpan() => backing.AsSpan(offset, Length);
public ReadOnlySpan<byte> AsSpan(int start) => Slice(start).AsSpan();
public ReadOnlySpan<byte> AsSpan(int start, int length) =>
AsSpan().Slice(start, length);
public ByteStringView Slice(int start) => Slice(start, Length);
public ByteStringView Slice(int start, int end)
{
if (start < 0 || end < start || end > Length)
throw new ArgumentOutOfRangeException(nameof(start));
return new(backing, offset + start, end - start);
}
// Materialization is intentional at persistent token/AST/public boundaries.
// Raw-string compatibility projects Latin1 byte characters; byte source
// consumers use spans instead. Unicode decoding is a separate explicit API.
public string Materialize() => GoString.FromBytes(AsSpan());
internal string DecodeUnicode() => System.Text.Encoding.UTF8.GetString(AsSpan());
internal byte[] ToArray() => AsSpan().ToArray();
public string Substring(int start, int length)
{
if ((uint)start > (uint)Length || (uint)length > (uint)(Length - start))
throw new ArgumentOutOfRangeException(nameof(start));
return Slice(start, start + length).Materialize();
}
}