• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

neon-sunset / U8String / 6005208900

28 Aug 2023 09:36PM UTC coverage: 18.096% (-0.2%) from 18.326%
6005208900

push

github

neon-sunset
feat: Extend NativeU8String and restructure solution to account for increased line count, add roadmap draft

134 of 1050 branches covered (0.0%)

Branch coverage included in aggregate %.

1058 of 1058 new or added lines in 25 files covered. (100.0%)

478 of 2332 relevant lines covered (20.5%)

35305.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

13.46
/src/Implementations/Standard/U8String.Conversions.cs
1
using System.Diagnostics.CodeAnalysis;
2
using System.Runtime.InteropServices;
3
using System.Text;
4

5
namespace U8Primitives;
6

7
#pragma warning disable RCS1206, IDE0057 // Simplify conditional and slice expressions. Why: codegen quality.
8
public readonly partial struct U8String
9
{
10
    /// <summary>
11
    /// Returns a <see cref="ReadOnlySpan{T}"/> view of the current <see cref="U8String"/>.
12
    /// </summary>
13
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
14
    public ReadOnlySpan<byte> AsSpan()
15
    {
16
        // The code below is written in a way that allows JIT/ILC to optimize
17
        // byte[]? reference assignment to a csel/cmov, eliding the branch conditional.
18
        // Worst case, if it is not elided, it will be a predicted forward branch.
19
        var (value, offset, length) = this;
2,044✔
20
        ref var reference = ref Unsafe.NullRef<byte>();
2,044✔
21
        if (value != null) reference = ref MemoryMarshal.GetArrayDataReference(value);
4,088✔
22
        reference = ref Unsafe.Add(ref reference, offset);
2,044✔
23
        return MemoryMarshal.CreateReadOnlySpan(ref reference, length);
2,044✔
24
    }
25

26
    ///<summary>
27
    /// Returns a <see cref="ReadOnlySpan{T}"/> view of the current <see cref="U8String"/> starting at the specified index.
28
    /// </summary>
29
    /// <param name="start">The index to start at.</param>
30
    /// <exception cref="ArgumentOutOfRangeException">
31
    /// Thrown when <paramref name="start"/> is less than zero or greater than <see cref="Length"/>.
32
    /// </exception>
33
    // Codegen for the overloads below would probably be garbage, which is ok for now.
34
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
35
    public ReadOnlySpan<byte> AsSpan(int start)
36
    {
37
        return AsSpan().Slice(start);
×
38
    }
39

40
    ///<summary>
41
    /// Returns a <see cref="ReadOnlySpan{T}"/> view of the current <see cref="U8String"/>
42
    /// starting at the specified index and of the specified length.
43
    /// </summary>
44
    /// <param name="start">The index to start at.</param>
45
    /// <param name="length">The length of the span.</param>
46
    /// <exception cref="ArgumentOutOfRangeException">
47
    /// Thrown when either <paramref name="start"/> or <paramref name="length"/> is out of bounds.
48
    /// </exception>
49
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
50
    public ReadOnlySpan<byte> AsSpan(int start, int length)
51
    {
52
        return AsSpan().Slice(start, length);
×
53
    }
54

55
    /// <summary>
56
    /// Returns a <see cref="ReadOnlyMemory{T}"/> view of the current <see cref="U8String"/>.
57
    /// </summary>
58
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
59
    public ReadOnlyMemory<byte> AsMemory()
60
    {
61
        return _value != null ? _value.AsMemory(Offset, Length) : default;
×
62
    }
63

64
    /// <inheritdoc cref="TryParse(ReadOnlySpan{char}, IFormatProvider?, out U8String)"/>
65
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
66
    public static U8String Parse(string s, IFormatProvider? provider = null)
67
    {
68
        return Parse(s.AsSpan(), provider);
×
69
    }
70

71
    /// <inheritdoc cref="TryParse(ReadOnlySpan{char}, IFormatProvider?, out U8String)"/>
72
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
73
    public static U8String Parse(ReadOnlySpan<char> s, IFormatProvider? provider = null)
74
    {
75
        // TODO: Decide when/how TryParse could fail, factor in the required codegen shape
76
        // to skip CNS string decoding after https://github.com/dotnet/runtime/pull/85328 lands.
77
        _ = TryParse(s, provider, out var result);
×
78
        return result;
×
79
    }
80

81
    /// <summary>
82
    /// Creates a <see cref="U8String"/> from the specified <paramref name="utf8Text"/>.
83
    /// </summary>
84
    /// <param name="utf8Text">The UTF-8 encoded text to create a <see cref="U8String"/> from.</param>
85
    /// <param name="provider">Defined by <see cref="ISpanParsable{U8String}"/> but not applicable to this type.</param>
86
    /// <returns>A new <see cref="U8String"/> created from <paramref name="utf8Text"/>.</returns>
87
    /// <exception cref="ArgumentException"> Thrown when <paramref name="utf8Text"/> contains invalid UTF-8.</exception>
88
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
89
    public static U8String Parse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider = null)
90
    {
91
        if (!TryParse(utf8Text, provider, out var result))
×
92
        {
93
            ThrowHelpers.InvalidUtf8();
×
94
        }
95

96
        return result;
×
97
    }
