2
\$\begingroup\$

This is a fraction of the binary writer I'm writing, and I'm trying find some way to improve it.

using System;
using System.Collections.Generic;
public class ByteBuffer
{
 // List used to hold all bytes that will be read
 private List<byte> buffer = new List<byte>(32);
 private int bitIndex = 0;
 /// <summary>
 /// Writes an n bits byte onto the buffer.
 /// </summary>
 public void Write(byte source, int n)
 {
 if ((n + bitIndex) / 8 > buffer.Count)
 {
 buffer.AddRange(new byte[(n + bitIndex) / 8 - buffer.Count]);
 }
 for (int i = 0; i < n; i++)
 {
 buffer[(bitIndex + i) / 8] |= (byte)(((source >> (n - 1 - i)) & 1) << (int)(7 - (bitIndex + i) % 8));
 }
 bitIndex += n;
 }
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jul 21, 2012 at 20:35
\$\endgroup\$
2
  • \$\begingroup\$ For what you're doing here, working with data at the bit level is overkill IMHO. The intrinsic type is the byte so you should work at that level at a minimum. You won't gain much in terms of efficiency and maintainability, in fact, it's quite the opposite. You're making it harder on yourself unnecessarily. Besides, that's why there's the BitArray type. \$\endgroup\$ Commented Jul 21, 2012 at 22:45
  • 2
    \$\begingroup\$ @JeffMercado In some cases, this is exactly what you need to do. For example, when implementing Huffman coding or some other compression algorithm. \$\endgroup\$ Commented Jul 22, 2012 at 0:54

3 Answers 3

1
\$\begingroup\$

I'm going to go out on a limb, not knowing the full extent of the use cases of the class, but there's a pretty decent class, BitArray that might handle your needs as such:

using System;
using System.Collections;
public class ByteBuffer
{
 // List used to hold all bytes that will be read
 private BitArray buffer;
 /// <summary>
 /// Writes an n bits byte onto the buffer.
 /// </summary>
 public void Write(byte source, int n)
 {
 buffer = Append(buffer, source, n);
 }
 private static BitArray Append(BitArray current, byte source, int n)
 {
 var count = current == null ? 0 : current.Count;
 var bools = new bool[count + n];
 if (count > 0)
 {
 current.CopyTo(bools, 0);
 }
 if (n > 0)
 {
 var after = new BitArray(new[] { source });
 for (int i = 0; i < n; i++)
 {
 bools[count + i] = after[i];
 }
 }
 return new BitArray(bools);
 }
}
answered Jul 22, 2012 at 5:24
\$\endgroup\$
1
\$\begingroup\$

If you're after efficiency, you shouldn't write bit by bit. For example, if bitIndex is currently 3 and you're writing the full 8 bits, just two steps are necessary: writing 5 bits to one byte and then the remaining 3 bits to another byte.

And depending on what you do, writing directly to some Stream might make more sense than using a List<byte>.

Also, you should probably check the input and throw and exception if n is not between 1 and 8.

answered Jul 21, 2012 at 21:19
\$\endgroup\$
2
  • \$\begingroup\$ Well, about using a stream, I'm only using the List<byte> because of the automatic expansion and Add/AddRange, to exclude the need of a WriteIndex field. Would the stream overhead, in fact, worth it? \$\endgroup\$ Commented Jul 21, 2012 at 21:42
  • \$\begingroup\$ I mean, you're most likely going to write the result to a file or network anyway in the end, no? If that's the case, it would be more efficient to write it there as soon as possible. \$\endgroup\$ Commented Jul 21, 2012 at 21:48
1
\$\begingroup\$

I ended up with an implementation that looks like this:

using System.Diagnostics;
public class ByteBuffer
{
 public byte[] tempBuffer = new byte[16];
 public int tempIndex = 0;
 /// <summary>
 /// Writes the given number of bits.
 /// </summary>
 public void Write(byte value, int bits)
 {
 Debug.Assert(bits > 0 && bits < 9, "Number of bits must be between 1 and 8.");
 int localBitLen = (tempIndex % 8);
 if (localBitLen == 0)
 {
 tempBuffer[tempIndex >> 3] = value;
 tempIndex += bits;
 return;
 }
 tempBuffer[tempIndex >> 3] &= (byte)(255 >> (8 - localBitLen)); // clear before writing
 tempBuffer[tempIndex >> 3] |= (byte)(value << localBitLen); // write first half
 // need write into next byte?
 if (localBitLen + bits > 8)
 {
 tempBuffer[(tempIndex >> 3) + 1] &= (byte)(255 << localBitLen); // clear before writing
 tempBuffer[(tempIndex >> 3) + 1] |= (byte)(value >> (8 - localBitLen)); // write second half
 }
 tempIndex += bits;
 }
}

I was able to do it with the help of some calculators (I just hate being bad with bitwise operations).

I had to use a byte[] rather than a stream since I can't write directly on the stream back-buffer. I might implement the Read, and exponential expansion for the buffer tomorrow.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
answered Jul 23, 2012 at 0:46
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.