westonpace commented on code in PR #35342:
URL: https://github.com/apache/arrow/pull/35342#discussion_r1186523477
##########
csharp/src/Apache.Arrow/ArrowBuffer.BitmapBuilder.cs:
##########
@@ -138,6 +138,28 @@ public BitmapBuilder AppendRange(IEnumerable<bool> values)
return this;
}
+
+ /// <summary>
+ /// Append multiple bits.
+ /// </summary>
+ /// <param name="value">Value of bits to append.</param>
+ /// <param name="length">Number of times the value should be
added.</param>
+ /// <returns>Returns the builder (for fluent-style
composition).</returns>
+ public BitmapBuilder AppendRange(bool value, int length)
+ {
+ EnsureAdditionalCapacity(length);
+
+ for (int i = 0; i < length; i++)
+ {
+ BitUtility.SetBit(Span, Length, value);
+ Length++;
+ }
+
+ SetBitCount += value ? length : 0;
+
+ return this;
+ }
Review Comment:
If you really want to eke out performance you could use
[Span.Fill](https://learn.microsoft.com/en-us/dotnet/api/system.span-1.fill?view=net-7.0)
for the whole bytes in the middle (assuming `length > 8`). E.g. something
like this:
```
public BitmapBuilder AppendRange2(bool value, int length)
{
// Use simpler method if there aren't many values
if (length < 20)
{
EnsureAdditionalCapacity(length);
for (int i = 0; i < length; i++)
{
BitUtility.SetBit(Span, Length, value);
Length++;
}
SetBitCount += value ? length : 0;
return this;
}
// Otherwise do the work to figure out how to copy whole bytes
int spaceLeftInCurrentByte = (8 - (Length % 8)) % 8;
// Bits we will be using to finish up the current byte
int remainderBits = Math.Min(length, spaceLeftInCurrentByte);
// Whole bytes that will be set
int wholeBytes = (length - remainderBits) / 8;
// Bits to set after the last whole byte
int trailingBits = length - remainderBits - (wholeBytes * 8);
int newBytes = (trailingBits > 0) ? wholeBytes + 1 : wholeBytes;
EnsureAdditionalCapacity(length);
var span = Memory.Span;
for (int i = 0; i < remainderBits; i++)
{
BitUtility.SetBit(span, Length, value);
Length++;
}
if (wholeBytes > 0)
{
var fill = (byte)(value ? 0xFF : 0x00);
// Length is guaranteed to be a multiple of 8 here
span.Slice(Length / 8, wholeBytes).Fill(fill);
}
Length += wholeBytes * 8;
for (int i = 0; i < trailingBits; i++)
{
BitUtility.SetBit(span, Length, value);
Length++;
}
SetBitCount += value ? length : 0;
return this;
}
```
The results are pretty significant once `length` gets large enough:
```
|------------------ |-------- |--------------:|-----------:|-----------:|
| AppendRangeFalse | 1 | 5.546 ns | 0.0364 ns | 0.0323 ns |
| AppendRangeTrue | 1 | 5.613 ns | 0.0484 ns | 0.0429 ns |
| AppendRange2False | 1 | 5.835 ns | 0.0751 ns | 0.0666 ns |
| AppendRange2True | 1 | 5.782 ns | 0.0280 ns | 0.0248 ns |
| AppendRangeFalse | 100 | 281.145 ns | 0.6840 ns | 0.6063 ns |
| AppendRangeTrue | 100 | 278.547 ns | 0.9460 ns | 0.8849 ns |
| AppendRange2False | 100 | 17.507 ns | 0.0414 ns | 0.0346 ns |
| AppendRange2True | 100 | 17.108 ns | 0.0698 ns | 0.0653 ns |
| AppendRangeFalse | 10000 | 27,397.477 ns | 51.9248 ns | 46.0300 ns |
| AppendRangeTrue | 10000 | 26,872.102 ns | 59.5216 ns | 49.7032 ns |
| AppendRange2False | 10000 | 14.870 ns | 0.1078 ns | 0.1009 ns |
| AppendRange2True | 10000 | 19.864 ns | 0.0747 ns | 0.0698 ns |
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]