Skip to content

Commit

Permalink
Merge pull request dotnet#852 from KrzysztofCwalina/Sequences
Browse files Browse the repository at this point in the history
Added SpanSequence
  • Loading branch information
KrzysztofCwalina authored Sep 29, 2016
2 parents 9684f6d + 7039435 commit e407acb
Show file tree
Hide file tree
Showing 16 changed files with 317 additions and 150 deletions.
11 changes: 5 additions & 6 deletions samples/LibuvWithNonAllocatingFormatters/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,14 @@ static void RunLoop(bool log)
formatter.Format(" @ {0:O}", DateTime.UtcNow);
}

unsafe
{
fixed (byte* ptr = formatter.Buffer)
{
// formatter should have a property for written bytes
var response = new Memory<byte>(formatter.Buffer, 0, formatter.CommitedByteCount, pointer: ptr);
var segment = formatter.Written;
unsafe {
fixed (byte* p = segment.Array) {
var response = new Memory<byte>(segment.Array, segment.Offset, segment.Count, pointer: p);
connection.TryWrite(response);
}
}

connection.Dispose();
};

Expand Down
35 changes: 24 additions & 11 deletions src/System.Buffers.Experimental/System/Buffers/Multispan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace System.Buffers
/// Also, be extra careful when disposing this type. If you dispose the original instance and its copy,
/// the pool used by this type will be corrupted.
/// </remarks>
public struct Multispan<T> : ISequence<Span<T>>
public struct Multispan<T> : ISpanSequence<T>
{
ArraySegment<T> _head;
ArraySegment<T>[] _tail;
Expand Down Expand Up @@ -277,21 +277,34 @@ private static Span<T> AsSlice(ArraySegment<T> segment)
return new Span<T>(segment.Array, segment.Offset, segment.Count);
}

public Span<T> TryGetItem(ref Position position)
SpanSequenceEnumerator<T> ISpanSequence<T>.GetEnumerator()
{
if (!position.IsEnd && position.IntegerPosition < _count) {
var item = this[position.IntegerPosition++];
if (position.IntegerPosition >= _count) position = Position.End;
return item;
} else {
return new SpanSequenceEnumerator<T>(this);
}

public Span<T> GetAt(ref Position position, bool advance = false)
{
if(_count == 0) {
position = Position.Invalid;
return default(Span<T>);
}

if(position.Equals(Position.BeforeFirst)) {
position = Position.First;
return default(Span<T>);
}
}

SequenceEnumerator<Span<T>> ISequence<Span<T>>.GetEnumerator()
{
return new SequenceEnumerator<Span<T>>(this);
if (position.IntegerPosition < _count) {
var item = this[position.IntegerPosition];
if (advance) {
position.IntegerPosition++;
if (position.IntegerPosition >= _count) position = Position.AfterLast;
}
return item;
}

position = Position.Invalid;
return default(Span<T>);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ namespace System.Buffers
{
public static class MultispanExtensions
{
public static bool TryParseUInt32<TMultispan>(this TMultispan bytes, EncodingData encoding, out uint value, out int consumed) where TMultispan : ISequence<Span<byte>>
public static bool TryParseUInt32<TMultispan>(this TMultispan bytes, EncodingData encoding, out uint value, out int consumed) where TMultispan : ISpanSequence<byte>
{
Position position = Position.BeforeFirst;
var first = bytes.TryGetItem(ref position);
Position position = Position.First;
var first = bytes.GetAt(ref position, advance:true);
if (!position.IsValid) throw new ArgumentException("bytes cannot be empty");

if (!PrimitiveParser.TryParse(first, EncodingData.Encoding.Utf8, out value, out consumed)) {
Expand All @@ -24,7 +24,7 @@ public static bool TryParseUInt32<TMultispan>(this TMultispan bytes, EncodingDat
return true;
}

var second = bytes.TryGetItem(ref position);
var second = bytes.GetAt(ref position, advance: true);

Span<byte> temp;
int numberOfBytesFromSecond = second.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ namespace System.Collections.Sequences
// new interface
public interface ISequence<T>
{
T TryGetItem(ref Position position);
/// <summary>
///
/// </summary>
/// <param name="position"></param>
/// <param name="advance"></param>
/// <returns></returns>
/// <remarks></remarks>
T GetAt(ref Position position, bool advance = false);

SequenceEnumerator<T> GetEnumerator();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@

namespace System.Collections.Sequences
{
public struct Position
public struct Position : IEquatable<Position>
{
public int IntegerPosition;
public object ObjectPosition;

public static Position End = new Position() { IntegerPosition = int.MinValue };
public static Position Invalid = new Position() { IntegerPosition = int.MinValue + 1 };
public static Position BeforeFirst = new Position();
public static Position BeforeFirst = new Position() { IntegerPosition = -1 };
public static Position First = new Position();
public static Position AfterLast = new Position() { IntegerPosition = int.MaxValue - 1 };
public static Position Invalid = new Position() { IntegerPosition = int.MaxValue };

public bool IsValid {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return IntegerPosition != Invalid.IntegerPosition; }
get { return IntegerPosition <= AfterLast.IntegerPosition; }
}
public bool IsEnd {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return IntegerPosition == End.IntegerPosition; }
get { return IntegerPosition == AfterLast.IntegerPosition; }
}

public bool Equals(Position other)
{
return IntegerPosition == other.IntegerPosition && ObjectPosition == other.ObjectPosition;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace System.Collections.Sequences
{
// a List<T> like type designed to be embeded in other types
public struct ResizableArray<T>
{
public T[] _array;
public int _count;

public ResizableArray(int capacity)
{
_array = new T[capacity];
_count = 0;
}

public ResizableArray(T[] array, int count = 0)
{
_array = array;
_count = count;
}

public void Add(T item)
{
if (_array.Length == _count) {
Resize();
}
_array[_count++] = item;
}

public T[] Resize(int newSize = -1)
{
var oldArray = _array;
if (newSize == -1) {
if(_array == null || _array.Length == 0) {
newSize = 4;
}
else {
newSize = _array.Length << 1;
}
}

var newArray = new T[newSize];
_array.CopyTo(newArray, 0);
_array = newArray;
return oldArray;
}

public T[] Resize(T[] newArray)
{
if (newArray.Length < _count) throw new Exception(String.Format("{0} {1}", newArray.Length, _count));
var oldArray = _array;
Array.Copy(_array, 0, newArray, 0, _count);
_array = newArray;
return oldArray;
}

public int Count => _count;

public int Capacity => _array.Length;

public T this[int index] {
get {
if (index > _count - 1) throw new IndexOutOfRangeException();
return _array[index];
}
set {
if (index > _count - 1) throw new IndexOutOfRangeException();
_array[index] = value;
}
}

public T GetAt(ref Position position, bool advance = false)
{
if( _count == 0) {
position = Position.Invalid;
return default(T);
}

if (position.Equals(Position.BeforeFirst)) {
position = Position.Invalid;
if (advance) {
position = Position.First;
}
return default(T);
}

if (position.IntegerPosition < _count) {
var item = _array[position.IntegerPosition];
if (advance) {
position.IntegerPosition++;
if (position.IntegerPosition == _count) position = Position.AfterLast;
}
return item;
}

position = Position.Invalid;
return default(T);
}

public ArraySegment<T> Full => new ArraySegment<T>(_array, 0, _count);
public ArraySegment<T> Free => new ArraySegment<T>(_array, _count, _array.Length - _count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,27 @@ public struct SequenceEnumerator<T>
{
Position _position;
ISequence<T> _sequence;
T _item;

public SequenceEnumerator(ISequence<T> sequence)
{
_sequence = sequence;
_position = Position.BeforeFirst;
_item = default(T);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
_item = _sequence.TryGetItem(ref _position);
if (_position.IsValid) {
return true;
_sequence.GetAt(ref _position, advance: true);
if (_position.IsValid && !_position.Equals(Position.AfterLast)) {
}
return false;
}

public T Current {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return _item;
return _sequence.GetAt(ref _position);
}
}
}

public static class SequenceEnumeratorExtensions
{
public static SequenceEnumerator<T> GetEnumerator<T>(this ISequence<T> sequence)
{
return new SequenceEnumerator<T>(sequence);
}
}
}
41 changes: 41 additions & 0 deletions src/System.Slices/System/SpanSequence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Sequences;
using System.Runtime.CompilerServices;

namespace System
{
public interface ISpanSequence<T>
{
SpanSequenceEnumerator<T> GetEnumerator();
Span<T> GetAt(ref Position position, bool advance = false);
}

public struct SpanSequenceEnumerator<T>
{
Position _position;
ISpanSequence<T> _sequence;

public SpanSequenceEnumerator(ISpanSequence<T> sequence)
{
_sequence = sequence;
_position = Position.BeforeFirst;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
var result = _sequence.GetAt(ref _position, advance:true);
return _position.IsValid;
}

public Span<T> Current {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return _sequence.GetAt(ref _position);
}
}
}
}

1 change: 1 addition & 0 deletions src/System.Slices/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
}
},
"dependencies": {
"System.Collections.Sequences": { "target": "project" },
"System.Runtime": "4.1.0",
"System.Runtime.InteropServices": "4.1.0",
"System.Diagnostics.Debug": "4.0.11",
Expand Down
Loading

0 comments on commit e407acb

Please sign in to comment.