Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Prepared System.Buffer.Primitives for API Review #1993

Merged
merged 5 commits into from
Dec 22, 2017

Conversation

KrzysztofCwalina
Copy link
Member

  • Unified Positions
  • Moved ReadCursorOperations around. These APIs are not general purpose Position APIs. They only work with ReadOnlyBuffer.
  • Renamed ReadOnlyBufferReader to BufferReader
  • Simplified namespaces

@pakrym, @davidfowl, @joshfree, @terrajobst

@@ -56,7 +56,7 @@ public static int CopyTo(this IMemoryList<byte> list, Span<byte> destination)
{
var current = list.Memory.Span;
var index = current.IndexOf(value);
if (index != -1) return Collections.Sequences.Position.Create(list, index);
if (index != -1) return new Collections.Sequences.Position(list, index);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

System.Collections.Sequences is imported, is there a name clash?

i.e. can this be just Position?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, forgot about it. I will remove.

@@ -180,5 +181,129 @@ public void Create_WorksWithOwnedMemory()
b => b.Slice(0, 70).Slice(0, b.End),
b => b.Slice(70, b.Start)
};

static bool TryGetBuffer(Position begin, Position end, out ReadOnlyMemory<byte> data, out Position next)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move the tests that call Seek to Pipelines.Tests and then eliminate it. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests were testing internal implementations of ROB why would we want to move them to Pipelines? Or even worse duplicate code being tested inside the test itself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you propose I do? Is there a way to test this without calling ROB's private APIs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make them internal. It has been done in other places to verify implementation details.

using System.Linq;
using System.Text;

namespace System.IO.Pipelines.Tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is useful not on only for pipelines, why is it moved back?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used just by pipelines tests

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why it builds but it's used by ROB and RBR tests that are in primitives.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two copies. I will remove one of them (i.e. the one in pipelines)

return segment;
}

//ThrowHelper.ThrowInvalidOperationException(ExceptionResource.UnexpectedSegmentType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove throwing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea. Good catch.

@@ -8,7 +8,7 @@

namespace System.IO.Pipelines
{
public static class ReadCursorOperations
public static class PositionOperations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it moved back to pipelines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's pipelines specific. It does not work with an arbitrary position. It only works with positions of IMemoryList, and possibly other things that ReadOnlyBuffer supports.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works with everything that ReadOnlyBuffer supports that's why it's in buffers. There is no need to have another copy in Pipelines.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Position is more general than Buffers. Look in System.Collections.Sequences. There is a Hashtable and ArrayList implementation that uses it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then move these methods to be on ROB

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I have done it initially and it did not work. But now it does. I will fix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it and added InternalsVisible from Pipelines.Tests to ReadOnlyBuffer. We need to design proper seek APIs though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, why do you need InternalsVisisbleTo to Pipelines.Tests? Just don't move SeekTests.cs from primitives.

Copy link
Contributor

@pakrym pakrym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too many copies of TryGetBuffer around.

public readonly partial struct ReadOnlyBuffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool TryGetBuffer(Position begin, Position end, out ReadOnlyMemory<byte> data, out Position next)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why internal? It can be private

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same thing, there is a test in tests/System.Buffers.Primitives.Tests/ReadableBufferFacts.cs using it.

}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static Position Seek(Position begin, Position end, long bytes, bool checkEndReachable = true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same: why not private?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the tests from tests/System.Buffers.Primitives.Tests/ReadableBufferFacts.cs do not require copied code or being moved.

}

[MethodImpl(MethodImplOptions.NoInlining)]
static Position SeekMultiSegment(Position begin, Position end, long bytes, bool checkEndReachable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private for everything else

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

public static explicit operator int(Position position) => position._index;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (T segment, int index) Get<T>()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect consumers to check if the segment is non-null/default?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on what they use the position for.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in most cases they either use it or not. If they don't use it, direct access to Index is enough. If they need both then I prefer throwing to returning default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can play with this. But I still want to do an experiment with changing the check to typeof(T) == typeof(Segment). I will try to do it after the new year. If if does not work, we can remove this method.

public static bool operator ==(Position left, Position right) => left._index == right._index && left._segment == right._segment;
public static bool operator !=(Position left, Position right) => left._index != right._index || left._segment != right._segment;

public static Position operator +(Position value, int index)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we were going to limit the ability to modify positions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now have public ctors, Index, and Segment. The + operator is much more hidden than those.
Also, without the operator, code that uses position as index is very wacky. It does not care about the Segment, yet it has to deal with it (in the ctor, at least).

We can think about it more, but I would treat this as a separate PR.

@@ -16,16 +15,16 @@ public ReadableBufferSequence(ReadOnlyBuffer buffer) : this()
_buffer = buffer;
}

public Collections.Sequences.Position First => Collections.Sequences.Position.Create(_buffer.Start.Segment, _buffer.Start.Index);
public Position Start => new Position(_buffer.Start.Segment, _buffer.Start.Index);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have start at all if we treat default as a Start?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think we treat default as start. I remove this early this week.

@@ -10,8 +10,65 @@ namespace System.Buffers
{
public readonly partial struct ReadOnlyBuffer
{
public static int Seek(Position begin, Position end, out Position result, byte byte0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change them to be extension/instance methods on ReadOnlyBuffer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do it separately. I think I have seen some code that calls the APIs with positions other that the buffer's start/end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Seek is the last one, but we can do it in a separate pass, just don't like moving things back and forth.

@KrzysztofCwalina KrzysztofCwalina merged commit 252c882 into dotnet:master Dec 22, 2017
@KrzysztofCwalina KrzysztofCwalina deleted the PositionUnification branch January 3, 2018 00:20
KrzysztofCwalina added a commit to KrzysztofCwalina/corefxlab that referenced this pull request Jan 5, 2018
* Unified Positions

* Removed fully qualified Position names

* Added accidentally removed throw

* Removed one copy of TestBufferFactory

* Rearrange Seek Methods
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants