Implemented Delta Row Compression.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10775 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2005-01-16 12:01:25 +00:00
parent a6d74a56c6
commit d647d0afe9
2 changed files with 275 additions and 0 deletions

View File

@ -0,0 +1,155 @@
/*
** DeltaRowCompression.cpp
** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "DeltaRowCompression.h"
#include <SupportDefs.h>
#include <memory.h>
AbstractDeltaRowCompressor::AbstractDeltaRowCompressor(int rowSize, uchar initialSeed)
: fSeedRow(new uchar[rowSize])
, fSize(rowSize)
, fInitialSeed(initialSeed)
{
Reset();
}
AbstractDeltaRowCompressor::~AbstractDeltaRowCompressor()
{
delete fSeedRow;
fSeedRow = NULL;
}
status_t AbstractDeltaRowCompressor::InitCheck()
{
if (fSeedRow != NULL) {
return B_OK;
} else {
return B_NO_MEMORY;
}
}
void AbstractDeltaRowCompressor::Reset()
{
if (fSeedRow != NULL) {
memset(fSeedRow, fInitialSeed, fSize);
}
}
int AbstractDeltaRowCompressor::CompressRaw(const uchar* row, bool updateSeedRow, bool updateDeltaRow)
{
int index = DiffersIndex(row, 0);
if (index == -1) {
// no differences
return 0;
}
fUpdateDeltaRow = updateDeltaRow;
fDeltaRowIndex = 0;
int seedRowIndex = 0;
do {
int length = DiffersLength(row, index);
// delta starts at index and contains length bytes
do {
// control byte limits data bytes to 8 bytes
int deltaBytes = length;
if (length > 8) {
deltaBytes = 8;
}
// calculate offset
int totalOffset = index - seedRowIndex;
bool needsOffsetBytes = totalOffset > 30;
int offset = totalOffset;
// control byte limits offset value to 31
if (needsOffsetBytes) {
offset = 31;
}
// write control byte (delta bytes bits 5-7; offset bits 0-4)
Put(((deltaBytes-1) << 5) | offset);
if (needsOffsetBytes) {
// write additional offset bytes after control byte
// the last offset byte must be less than 255
totalOffset -= offset;
while (totalOffset >= 255) {
Put(255);
totalOffset -= 255;
}
Put(totalOffset);
}
// write data bytes
for (int i = 0; i < deltaBytes; i ++) {
// copy row to seed row and delta row
uchar byte = row[index];
if (updateSeedRow) {
ASSERT (index < fSize);
fSeedRow[index] = byte;
}
Put(byte);
index ++;
}
seedRowIndex = index;
length -= deltaBytes;
} while (length > 0);
index = DiffersIndex(row, index);
} while (index != -1);
return fDeltaRowIndex;
}
int AbstractDeltaRowCompressor::CalculateSize(const uchar* row, bool updateSeedRow)
{
return CompressRaw(row, updateSeedRow, false);
}
void AbstractDeltaRowCompressor::Compress(const uchar* row)
{
CompressRaw(row, true, true);
}
#ifdef TEST_DELTA_ROW_COMPRESSION
void test(AbstractDeltaRowCompressor* compressor, uchar* row) {
int size = compressor->CalculateSize(row);
printf("size %d\n", size);
if (size > 0) {
uchar* buffer = new uchar[size];
compressor->Compress(row, buffer, size);
for (int i = 0; i < size; i ++) {
printf("%2.2x ", (int)buffer[i]);
}
printf("\n");
delete buffer;
}
printf("\n");
}
int main(int argc, char *argv[])
{
int n = 5;
uchar row1[] = {0, 0, 0, 0, 0};
uchar row2[] = {0, 1, 0, 0, 0};
uchar row3[] = {1, 1, 0, 2, 2};
DeltaRowCompressor compressor(n, 0);
test(&compressor, row1);
test(&compressor, row2);
test(&compressor, row3);
}
#endif

View File

@ -0,0 +1,120 @@
/*
** DeltaRowCompression.h
** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef _DELTA_ROW_COMPRESSION_H
#define _DELTA_ROW_COMPRESSION_H
#include <Debug.h>
class AbstractDeltaRowCompressor {
public:
AbstractDeltaRowCompressor(int rowSize, uchar initialSeed);
virtual ~AbstractDeltaRowCompressor();
// InitCheck returns B_OK on successful construction of this object or
// B_NO_MEMORY if the buffer for the seed row could not be allocated.
status_t InitCheck();
// Clears the seed row to the initial seed specified in the constructor
void Reset();
// Returns the size of the delta row.
// The size is 0 if the row is equal to the seed row (previous row).
// The seed row is updated only if updateSeedRow is true.
int CalculateSize(const uchar* row, bool updateSeedRow = false);
// Compresses the row using the delta row compression algorithm.
// The seed row is updated.
void Compress(const uchar* row);
protected:
// append byte to delta row
virtual void AppendByteToDeltaRow(uchar byte) = 0;
// returns the current size of the delta row
inline int CurrentDeltaRowSize() {
return fDeltaRowIndex;
}
private:
// Returns the index where seed row and row differ
// or -1 if both arrays are equal.
inline int DiffersIndex(const uchar* row, int index)
{
while (index < fSize) {
if (fSeedRow[index] != row[index]) {
return index;
}
index ++;
}
return -1;
}
// Returns the number of bytes that row differs from seed row
// starting at the specified index.
inline int DiffersLength(const uchar* row, int index)
{
int startIndex = index;
while (index < fSize) {
if (fSeedRow[index] == row[index]) {
break;
}
index ++;
}
return index - startIndex;
}
// Compresses row with delta row compression algorithm.
// The seed row is updated only if updateSeedRow is true.
// If updateDeltaRow is true the method AppendByteToDeltaRow is called.
int CompressRaw(const uchar* row, bool updateSeedRow, bool updateDeltaRow);
// write byte to delta row and calculate size of delta row
// If a client overrides this method and wants to calculate the
// size of the delta row the method must be called.
void Put(uchar byte) {
if (fUpdateDeltaRow) {
AppendByteToDeltaRow(byte);
}
fDeltaRowIndex ++;
}
uchar* fSeedRow; // the seed row
int fSize; // the size of the seed row in bytes
uchar fInitialSeed; // the value to initialize the seed row with
int fDeltaRowIndex; // the index of the next byte to be written into the delta row
bool fUpdateDeltaRow; // write delta row
};
class DeltaRowCompressor : public AbstractDeltaRowCompressor
{
public:
DeltaRowCompressor(int rowSize, uchar initialSeed)
: AbstractDeltaRowCompressor(rowSize, initialSeed)
{
// nothing to do
}
// The delta row to be written to.
void SetDeltaRow(uchar* deltaRow) {
fDeltaRow = deltaRow;
}
protected:
virtual void AppendByteToDeltaRow(uchar byte) {
fDeltaRow[CurrentDeltaRowSize()] = byte;
}
private:
uchar* fDeltaRow; // the delta row
};
#endif