Add in RLE primitives to lib

This commit is contained in:
Paul Ramsey 2013-02-04 15:33:54 -08:00
parent 070609ef87
commit d5fec6a94c
5 changed files with 227 additions and 0 deletions

View File

@ -191,6 +191,8 @@ LIBS="$LIBS_SAVE"
AC_DEFINE_UNQUOTED([LIBXML2_VERSION], ["$LIBXML2_VERSION"], [PointCloud libxml2 version])
AC_SUBST([LIBXML2_VERSION])
AC_SUBST([XML2_LDFLAGS])
AC_SUBST([XML2_CPPFLAGS])
dnl ===========================================================================

View File

@ -5,6 +5,7 @@ CPPFLAGS = $(XML2_CPPFLAGS)
LDFLAGS = $(XML2_LDFLAGS)
OBJS = \
pc_dimensional.o \
pc_mem.o \
pc_patch.o \
pc_point.o \

View File

@ -177,12 +177,101 @@ test_patch_hex_out()
pcfree(wkt);
}
#if 0
/** Convert RLE bytes to value bytes */
uint8_t* pc_bytes_run_length_decode(const uint8_t *bytes_rle, size_t bytes_rle_size, uint32_t interpretation, size_t *bytes_nelems);
#endif
static void
test_run_length_encoding()
{
char *bytes, *bytes_rle, *bytes_de_rle;
int nr;
uint32_t bytes_nelems;
size_t bytes_rle_size;
size_t size;
uint8_t interp;
size_t interp_size;
bytes = "aaaabbbbccdde";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 5);
bytes = "a";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 1);
bytes = "aa";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 1);
bytes = "ab";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 2);
bytes = "abcdefg";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 7);
bytes = "aabcdefg";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 7);
bytes = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
nr = pc_bytes_run_count(bytes, PC_UINT8, strlen(bytes));
CU_ASSERT_EQUAL(nr, 1);
bytes_rle = pc_bytes_run_length_encode(bytes, PC_UINT8, strlen(bytes), &bytes_rle_size);
bytes_de_rle = pc_bytes_run_length_decode(bytes_rle, bytes_rle_size, PC_UINT8, &bytes_nelems);
CU_ASSERT_EQUAL(memcmp(bytes, bytes_de_rle, strlen(bytes)), 0);
pcfree(bytes_rle);
pcfree(bytes_de_rle);
bytes = "aabcdefg";
interp = PC_UINT8;
interp_size = INTERPRETATION_SIZES[interp];
size = strlen(bytes) / interp_size;
bytes_rle = pc_bytes_run_length_encode(bytes, interp, size, &bytes_rle_size);
bytes_de_rle = pc_bytes_run_length_decode(bytes_rle, bytes_rle_size, interp, &bytes_nelems);
CU_ASSERT_EQUAL(memcmp(bytes, bytes_de_rle, strlen(bytes)), 0);
CU_ASSERT_EQUAL(bytes_nelems, strlen(bytes)/interp_size);
pcfree(bytes_rle);
pcfree(bytes_de_rle);
bytes = "aaaaaabbbbeeeeeeeeeehhiiiiiioooo";
interp = PC_UINT32;
interp_size = INTERPRETATION_SIZES[interp];
size = strlen(bytes) / interp_size;
bytes_rle = pc_bytes_run_length_encode(bytes, interp, size, &bytes_rle_size);
bytes_de_rle = pc_bytes_run_length_decode(bytes_rle, bytes_rle_size, interp, &bytes_nelems);
CU_ASSERT_EQUAL(memcmp(bytes, bytes_de_rle, strlen(bytes)), 0);
CU_ASSERT_EQUAL(bytes_nelems, strlen(bytes)/interp_size);
pcfree(bytes_rle);
pcfree(bytes_de_rle);
bytes = "aaaaaabbbbeeeeeeeeeehhiiiiiioooo";
interp = PC_UINT16;
interp_size = INTERPRETATION_SIZES[interp];
size = strlen(bytes) / interp_size;
bytes_rle = pc_bytes_run_length_encode(bytes, interp, size, &bytes_rle_size);
bytes_de_rle = pc_bytes_run_length_decode(bytes_rle, bytes_rle_size, interp, &bytes_nelems);
CU_ASSERT_EQUAL(memcmp(bytes, bytes_de_rle, strlen(bytes)), 0);
CU_ASSERT_EQUAL(bytes_nelems, strlen(bytes)/interp_size);
pcfree(bytes_rle);
pcfree(bytes_de_rle);
}
/* REGISTER ***********************************************************/
CU_TestInfo patch_tests[] = {
PG_TEST(test_endian_flip),
PG_TEST(test_patch_hex_in),
PG_TEST(test_patch_hex_out),
PG_TEST(test_run_length_encoding),
CU_TEST_INFO_NULL
};

