using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; readonly struct QueryStringEnumerable { private readonly ReadOnlyMemory queryString; public QueryStringEnumerable(string? queryString) : this(queryString.AsMemory()) { } public QueryStringEnumerable(ReadOnlyMemory queryString) { this.queryString = queryString; } public Enumerator GetEnumerator() => new(queryString); public readonly struct EncodedNameValuePair { internal EncodedNameValuePair(ReadOnlyMemory encodedName, ReadOnlyMemory encodedValue) { EncodedName = encodedName; EncodedValue = encodedValue; } public readonly ReadOnlyMemory EncodedName { get; } public readonly ReadOnlyMemory EncodedValue { get; } public ReadOnlyMemory DecodeName() => Decode(EncodedName); public ReadOnlyMemory DecodeValue() => Decode(EncodedValue); private static ReadOnlyMemory Decode(ReadOnlyMemory chars) { return chars.Length < 16 && chars.Span.IndexOfAny('%', '+') < 0 ? chars : Uri.UnescapeDataString(SpanHelper.ReplacePlusWithSpace(chars.Span)).AsMemory(); } } public struct Enumerator { private ReadOnlyMemory query; internal Enumerator(ReadOnlyMemory query) { Current = default; this.query = query.IsEmpty || query.Span[0] != '?' ? query : query[1..]; } public EncodedNameValuePair Current { get; private set; } public bool MoveNext() { while (!query.IsEmpty) { ReadOnlyMemory segment; var delimiterIndex = query.Span.IndexOf('&'); if (delimiterIndex >= 0) { segment = query[..delimiterIndex]; query = query[(delimiterIndex + 1)..]; } else { segment = query; query = default; } int equalIndex = segment.Span.IndexOf('='); if (equalIndex >= 0) { Current = new EncodedNameValuePair(segment[..equalIndex], segment[(equalIndex + 1)..]); return true; } else if (!segment.IsEmpty) { Current = new EncodedNameValuePair(segment, default); return true; } } Current = default; return false; } } private static class SpanHelper { private static readonly SpanAction replacePlusWithSpace = ReplacePlusWithSpaceCore; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe string ReplacePlusWithSpace(ReadOnlySpan span) { fixed (char* ptr = &MemoryMarshal.GetReference(span)) { return string.Create(span.Length, (IntPtr)ptr, replacePlusWithSpace); } } private static unsafe void ReplacePlusWithSpaceCore(Span buffer, IntPtr state) { fixed (char* ptr = &MemoryMarshal.GetReference(buffer)) { ushort* input = (ushort*)state.ToPointer(); ushort* output = (ushort*)ptr; nint i = 0; nint n = (nint)(uint)buffer.Length; if (Vector256.IsHardwareAccelerated && n >= Vector256.Count) { Vector256 vecPlus = Vector256.Create((ushort)'+'); Vector256 vecSpace = Vector256.Create((ushort)' '); do { Vector256 vec = Vector256.Load(input + i); Vector256 mask = Vector256.Equals(vec, vecPlus); Vector256 res = Vector256.ConditionalSelect(mask, vecSpace, vec); res.Store(output + i); i += Vector256.Count; } while (i <= n - Vector256.Count); } if (Vector128.IsHardwareAccelerated && n - i >= Vector128.Count) { do { Vector128 vec = Vector128.Load(input + i); Vector128 vecPlus = Vector128.Create((ushort)'+'); Vector128 mask = Vector128.Equals(vec, vecPlus); Vector128 vecSpace = Vector128.Create((ushort)' '); Vector128 res = Vector128.ConditionalSelect(mask, vecSpace, vec); res.Store(output + i); i += Vector128.Count; } while (i <= n - Vector128.Count); } for (; i < n; ++i) { if (input[i] != '+') { output[i] = input[i]; } else { output[i] = ' '; } } } } } }