Skip to content

Add methods to manipulate Half in binary#40882

Merged
jkotas merged 10 commits intodotnet:masterfrom
huoyaoyuan:half-binary
Sep 1, 2020
Merged

Add methods to manipulate Half in binary#40882
jkotas merged 10 commits intodotnet:masterfrom
huoyaoyuan:half-binary

Conversation

@huoyaoyuan
Copy link
Member

Closes #38456 . Closes #38288 .

@Dotnet-GitSync-Bot
Copy link
Collaborator

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented Aug 15, 2020

Tagging subscribers to this area: @tannergooding, @pgovind
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan
Copy link
Member Author

Merging master fixes half write tests. The new failing tests looks like unrelated.

@jeffhandley
Copy link
Member

@jkotas I do not think this would meet the bar for merging into 5.0; do you agree? If so, I'll change #38456 to be 6.0.0.

@huoyaoyuan
Copy link
Member Author

I'm OK with 6.0. This should be only a subset of operations for Half.

@tannergooding
Copy link
Member

@GrabYourPitchforks, @adamsitnik, could you give this a second review since you own System.Memory?

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

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

LGTM, I've left some comments, but mostly nits


[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe short HalfToInt16Bits(Half value)
public static unsafe short HalfToInt16Bits(Half value)
Copy link
Member

Choose a reason for hiding this comment

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

not related to your changes: I would be really surprised if this method was not inlined without [MethodImpl(MethodImplOptions.AggressiveInlining)] applied

Comment on lines +40 to +42
return !BitConverter.IsLittleEndian ?
BitConverter.Int16BitsToHalf(ReverseEndianness(MemoryMarshal.Read<short>(source))) :
MemoryMarshal.Read<Half>(source);
Copy link
Member

Choose a reason for hiding this comment

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

pedantic nit: removing extra ! can simplify the code?

Suggested change
return !BitConverter.IsLittleEndian ?
BitConverter.Int16BitsToHalf(ReverseEndianness(MemoryMarshal.Read<short>(source))) :
MemoryMarshal.Read<Half>(source);
return BitConverter.IsLittleEndian ?
MemoryMarshal.Read<Half>(source) :
BitConverter.Int16BitsToHalf(ReverseEndianness(MemoryMarshal.Read<short>(source)));

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 just copied the code body from double overload and changed the types. They should be consistent after this PR right?

Comment on lines +46 to +54
if (BitConverter.IsLittleEndian)
{
short tmp = ReverseEndianness(BitConverter.HalfToInt16Bits(value));
MemoryMarshal.Write(destination, ref tmp);
}
else
{
MemoryMarshal.Write(destination, ref value);
}
Copy link
Member

Choose a reason for hiding this comment

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

very-very pedantic nit: you are sometimes using else block, sometimes not`

if (condition)
{
   // do one thing
   // return sth;
}

// return sth else
if (condition)
{
   // do one thing
   // return sth;
}
else
{
   // return sth else
}

it would be good to stick to one pattern and follow it in the entire PR

_buffer[1] = (byte)(TmpValue >> 8);
_buffer[2] = (byte)(TmpValue >> 16);
_buffer[3] = (byte)(TmpValue >> 24);
BinaryPrimitives.WriteSingleLittleEndian(_buffer, value);
Copy link
Member

Choose a reason for hiding this comment

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

since you have changed it for single overload, should we do the same for int, uint, short, ushort and other methods that don't use BinaryPrimitives? (just for consistency)

public virtual void Write(short value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
OutStream.Write(_buffer, 0, 2);
}
// Writes a two-byte unsigned integer to this stream. The current position
// of the stream is advanced by two.
//
[CLSCompliant(false)]
public virtual void Write(ushort value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
OutStream.Write(_buffer, 0, 2);
}
// Writes a four-byte signed integer to this stream. The current position
// of the stream is advanced by four.
//
public virtual void Write(int value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 24);
OutStream.Write(_buffer, 0, 4);
}
// Writes a four-byte unsigned integer to this stream. The current position
// of the stream is advanced by four.
//
[CLSCompliant(false)]
public virtual void Write(uint value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 24);
OutStream.Write(_buffer, 0, 4);
}

Copy link
Member

Choose a reason for hiding this comment

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

This was explored in #37582 (comment) . Using the Span-based helpers for <8 byte types is not profitable (converting array to Span is cheap, but it is not free).

Copy link
Member

Choose a reason for hiding this comment

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

Using the Span-based helpers for <8 byte types is not profitable

@jkotas thanks for another valuable comment! Does it mean that the single change should be reverted and the new Write(Half value) method should not be using BinaryPrimitives as well?

Copy link
Member

Choose a reason for hiding this comment

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

I would think so, unless we have data that suggest otherwise.

@jkotas jkotas merged commit 393c1b2 into dotnet:master Sep 1, 2020
@jkotas
Copy link
Member

jkotas commented Sep 1, 2020

huoyaoyuan Thank you!

@huoyaoyuan huoyaoyuan deleted the half-binary branch September 1, 2020 20:21
@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider adding Half support to the BinaryPrimitives class Consider adding HalfToInt16Bits and Int16BitsToHalf to BitConverter

6 participants