View File

@ -84,5 +84,13 @@ int pc_schema_has_name(const PCSCHEMA *s, const char *name);
/** Copy a string within the global memory management context */
char* pcstrdup(const char *str);
/** How many runs are there in a value array? */
uint32_t pc_bytes_run_count(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems);
/** Convert value bytes to RLE bytes */
uint8_t* pc_bytes_run_length_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems, size_t *bytes_rle_size);
/** Convert RLE bytes to value bytes */
uint8_t* pc_bytes_run_length_decode(const uint8_t *bytes_rle, size_t bytes_rle_size, uint32_t interpretation, uint32_t *bytes_nelems);
#endif /* _PC_API_INTERNAL_H */

View File

@ -19,3 +19,130 @@
#include <stdarg.h>
#include "pc_api_internal.h"
uint32_t
pc_bytes_run_count(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems)
{
int i;
const uint8_t *ptr0;
const uint8_t *ptr1;
size_t size = INTERPRETATION_SIZES[interpretation];
uint32_t runcount = 1;
for ( i = 1; i < nelems; i++ )
{
ptr0 = bytes + (i-1)*size;
ptr1 = bytes + i*size;
if ( memcmp(ptr0, ptr1, size) != 0 )
{
runcount++;
}
}
return runcount;
}
/**
* Take the uncompressed bytes and run-length encode (RLE) them.
* Structure of RLE array as:
* <uint8> number of elements
* <val> value
* ...
*/
uint8_t *
pc_bytes_run_length_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems, size_t *bytes_rle_size)
{
int i;
uint8_t *buf, *bufptr;
const uint8_t *bytesptr;
const uint8_t *runstart;
uint8_t *bytes_rle;
size_t size = INTERPRETATION_SIZES[interpretation];
uint8_t runlength = 1;
/* Allocate more size than we need (worst case: n elements, n runs) */
buf = pcalloc(nelems*size + sizeof(uint8_t)*size);
bufptr = buf;
/* First run starts at the start! */
runstart = bytes;
for ( i = 1; i <= nelems; i++ )
{
bytesptr = bytes + i*size;
/* Run continues... */
if ( i < nelems && runlength < 255 && memcmp(runstart, bytesptr, size) == 0 )
{
runlength++;
}
else
{
/* Write # elements in the run */
*bufptr = runlength;
bufptr += 1;
/* Write element value */
memcpy(bufptr, runstart, size);
bufptr += size;
/* Advance read head */
runstart = bytesptr;
runlength = 1;
}
}
/* Length of buffer */
if ( bytes_rle_size )
{
*bytes_rle_size = (bufptr - buf);
}
/* Write out shortest buffer possible */
bytes_rle = pcalloc(*bytes_rle_size);
memcpy(bytes_rle, buf, *bytes_rle_size);
pcfree(buf);
return bytes_rle;
}
/**
* Take the compressed bytes and run-length dencode (RLE) them.
* Structure of RLE array is:
* <uint8> number of elements
* <val> value
* ...
*/
uint8_t *
pc_bytes_run_length_decode(const uint8_t *bytes_rle, size_t bytes_rle_size, uint32_t interpretation, uint32_t *bytes_nelems)
{
int i, n;
uint8_t *bytes;
uint8_t *bytes_ptr;
const uint8_t *bytes_rle_ptr = bytes_rle;
const uint8_t *bytes_rle_end = bytes_rle + bytes_rle_size;
size_t size = INTERPRETATION_SIZES[interpretation];
uint8_t runlength;
uint32_t nelems = 0;
/* Count up how big our output is. */
while( bytes_rle_ptr < bytes_rle_end )
{
nelems += *bytes_rle_ptr;
bytes_rle_ptr += 1 + size;
}
*bytes_nelems = nelems;
/* Alocate output and fill it up */
bytes = pcalloc(size * nelems);
bytes_ptr = bytes;
bytes_rle_ptr = bytes_rle;
while ( bytes_rle_ptr < bytes_rle_end )
{
n = *bytes_rle_ptr;
bytes_rle_ptr += 1;
for ( i = 0; i < n; i++ )
{
memcpy(bytes_ptr, bytes_rle_ptr, size);
bytes_ptr += size;
}
bytes_rle_ptr += size;
}
return bytes;
}