• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Build has been canceled!

neon-sunset / U8String / 5913123732

19 Aug 2023 07:18PM UTC coverage: 22.694% (+0.009%) from 22.685%
5913123732

push

github

neon-sunset
style: clean up enumerators

122 of 776 branches covered (15.72%)

Branch coverage included in aggregate %.

3 of 3 new or added lines in 1 file covered. (100.0%)

439 of 1696 relevant lines covered (25.88%)

30126.83 hits per line

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

0.0
/src/U8String.Splitting.cs
1
using System.Collections;
2
using System.Runtime.InteropServices;
3
using System.Text;
4
using U8Primitives.Abstractions;
5
using U8Primitives.InteropServices;
6

7
#pragma warning disable RCS1085, RCS1085FadeOut, IDE0032 // Use auto-implemented property. Why: readable fields.
8
namespace U8Primitives;
9

10
public readonly partial struct U8String
11
{
12
    public U8SplitPair SplitFirst(byte separator)
13
    {
14
        if (!U8Info.IsAsciiByte(separator))
×
15
        {
16
            // TODO: EH UX
17
            ThrowHelpers.ArgumentOutOfRange();
×
18
        }
19

20
        var source = this;
×
21
        if (!source.IsEmpty)
×
22
        {
23
            var span = source.UnsafeSpan;
×
24
            var index = span.IndexOf(separator);
×
25
            if (index >= 0)
×
26
            {
27
                return new(source, index, 1);
×
28
            }
29

30
            return U8SplitPair.NotFound(source);
×
31
        }
32

33
        return default;
×
34
    }
35

36
    public U8SplitPair SplitFirst(char separator) => char.IsAscii(separator)
×
37
        ? SplitFirst((byte)separator)
×
38
        : SplitFirstUnchecked(separator.NonAsciiToUtf8(out _));
×
39

40
    public U8SplitPair SplitFirst(Rune separator) => separator.IsAscii
×
41
        ? SplitFirst((byte)separator.Value)
×
42
        : SplitFirstUnchecked(separator.NonAsciiToUtf8(out _));
×
43

44
    public U8SplitPair SplitFirst(U8String separator)
45
    {
46
        var source = this;
×
47
        if (!source.IsEmpty)
×
48
        {
49
            if (!separator.IsEmpty)
×
50
            {
51
                var span = source.UnsafeSpan;
×
52
                var index = span.IndexOf(separator.UnsafeSpan);
×
53
                if (index >= 0)
×
54
                {
55
                    return new(source, index, separator.Length);
×
56
                }
57
            }
58

59
            return U8SplitPair.NotFound(source);
×
60
        }
61

62
        return default;
×
63
    }
64

65
    // It would be *really nice* to aggressively inline this method
66
    // but the way validation is currently implemented does not significantly
67
    // benefit from splitting on UTF-8 literals while possibly risking
68
    // running out of inlining budget significantly regressing performance everywhere else.
69
    public U8SplitPair SplitFirst(ReadOnlySpan<byte> separator)
70
    {
71
        var source = this;
×
72
        if (!source.IsEmpty)
×
73
        {
74
            if (!separator.IsEmpty)
×
75
            {
76
                var span = source.UnsafeSpan;
×
77
                var index = span.IndexOf(separator);
×
78
                if (index >= 0)
×
79
                {
80
                    // Same as with Slice(int, int), this might dereference past the end of the string.
81
                    // TODO: Do something about it if it's ever an issue.
82
                    if (U8Info.IsContinuationByte(source.UnsafeRefAdd(index)) ||
×
83
                        U8Info.IsContinuationByte(source.UnsafeRefAdd(index + separator.Length)))
×
84
                    {
85
                        ThrowHelpers.InvalidSplit();
×
86
                    }
87

88
                    return new(source, index, separator.Length);
×
89
                }
90
            }
91

92
            return U8SplitPair.NotFound(source);
×
93
        }
94

95
        return default;
×
96
    }
97

98
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
99
    public U8SplitPair SplitFirstUnchecked(ReadOnlySpan<byte> separator)
100
    {
101
        var source = this;
×
102
        if (!source.IsEmpty)
×
103
        {
104
            if (!separator.IsEmpty)
×
105
            {
106
                var span = source.UnsafeSpan;
×
107
                var index = span.IndexOf(separator);
×
108
                if (index >= 0)
×
109
                {
110
                    return new(source, index, separator.Length);
×
111
                }
112
            }
113

114
            return U8SplitPair.NotFound(source);
×
115
        }
116

117
        return default;
×
118
    }
119

120
    public U8SplitPair SplitLast(byte separator)
121
    {
122
        if (!U8Info.IsAsciiByte(separator))
×
123
        {
124
            // TODO: EH UX
125
            ThrowHelpers.ArgumentOutOfRange();
×
126
        }
127

128
        var source = this;
×
129
        if (!source.IsEmpty)
×
130
        {
131
            var span = source.UnsafeSpan;
×
132
            var index = span.LastIndexOf(separator);
×
133
            if (index >= 0)
×
134
            {
135
                return new(source, index, 1);
×
136
            }
137

138
            return U8SplitPair.NotFound(source);
×
139
        }
140

141
        return default;
×
142
    }
143

144
    public U8SplitPair SplitLast(char separator) => char.IsAscii(separator)
×
145
        ? SplitLast((byte)separator)
×
146
        : SplitLastUnchecked(separator.NonAsciiToUtf8(out _));
×
147

148
    public U8SplitPair SplitLast(Rune separator) => separator.IsAscii
×
149
        ? SplitLast((byte)separator.Value)
×
150
        : SplitLastUnchecked(separator.NonAsciiToUtf8(out _));
×
151

152
    public U8SplitPair SplitLast(U8String separator)
153
    {
154
        var source = this;
×
155
        if (!source.IsEmpty)
×
156
        {
157
            if (!separator.IsEmpty)
×
158
            {
159
                var span = source.UnsafeSpan;
×
160
                var index = span.LastIndexOf(separator.UnsafeSpan);
×
161
                if (index >= 0)
×
162
                {
163
                    return new(source, index, separator.Length);
×
164
                }
165
            }
166

167
            return U8SplitPair.NotFound(source);
×
168
        }
169

170
        return default;
×
171
    }
172

173
    public U8SplitPair SplitLast(ReadOnlySpan<byte> separator)
174
    {
175
        var source = this;
×
176
        if (!source.IsEmpty)
×
177
        {
178
            if (!separator.IsEmpty)
×
179
            {
180
                var span = source.UnsafeSpan;
×
181
                var index = span.LastIndexOf(separator);
×
182
                if (index >= 0)
×
183
                {
184
                    if (U8Info.IsContinuationByte(source.UnsafeRefAdd(index)) ||
×
185
                        U8Info.IsContinuationByte(source.UnsafeRefAdd(index + separator.Length)))
×
186
                    {
187
                        ThrowHelpers.InvalidSplit();
×
188
                    }
189

190
                    return new(source, index, separator.Length);
×
191
                }
192
            }
193

194
            return U8SplitPair.NotFound(source);
×
195
        }
196

197
        return default;
×
198
    }
199

200
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
201
    public U8SplitPair SplitLastUnchecked(ReadOnlySpan<byte> separator)
202
    {
203
        var source = this;
×
204
        if (!source.IsEmpty)
×
205
        {
206
            if (!separator.IsEmpty)
×
207
            {
208
                var span = source.UnsafeSpan;
×
209
                var index = span.LastIndexOf(separator);
×
210
                if (index >= 0)
×
211
                {
212
                    return new(source, index, separator.Length);
×
213
                }
214
            }
215

216
            return U8SplitPair.NotFound(source);
×
217
        }
218

219
        return default;
×
220
    }
221

222
    public U8Split<byte> Split(byte separator)
223
    {
224
        if (!U8Info.IsAsciiByte(separator))
×
225
        {
226
            ThrowHelpers.ArgumentOutOfRange();
×
227
        }
228

229
        return new(this, separator);
×
230
    }
231

232
    public ConfiguredU8Split<byte> Split(byte separator, U8SplitOptions options)
233
    {
234
        if (!U8Info.IsAsciiByte(separator))
×
235
        {
236
            ThrowHelpers.ArgumentOutOfRange();
×
237
        }
238

239
        return new(this, separator, options);
×
240
    }
241

242
    public U8Split<char> Split(char separator)
243
    {
244
        if (char.IsSurrogate(separator))
×
245
        {
246
            ThrowHelpers.ArgumentOutOfRange();
×
247
        }
248

249
        return new(this, separator);
×
250
    }
251

252
    public ConfiguredU8Split<char> Split(char separator, U8SplitOptions options)
253
    {
254
        if (char.IsSurrogate(separator))
×
255
        {
256
            ThrowHelpers.ArgumentOutOfRange();
×
257
        }
258

259
        return new(this, separator, options);
×
260
    }
261

262
    public U8Split<Rune> Split(Rune separator) => new(this, separator);
×
263

264
    public ConfiguredU8Split<Rune> Split(Rune separator, U8SplitOptions options) => new(this, separator, options);
×
265

266
    public U8Split Split(U8String separator)
267
    {
268
        return !separator.IsEmpty ? new(this, separator) : default;
×
269
    }
270

271
    public ConfiguredU8Split<U8String> Split(U8String separator, U8SplitOptions options)
272
    {
273
        return !separator.IsEmpty ? new(this, separator, options) : default;
×
274
    }
275

276
    public U8Split<byte[]> Split(byte[] separator)
277
    {
278
        if (!IsValid(separator))
×
279
        {
280
            // TODO: EH UX
281
            ThrowHelpers.InvalidSplit();
×
282
        }
283

284
        var source = this;
×
285
        return (!source.IsEmpty && separator != null) ? new(source, separator) : default;
×
286
    }
287

288
    public ConfiguredU8Split<byte[]> Split(byte[] separator, U8SplitOptions options)
289
    {
290
        if (!IsValid(separator))
×
291
        {
292
            // TODO: EH UX
293
            ThrowHelpers.InvalidSplit();
×
294
        }
295

296
        var source = this;
×
297
        return (!source.IsEmpty && separator != null) ? new(source, separator, options) : default;
×
298
    }
299
}
300

