/// <summary>Compress a buffer in native memory</summary> /// <param name="buffer">Pointer to the native memory buffer to compress</param> /// <param name="count">Number of bytes to compress</param> /// <param name="output">Where to write the compressed words</param> /// <returns>Number of extra bits that where output in the last literal word (or none if 0)</returns> internal static unsafe int CompressToUnsafe(byte *buffer, int count, CompressedBitmapWriter output) { // Simplified algorithm: // 1) read 31 bits from input (BE) // 2) if not all 0 (or all 1), then output a literal word (MSB set to 0), and jump back to step 1) // 3) set LENGTH = 1, FILL_BIT = 0 (or 1) // 4) Peek at next 31 bits, and if they are still all 0 (or 1), increment N, and jump back to step 4) // 5) output a repeat word, with MSB set to 1, followed by FILL_BIT, and then LENGTH-1 (30 bit), and jump back to step 1) // Optimizations: // - for very small inputs (3 bytes or less) we return a single literal word // - we read 64 bits at a time in the buffer, because it fits nicely in an UInt64 register var bucket = new UncompressedWordReader(buffer, count); uint word; while ((word = bucket.Read()) != UncompressedWordReader.NotEnough) { output.Write(word); } // if there are remaining bits, they are padded with 0 and written as a literal int bits = bucket.Bits; if (bits > 0) { //note: MSB will already be 0 word = bucket.ReadLast(); output.Write(word); } // write the header output.Pack(); return(bits); }
/// <summary>Compress a buffer in native memory</summary> /// <param name="buffer">Pointer to the native memory buffer to compress</param> /// <param name="count">Number of bytes to compress</param> /// <param name="output">Where to write the compressed words</param> /// <returns>Number of extra bits that where output in the last literal word (or none if 0)</returns> internal static unsafe int CompressToUnsafe(byte* buffer, int count, CompressedBitmapWriter output) { // Simplified algorithm: // 1) read 31 bits from input (BE) // 2) if not all 0 (or all 1), then output a literal word (MSB set to 0), and jump back to step 1) // 3) set LENGTH = 1, FILL_BIT = 0 (or 1) // 4) Peek at next 31 bits, and if they are still all 0 (or 1), increment N, and jump back to step 4) // 5) output a repeat word, with MSB set to 1, followed by FILL_BIT, and then LENGTH-1 (30 bit), and jump back to step 1) // Optimisations: // - for very small inputs (3 bytes or less) we return a single literal word // - we read 64 bits at a time in the buffer, because it fits nicely in an UInt64 register var bucket = new UncompressedWordReader(buffer, count); uint word; while ((word = bucket.Read()) != UncompressedWordReader.NotEnough) { output.Write(word); } // if there are reamining bits, they are padded with 0 and written as a literal int bits = bucket.Bits; if (bits > 0) { //note: MSB will already be 0 word = bucket.ReadLast(); output.Write(word); } // write the header output.Pack(); return bits; }