Span に拡張メソッドとして生えているOverlaps
メソッドが気になったので、簡単に確認してみる。
MemoryExtensions.Overlaps メソッド (System) | Microsoft Learn
このメソッドは、ある Span が別の Span とメモリ上で重なっているかを判定するもの。
まず、参照が違うものは当然false
。
var array = Enumerable.Range(0, 10).ToArray(); var array2 = Enumerable.Range(0, 10).ToArray(); var s1 = array.AsSpan(); var s2 = array2.AsSpan(); Console.WriteLine($"s1 ols s2: {s1.Overlaps(s2)}"); // s1 ols s2: False
ある Span と、そこからスライスした Span とは当然true
。
異なった Span でも、参照が同じで範囲が重なっていればきちんとtrue
が返る。
var s3 = s1[3..4]; Console.WriteLine($"s1 ols s3: {s1.Overlaps(s3)}"); var s4 = array.AsSpan(3, 2); Console.WriteLine($"s1 ols s4: {s1.Overlaps(s4)}"); // s1 ols s3: True // s1 ols s4: True
オフセットを得るためのオーバーロードもある。
var s5 = s1[3..5]; var s6 = s1[..2]; var s7 = s1[4..7]; Console.WriteLine($"s1 ols s5: {s1.Overlaps(s5, out var offset)}, {offset}"); Console.WriteLine($"s1 ols s6: {s1.Overlaps(s6, out offset)}, {offset}"); Console.WriteLine($"s1 ols s7: {s1.Overlaps(s7, out offset)}, {offset}"); Console.WriteLine($"s5 ols s1: {s5.Overlaps(s1, out offset)}, {offset}"); Console.WriteLine($"s5 ols s6: {s5.Overlaps(s6, out offset)}, {offset}"); Console.WriteLine($"s5 ols s7: {s5.Overlaps(s7, out offset)}, {offset}"); // s1 ols s5: True, 3 // s1 ols s6: True, 0 // s1 ols s7: True, 4 // s5 ols s1: True, -3 // s5 ols s6: False, 0 // s5 ols s7: True, 1
処理の中身としては、Span 同士のバイトオフセットを取って、Span の長さと型のサイズを乗算したものと較べて判断している。
参考:Source Browser
public static unsafe bool Overlaps<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other) { if (span.IsEmpty || other.IsEmpty) { return false; } nint byteOffset = Unsafe.ByteOffset( ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other)); return (nuint)byteOffset < (nuint)((nint)span.Length * sizeof(T)) || (nuint)byteOffset > (nuint)(-((nint)other.Length * sizeof(T))); }
標準ライブラリ内では、例えばReadOnlySpan<char>.ToLower(Span<T>, CultureInfo?)
メソッドで、対象 ReadOnlySpan が destination となる Span と重なっていないかを確認、といったふうに使われている。
参考:runtime/MemoryExtensions.Globalization.cs at 6fd40193b9e8b9c5028edf741f266ff01bc75636 · dotnet/runtime · GitHub
source.Overlaps(destination)
を確認して例外を投げるのがイディオムのようだ。
なんとなく他でも使えそうな気がするけれれど、パッとは出てこない。
使い所でうまく引き出しから出せるかが課題。