301
public readonly record struct U8SplitPair
302
{
303
    readonly U8String _value;
304
    readonly int _offset;
305
    readonly int _stride;
306

307
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
308
    internal U8SplitPair(U8String value, int offset, int stride)
309
    {
310
        _value = value;
×
311
        _offset = offset;
×
312
        _stride = stride;
×
313
    }
×
314

315
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
316
    public static U8SplitPair NotFound(U8String value)
317
    {
318
        return new(value, value.Length, 0);
×
319
    }
320

321
    public U8String Segment
322
    {
323
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
324
        get => U8Marshal.Slice(_value, 0, _offset);
×
325
    }
326

327
    public U8String Remainder
328
    {
329
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
330
        get => U8Marshal.Slice(_value, _offset + _stride);
×
331
    }
332

333
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
334
    public void Deconstruct(out U8String segment, out U8String remainder)
335
    {
336
        segment = Segment;
×
337
        remainder = Remainder;
×
338
    }
×
339

340
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
341
    public static implicit operator (U8String, U8String)(U8SplitPair value)
342
    {
343
        return (value.Segment, value.Remainder);
×
344
    }
345
}
346

347
public struct U8Split : ICollection<U8String>, IU8Enumerable<U8Split.Enumerator>
348
{
349
    readonly U8String _value;
350
    readonly U8String _separator;
351
    int _count;
352

353
    internal U8Split(U8String value, U8String separator)
354
    {
355
        _value = value;
×
356
        _separator = separator;
×
357
        _count = value.IsEmpty ? 0 : -1;
×
358
    }
×
359

360
    public int Count
361
    {
362
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
363
        get
364
        {
365
            var count = _count;
×
366
            if (count >= 0)
×
367
            {
368
                return count;
×
369
            }
370

371
            // Matches the behavior of string.Split('\n').Length for "hello\n"
372
            // TODO: Should we break consistency and not count the very last segment if it is empty?
373
            return _count = Count(_value.UnsafeSpan, _separator) + 1;
×
374

375
            static int Count(ReadOnlySpan<byte> value, ReadOnlySpan<byte> separator)
376
            {
377
                return U8Searching.Count(value, separator);
×
378
            }
379
        }
380
    }
381

382
    public readonly bool Contains(U8String item)
383
    {
384
        var separator = _separator;
×
385
        var overlaps = item.Contains(separator);
×
386

387
        return !overlaps && _value.Contains(item);
×
388
    }
389

390
    public void CopyTo(U8String[] array, int index)
391
    {
392
        this.CopyTo<U8Split, Enumerator, U8String>(array.AsSpan()[index..]);
×
393
    }
×
394

395
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
396
    public readonly void Deconstruct(out U8String first, out U8String second)
397
    {
398
        this.Deconstruct<U8Split, Enumerator, U8String>(out first, out second);
×
399
    }
×
400

401
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
402
    public readonly void Deconstruct(out U8String first, out U8String second, out U8String third)
403
    {
404
        this.Deconstruct<U8Split, Enumerator, U8String>(out first, out second, out third);
×
405
    }
×
406

407
    public U8String[] ToArray() => this.ToArray<U8Split, Enumerator, U8String>();
×
408
    public List<U8String> ToList() => this.ToList<U8Split, Enumerator, U8String>();
×
409

410
    /// <summary>
411
    /// Returns a <see cref="Enumerator"/> over the provided string.
412
    /// </summary>
413
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
414
    public readonly Enumerator GetEnumerator() => new(_value, _separator);
×
415

416
    readonly IEnumerator<U8String> IEnumerable<U8String>.GetEnumerator() => GetEnumerator();
×
417
    readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
×
418
    readonly bool ICollection<U8String>.IsReadOnly => true;
×
419

420
    public struct Enumerator : IU8Enumerator
421
    {
422
        readonly byte[]? _value;
423
        readonly U8String _separator;
424
        U8Range _current;
425
        U8Range _remaining;
426

427
        internal Enumerator(U8String value, U8String separator)
428
        {
429
            _value = value._value;
×
430
            _separator = separator;
×
431
            _remaining = value._inner;
×
432
        }
×
433

434
        public readonly U8String Current => new(_value, _current.Offset, _current.Length);
×
435

436
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
437
        public bool MoveNext()
438
        {
439
            var remaining = _remaining;
×
440
            if (remaining.Length > 0)
×
441
            {
442
                var value = _value!.SliceUnsafe(remaining.Offset, remaining.Length);
×
443
                var separator = _separator;
×
444
                var index = value.IndexOf(separator.UnsafeSpan);
×
445
                if (index >= 0)
×
446
                {
447
                    _current = new(remaining.Offset, index);
×
448
                    _remaining = new(
×
449
                        remaining.Offset + index + separator.Length,
×
450
                        remaining.Length - index - separator.Length);
×
451
                }
452
                else
453
                {
454
                    _current = remaining;
×
455
                    _remaining = default;
×
456
                }
457

458
                return true;
×
459
            }
460

461
            return false;
×
462
        }
463

464
        readonly object IEnumerator.Current => Current;
×
465
        readonly void IEnumerator.Reset() => throw new NotSupportedException();
×
466
        readonly void IDisposable.Dispose() { }
×
467
    }
468

469
    readonly void ICollection<U8String>.Add(U8String item) => throw new NotSupportedException();
×
470
    readonly void ICollection<U8String>.Clear() => throw new NotSupportedException();
×
471
    readonly bool ICollection<U8String>.Remove(U8String item) => throw new NotSupportedException();
×
472
}
473