98

99
    /// <inheritdoc cref="TryParse(ReadOnlySpan{char}, IFormatProvider?, out U8String)"/>
100
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
101
    public static bool TryParse(
102
        [NotNullWhen(true)] string? s,
103
        IFormatProvider? provider,
104
        [MaybeNullWhen(false)] out U8String result) => TryParse(s.AsSpan(), provider, out result);
×
105

106
    /// <summary>
107
    /// Decodes the specified <paramref name="s"/> into a <see cref="U8String"/>.
108
    /// </summary>
109
    /// <param name="s">The UTF-16 encoded string to decode.</param>
110
    /// <param name="provider">Defined by <see cref="ISpanParsable{U8String}"/> but not applicable to this type.</param>
111
    /// <param name="result">The decoded <see cref="U8String"/>.</param>
112
    /// <returns>True if the <paramref name="s"/> was successfully decoded, otherwise false.</returns>
113
    public static bool TryParse(
114
        ReadOnlySpan<char> s,
115
        IFormatProvider? provider,
116
        out U8String result)
117
    {
118
        // Double traversal becomes the favourable tradeoff at longer lengths,
119
        // and at shorter lengths the overhead is negligible.
120
        var length = Encoding.UTF8.GetByteCount(s);
×
121
        var value = new byte[length];
×
122

123
        if (Encoding.UTF8.TryGetBytes(s, value, out var bytesWritten))
×
124
        {
125
            result = new U8String(value, 0, bytesWritten);
×
126
            return true;
×
127
        }
128

129
        result = default;
×
130
        return false;
×
131
    }
132

133
    /// <summary>
134
    /// Creates a <see cref="U8String"/> from the specified <paramref name="utf8Text"/>.
135
    /// </summary>
136
    /// <param name="utf8Text">The UTF-8 encoded text to create a <see cref="U8String"/> from.</param>
137
    /// <param name="provider">Defined by <see cref="ISpanParsable{U8String}"/> but not applicable to this type.</param>
138
    /// <param name="result">A new <see cref="U8String"/> created from <paramref name="utf8Text"/>.</param>
139
    /// <returns>True if the <paramref name="utf8Text"/> contains well-formed UTF-8, otherwise false.</returns>
140
    public static bool TryParse(
141
        ReadOnlySpan<byte> utf8Text,
142
        IFormatProvider? provider,
143
        out U8String result)
144
    {
145
        if (IsValid(utf8Text))
×
146
        {
147
            result = new U8String(utf8Text, skipValidation: true);
×
148
            return true;
×
149
        }
150

151
        result = default;
×
152
        return false;
×
153
    }
154

155
    /// <summary>
156
    /// Encodes the current <see cref="U8String"/> into its UTF-16 representation and writes it to the specified <paramref name="destination"/>.
157
    /// </summary>
158
    /// <param name="destination">The destination to write the UTF-16 representation to.</param>
159
    /// <param name="charsWritten">The number of characters written to <paramref name="destination"/>.</param>
160
    /// <param name="format">Defined by <see cref="ISpanFormattable"/> but not applicable to this type.</param>
161
    /// <param name="provider">Defined by <see cref="ISpanFormattable"/> but not applicable to this type.</param>
162
    /// <returns>True if the UTF-16 representation was successfully written to <paramref name="destination"/>, otherwise false.</returns>
163
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
164
    public bool TryFormat(
165
        Span<char> destination,
166
        out int charsWritten,
167
        ReadOnlySpan<char> format,
168
        IFormatProvider? provider)
169
    {
170
        return Encoding.UTF8.TryGetChars(this, destination, out charsWritten);
×
171
    }
172

173
    /// <inheritdoc />
174
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
175
    public bool TryFormat(
176
        Span<byte> utf8Destination,
177
        out int bytesWritten,
178
        ReadOnlySpan<char> format,
179
        IFormatProvider? provider)
180
    {
181
        var length = Length;
×
182
        if (length <= utf8Destination.Length)
×
183
        {
184
            AsSpan().CopyTo(utf8Destination);
×
185
            bytesWritten = length;
×
186
            return true;
×
187
        }
188

189
        bytesWritten = 0;
×
190
        return false;
×
191
    }
192

193
    /// <summary>
194
    /// Returns a <see cref="byte"/> array containing the current <see cref="U8String"/>'s bytes.
195
    /// </summary>
196
    /// <returns>A new <see cref="byte"/> array to which the current <see cref="U8String"/>'s bytes were copied.</returns>
197
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
198
    public byte[] ToArray() => AsSpan().ToArray();
×
199

200
    /// <inheritdoc cref="ToString()"/>
201
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
202
    public string ToString(string? format, IFormatProvider? formatProvider) => ToString();
×
203

204
    /// <summary>
205
    /// Encodes the current <see cref="U8String"/> into its UTF-16 <see cref="string"/> representation.
206
    /// </summary>
207
    public override string ToString()
208
    {
209
        return _value != null ? Encoding.UTF8.GetString(this) : string.Empty;
×
210
    }
211
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc