diff --git a/src/LongSpan.cs b/src/LongSpan.cs index f9a6259..906e0e2 100644 --- a/src/LongSpan.cs +++ b/src/LongSpan.cs @@ -1,11 +1,91 @@ // Copyright (c) 2026 Viktor Stojanović. All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. +using System; +using System.Runtime.CompilerServices; + namespace SharpAllocators; +/// +/// represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed +/// or native memory, or to memory allocated on the stack. It is type-safe and memory-safe. +/// public readonly ref struct LongSpan { + /// A byref or a native ptr. private readonly ref T _reference; - public readonly long Length { get; } + + /// The number of elements this Span contains. + private readonly long _length; + + /// + /// The number of items in the span. + /// + public readonly long Length => _length; + + /// + /// Gets a value indicating whether this is empty. + /// + /// if this span is empty; otherwise, . public readonly bool IsEmpty => Length is 0; + + /// Creates a new of length 1 around the specified reference. + /// A reference to data. + public LongSpan(ref T reference) + { + _reference = ref reference; + _length = 1; + } + + /// + /// Creates a new span over the target unmanaged buffer. Clearly this + /// is quite dangerous, because we are creating arbitrarily typed T's + /// out of a void*-typed block of memory. And the length is not checked. + /// But if this creation is correct, then all subsequent uses are correct. + /// + /// An unmanaged pointer to memory. + /// The number of elements the memory contains. + /// + /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. + /// + /// + /// Thrown when the specified is negative. + /// + public unsafe LongSpan(void* pointer, long length) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException(nameof(length), "Length cannot negative"); + } + + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + throw new ArgumentException("Generic type parameter T cannot be a refrence type or contain refrences", nameof(T)); + } + + _reference = ref *(T*)pointer; + _length = length; + } + + /// + /// Returns a reference to specified element of the Span. + /// + /// The zero-based index. + /// + /// + /// Thrown when index less than 0 or index greater than or equal to Length + /// + public ref T this[long index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if ((ulong)index >= (ulong)_length) + { + throw new IndexOutOfRangeException("Index cannot be less then zero or greater then or equal to length"); + } + + return ref Unsafe.Add(ref _reference, (nint)index); // right now this can cause UB on 32 bit systems + } + } }