474
// TODO: Optimize even more. This design is far from the northstar of perfect codegen
475
// but it still somehow manages to outperform Rust split iterators
476
public struct U8Split<TSeparator> :
477
    ICollection<U8String>,
478
    IU8Enumerable<U8Split<TSeparator>.Enumerator>
479
{
480
    readonly U8String _value;
481
    readonly TSeparator? _separator;
482
    int _count;
483

484
    // TODO: validate/guard against unsupported generic instantiations
485
    // e.g.: foreach (var e in default(U8Split<object[]>)) must throw or at least not produce UB
486
    // Possible solution: just make the T -> byte[] cast throwing instead of reinterpret,
487
    // paying the price for splitting on boxed byte sequences which are not U8String.
488
    // This can be further mitigated by introducing proper U8RefSplit for splitting on
489
    // UTF-8 literals and other sources of ROS<byte> without forcing reallocation due to lifetime constraints.
490
    internal U8Split(U8String value, TSeparator? separator)
491
    {
492
        _value = value;
×
493
        _separator = separator;
×
494
        _count = value.IsEmpty ? 0 : -1;
×
495
    }
×
496

497
    public int Count
498
    {
499
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
500
        get
501
        {
502
            var count = _count;
×
503
            if (count >= 0)
×
504
            {
505
                return count;
×
506
            }
507

508
            // Matches the behavior of string.Split('\n').Length for "hello\n"
509
            // TODO: Should we break consistency and not count the very last segment if it is empty?
510
            return _count = Count(_value, _separator) + 1;
×
511

512
            static int Count(ReadOnlySpan<byte> value, TSeparator? separator)
513
            {
514
                return U8Searching.Count(value, separator);
×
515
            }
516
        }
517
    }
518

519
    public readonly bool Contains(U8String item)
520
    {
521
        var separator = _separator;
×
522
        var overlaps = U8Searching.Contains(item, separator);
×
523

524
        return !overlaps && _value.Contains(item);
×
525
    }
526

527
    public void CopyTo(U8String[] array, int index)
528
    {
529
        this.CopyTo<U8Split<TSeparator>, Enumerator, U8String>(array.AsSpan()[index..]);
×
530
    }
×
531

532
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
533
    public readonly void Deconstruct(out U8String first, out U8String second)
534
    {
535
        this.Deconstruct<U8Split<TSeparator>, Enumerator, U8String>(out first, out second);
×
536
    }
×
537

538
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
539
    public readonly void Deconstruct(out U8String first, out U8String second, out U8String third)
540
    {
541
        this.Deconstruct<U8Split<TSeparator>, Enumerator, U8String>(out first, out second, out third);
×
542
    }
×
543

544
    public U8String[] ToArray() => this.ToArray<U8Split<TSeparator>, Enumerator, U8String>();
×
545
    public List<U8String> ToList() => this.ToList<U8Split<TSeparator>, Enumerator, U8String>();
×
546

547
    /// <summary>
548
    /// Returns a <see cref="Enumerator"/> over the provided string.
549
    /// </summary>
550
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
551
    public readonly Enumerator GetEnumerator() => new(_value, _separator);
×
552

553
    readonly IEnumerator<U8String> IEnumerable<U8String>.GetEnumerator() => GetEnumerator();
×
554
    readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
×
555
    readonly bool ICollection<U8String>.IsReadOnly => true;
×
556

557
    public struct Enumerator : IU8Enumerator
558
    {
559
        readonly byte[]? _value;
560
        readonly TSeparator? _separator;
561
        readonly U8Size _separatorSize;
562
        U8Range _current;
563
        U8Range _remaining;
564

565
        internal Enumerator(U8String value, TSeparator? separator)
566
        {
567
            _value = value._value;
×
568
            _separator = separator;
×
569
            _separatorSize = U8Info.GetSize(separator);
×
570
            _remaining = value._inner;
×
571
        }
×
572

573
        public readonly U8String Current => new(_value, _current.Offset, _current.Length);
×
574

575
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
576
        public bool MoveNext()
577
        {
578
            var remaining = _remaining;
×
579
            if (remaining.Length > 0)
×
580
            {
581
                var size = _separatorSize;
×
582
                var value = _value!.SliceUnsafe(remaining.Offset, remaining.Length);
×
583
                var index = U8Searching.IndexOf(value, _separator, size);
×
584
                if (index >= 0)
×
585
                {
586
                    _current = new(remaining.Offset, index);
×
587
                    _remaining = new(
×
588
                        remaining.Offset + index + (int)size,
×
589
                        remaining.Length - index - (int)size);
×
590
                }
591
                else
592
                {
593
                    _current = remaining;
×
594
                    _remaining = default;
×
595
                }
596

597
                return true;
×
598
            }
599

600
            return false;
×
601
        }
602

603
        readonly object IEnumerator.Current => Current;
×
604
        readonly void IEnumerator.Reset() => throw new NotSupportedException();
×
605
        readonly void IDisposable.Dispose() { }
×
606
    }
607

608
    readonly void ICollection<U8String>.Add(U8String item) => throw new NotSupportedException();
×
609
    readonly void ICollection<U8String>.Clear() => throw new NotSupportedException();
×
610
    readonly bool ICollection<U8String>.Remove(U8String item) => throw new NotSupportedException();
×
611
}
612

