From d5fec6a94c9ce3da07badca8bfa0a112a12f69f7 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Mon, 4 Feb 2013 15:33:54 -0800 Subject: [PATCH] Add in RLE primitives to lib --- configure.ac | 2 + libpc/Makefile | 1 + libpc/cunit/cu_pc_patch.c | 89 ++++++++++++++++++++++++++ libpc/pc_api_internal.h | 8 +++ libpc/pc_dimensional.c | 127 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+) diff --git a/configure.ac b/configure.ac index 2851c2a..8182b17 100644 --- a/configure.ac +++ b/configure.ac @@ -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 =========================================================================== diff --git a/libpc/Makefile b/libpc/Makefile index 8ce8b55..c9af445 100644 --- a/libpc/Makefile +++ b/libpc/Makefile @@ -5,6 +5,7 @@ CPPFLAGS = $(XML2_CPPFLAGS) LDFLAGS = $(XML2_LDFLAGS) OBJS = \ + pc_dimensional.o \ pc_mem.o \ pc_patch.o \ pc_point.o \ diff --git a/libpc/cunit/cu_pc_patch.c b/libpc/cunit/cu_pc_patch.c index ee3e4d9..8cc2579 100644 --- a/libpc/cunit/cu_pc_patch.c +++ b/libpc/cunit/cu_pc_patch.c @@ -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 }; diff --git a/libpc/pc_api_internal.h b/libpc/pc_api_internal.h index 35120d1..d197030 100644 --- a/libpc/pc_api_internal.h +++ b/libpc/pc_api_internal.h @@ -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 */ \ No newline at end of file diff --git a/libpc/pc_dimensional.c b/libpc/pc_dimensional.c index 966a3fd..018977e 100644 --- a/libpc/pc_dimensional.c +++ b/libpc/pc_dimensional.c @@ -19,3 +19,130 @@ #include #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: +* number of elements +* 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: +* number of elements +* 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; +} +