From 533403ce33f428aed7795afcb8f30cadea8a80e3 Mon Sep 17 00:00:00 2001 From: Pavel Koneski Date: Sun, 10 May 2026 22:07:42 -0700 Subject: [PATCH 1/2] Rely on first-class span conversions of C# 14 --- src/core/IronPython/Hosting/PythonOptionsParser.cs | 4 ++-- src/core/IronPython/Modules/_io/StringIO.cs | 4 ++-- src/core/IronPython/Runtime/LiteralParser.cs | 4 ++-- src/core/IronPython/Runtime/Operations/PythonOps.cs | 4 ---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/core/IronPython/Hosting/PythonOptionsParser.cs b/src/core/IronPython/Hosting/PythonOptionsParser.cs index 277f0847a..9aee202e4 100644 --- a/src/core/IronPython/Hosting/PythonOptionsParser.cs +++ b/src/core/IronPython/Hosting/PythonOptionsParser.cs @@ -150,12 +150,12 @@ protected override void ParseArgument(string/*!*/ arg) { } if (arg == "/?" || arg == "--help") { - HandleOptions("h".AsSpan()); + HandleOptions("h"); return; } if (arg == "--version") { - HandleOptions("V".AsSpan()); + HandleOptions("V"); return; } diff --git a/src/core/IronPython/Modules/_io/StringIO.cs b/src/core/IronPython/Modules/_io/StringIO.cs index 1b67ed0fc..4c9cc2441 100644 --- a/src/core/IronPython/Modules/_io/StringIO.cs +++ b/src/core/IronPython/Modules/_io/StringIO.cs @@ -114,7 +114,7 @@ private string readline(int limit) { span = span.Slice(0, idx + 1); } } else if (_newline == string.Empty) { - var idx = span.IndexOfAny("\r\n".AsSpan()); + var idx = span.IndexOfAny("\r\n"); if (idx != -1) { if (span[idx++] == '\r') { // ensure we don't split \r\n @@ -377,7 +377,7 @@ private int DoWrite(string str) { if (_newline is null) { while (true) { - var idx = span.IndexOfAny("\r\n".AsSpan()); + var idx = span.IndexOfAny("\r\n"); if (idx == -1) break; diff --git a/src/core/IronPython/Runtime/LiteralParser.cs b/src/core/IronPython/Runtime/LiteralParser.cs index 1ef1adb68..24ac94dfa 100644 --- a/src/core/IronPython/Runtime/LiteralParser.cs +++ b/src/core/IronPython/Runtime/LiteralParser.cs @@ -219,7 +219,7 @@ void handleError(in ReadOnlySpan data, int start, int end, string reason) { #nullable enable private static bool TryParseExpression(Parser parser, ReadOnlySpan data, [NotNullWhen(true)] out Expression? expression, [NotNullWhen(false)] out string? error) { - if (data.TrimStart(" \t\f\r\n".AsSpan()).Length == 0) { + if (data.TrimStart(" \t\f\r\n").Length == 0) { expression = null; error = "f-string: empty expression not allowed"; return false; @@ -649,7 +649,7 @@ private static bool TryParseInt(in ReadOnlySpan text, int start, int lengt } public static object ParseInteger(string text, int b) { - if (TryParseInteger(text.AsSpan(), b, false, out object val)) { + if (TryParseInteger(text, b, false, out object val)) { return val; } throw new ValueErrorException($"invalid literal with base {b}: {text}"); diff --git a/src/core/IronPython/Runtime/Operations/PythonOps.cs b/src/core/IronPython/Runtime/Operations/PythonOps.cs index e1e6f9a7b..42c7744fb 100644 --- a/src/core/IronPython/Runtime/Operations/PythonOps.cs +++ b/src/core/IronPython/Runtime/Operations/PythonOps.cs @@ -3689,10 +3689,6 @@ internal static string MakeString(this IList bytes, int startIdx, int maxB return StringOps.Latin1Encoding.GetString(byteArr, startIdx, maxBytes); } - internal static string MakeString(this Span bytes) { - return MakeString((ReadOnlySpan)bytes); - } - internal static string MakeString(this ReadOnlySpan bytes) { if (bytes.IsEmpty) { return string.Empty; From e8f5ed0b40d4ea453488ccc077c346a16ddbc023 Mon Sep 17 00:00:00 2001 From: Pavel Koneski Date: Sun, 10 May 2026 22:18:12 -0700 Subject: [PATCH 2/2] Optimize use of Span in Bytes --- src/core/IronPython/Runtime/Bytes.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/IronPython/Runtime/Bytes.cs b/src/core/IronPython/Runtime/Bytes.cs index a04bfa7aa..43fb79ab1 100644 --- a/src/core/IronPython/Runtime/Bytes.cs +++ b/src/core/IronPython/Runtime/Bytes.cs @@ -375,7 +375,7 @@ public static object fromhex(CodeContext context, [NotNone] PythonType cls, [Not return PythonTypeOps.CallParams(context, cls, new Bytes(hex)); } - public string hex() => ToHex(_bytes.AsSpan()); // new in CPython 3.5 + public string hex() => ToHex(_bytes); // new in CPython 3.5 internal static string ToHex(ReadOnlySpan bytes) { if (bytes.Length == 0) return string.Empty; @@ -395,13 +395,13 @@ static char ToAscii(int b) { // new in CPython 3.8 public string hex([NotNone] string sep, int bytes_per_sep = 1) { if (sep.Length != 1) throw PythonOps.ValueError($"{nameof(sep)} must be length 1"); - return ToHex(_bytes.AsSpan(), sep[0], bytes_per_sep); + return ToHex(_bytes, sep[0], bytes_per_sep); } // new in CPython 3.8 public string hex([BytesLike, NotNone] IList sep, int bytes_per_sep = 1) { if (sep.Count != 1) throw PythonOps.ValueError($"{nameof(sep)} must be length 1"); - return ToHex(_bytes.AsSpan(), (char)sep[0], bytes_per_sep); + return ToHex(_bytes, (char)sep[0], bytes_per_sep); } internal static string ToHex(ReadOnlySpan bytes, char sep, int bytes_per_sep) { @@ -1077,9 +1077,9 @@ public int this[object? index] { #region Implementation Details - internal ReadOnlyMemory AsMemory() => _bytes.AsMemory(); + internal ReadOnlyMemory AsMemory() => _bytes; - internal ReadOnlySpan AsSpan() => _bytes.AsSpan(); + internal ReadOnlySpan AsSpan() => _bytes; internal static bool TryInvokeBytesOperator(CodeContext context, object? obj, [NotNullWhen(true)] out Bytes? bytes) { if (PythonTypeOps.TryInvokeUnaryOperator(context, obj, "__bytes__", out object? res)) {