613
public readonly struct ConfiguredU8Split<TSeparator> :
614
    IU8Enumerable<ConfiguredU8Split<TSeparator>.Enumerator>
615
{
616
    readonly U8String _value;
617
    readonly TSeparator? _separator;
618
    readonly U8SplitOptions _options;
619

620
    internal ConfiguredU8Split(U8String value, TSeparator? separator, U8SplitOptions options)
621
    {
622
        _value = value;
×
623
        _separator = separator;
×
624
        _options = options;
×
625
    }
×
626

627
    public readonly Enumerator GetEnumerator() => new(_value, _separator, _options);
×
628

629
    readonly IEnumerator<U8String> IEnumerable<U8String>.GetEnumerator() => GetEnumerator();
×
630
    readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
×
631

632
    public struct Enumerator : IU8Enumerator
633
    {
634
        readonly byte[]? _value;
635
        readonly TSeparator? _separator;
636
        readonly U8Size _separatorSize;
637
        readonly U8SplitOptions _options;
638
        U8Range _current;
639
        U8Range _remaining;
640

641
        internal Enumerator(U8String value, TSeparator? separator, U8SplitOptions options)
642
        {
643
            _value = value._value;
×
644
            _separator = separator;
×
645
            _separatorSize = U8Info.GetSize(separator);
×
646
            _options = options;
×
647
            _remaining = value._inner;
×
648
        }
×
649

650
        public readonly U8String Current => new(_value, _current.Offset, _current.Length);
×
651

652
        // TODO: Not most efficient but it works for now
653
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
654
        public bool MoveNext()
655
        {
656
        Next:
657
            var remaining = _remaining;
×
658
            if (remaining.Length > 0)
×
659
            {
660
                var size = _separatorSize;
×
661
                var value = _value!.SliceUnsafe(remaining.Offset, remaining.Length);
×
662
                var index = U8Searching.IndexOf(value, _separator, size);
×
663
                if (index >= 0)
×
664
                {
665
                    _current = (_options & U8SplitOptions.Trim) != U8SplitOptions.Trim
×
666
                        ? new(remaining.Offset, index)
×
667
                        : TrimEntry(_value!, new(remaining.Offset, index));
×
668
                    _remaining = new(
×
669
                        remaining.Offset + index + (int)size,
×
670
                        remaining.Length - index - (int)size);
×
671
                }
672
                else
673
                {
674
                    _current = (_options & U8SplitOptions.Trim) != U8SplitOptions.Trim
×
675
                        ? remaining
×
676
                        : TrimEntry(_value!, remaining);
×
677
                    _remaining = default;
×
678
                }
679

680
                if ((_options & U8SplitOptions.RemoveEmpty) is U8SplitOptions.RemoveEmpty
×
681
                    && _current.Length is 0)
×
682
                {
683
                    goto Next;
684
                }
685

686
                return true;
×
687
            }
688

689
            return false;
×
690
        }
691

692
        private static U8Range TrimEntry(byte[] value, U8Range range)
693
        {
694
            // This could have been done better but works for now.
695
            return new U8String(value, range).Trim()._inner;
×
696
        }
697

698
        readonly object IEnumerator.Current => Current;
×
699
        readonly void IEnumerator.Reset() => throw new NotSupportedException();
×
700
        readonly void IDisposable.Dispose() { }
×
701
    }
702
}
703

704
// // TODO:
705
// public ref struct U8RefSplit
706
// {
707
//     readonly U8String _value;
708
//     readonly ReadOnlySpan<byte> _separator;
709
//     // Can't force JIT/ILC to emit proper layout here which is sad, and explicit layout ruins codegen
710
//     // int _count;
711
// }
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

© 2025 Coveralls, Inc