diff --git a/lib/cunit/Makefile b/lib/cunit/Makefile index 7098afb..ea3181e 100644 --- a/lib/cunit/Makefile +++ b/lib/cunit/Makefile @@ -9,6 +9,7 @@ EXE = cu_tester # ADD YOUR NEW TEST FILE HERE (1/1) OBJS = \ cu_tester.o \ + cu_pc_bytes.o \ cu_pc_schema.o \ cu_pc_point.o \ cu_pc_patch.o \ diff --git a/lib/cunit/cu_pc_bytes.c b/lib/cunit/cu_pc_bytes.c new file mode 100644 index 0000000..b0df39d --- /dev/null +++ b/lib/cunit/cu_pc_bytes.c @@ -0,0 +1,474 @@ +/*********************************************************************** +* cu_pc_schema.c +* +* Testing for the schema API functions +* +* Portions Copyright (c) 2012, OpenGeo +* +***********************************************************************/ + +#include "CUnit/Basic.h" +#include "cu_tester.h" + +/* GLOBALS ************************************************************/ + +static PCSCHEMA *schema = NULL; +static const char *xmlfile = "data/pdal-schema.xml"; + +/* Setup/teardown for this suite */ +static int +init_suite(void) +{ + char *xmlstr = file_to_str(xmlfile); + int rv = pc_schema_from_xml(xmlstr, &schema); + pcfree(xmlstr); + if ( rv == PC_FAILURE ) return 1; + + return 0; +} + +static int +clean_suite(void) +{ + pc_schema_free(schema); + return 0; +} + + +/* TESTS **************************************************************/ + + +static PCBYTES initbytes(uint8_t *bytes, size_t size, uint32_t interp) +{ + PCBYTES pcb; + pcb.bytes = bytes; + pcb.size = size; + pcb.interpretation = interp; + pcb.npoints = pcb.size / pc_interpretation_size(pcb.interpretation); + pcb.compression = PC_DIM_NONE; + pcb.readonly = PC_TRUE; + return pcb; +} + +/* +* Run-length encode a byte stream by word. +* Lots of identical words means great +* compression ratios. +*/ +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; + PCBYTES pcb, epcb, pcb2; + +/* +typedef struct +{ + size_t size; + uint32_t npoints; + uint32_t interpretation; + uint32_t compression; + uint8_t *bytes; +} PCBYTES; +*/ + + bytes = "aaaabbbbccdde"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 5); + + bytes = "a"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 1); + + bytes = "aa"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 1); + + bytes = "ab"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 2); + + bytes = "abcdefg"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 7); + + bytes = "aabcdefg"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 7); + + bytes = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + nr = pc_bytes_run_count(&pcb); + CU_ASSERT_EQUAL(nr, 1); + + epcb = pc_bytes_run_length_encode(pcb); + pcb2 = pc_bytes_run_length_decode(epcb); + + CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); + CU_ASSERT_EQUAL(pcb.size, pcb2.size); + CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); + pc_bytes_free(epcb); + pc_bytes_free(pcb2); + + bytes = "aabcdefg"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + epcb = pc_bytes_run_length_encode(pcb); + pcb2 = pc_bytes_run_length_decode(epcb); + CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); + CU_ASSERT_EQUAL(pcb.size, pcb2.size); + CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); + pc_bytes_free(epcb); + pc_bytes_free(pcb2); + + bytes = (uint8_t*)((uint32_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 }); + pcb = initbytes(bytes, 8, PC_UINT32); + epcb = pc_bytes_run_length_encode(pcb); + pcb2 = pc_bytes_run_length_decode(epcb); + CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); + CU_ASSERT_EQUAL(pcb.size, pcb2.size); + CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); + pc_bytes_free(epcb); + pc_bytes_free(pcb2); + + bytes = (uint8_t*)((uint16_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 }); + pcb = initbytes(bytes, 8, PC_UINT16); + epcb = pc_bytes_run_length_encode(pcb); + pcb2 = pc_bytes_run_length_decode(epcb); + CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); + CU_ASSERT_EQUAL(pcb.size, pcb2.size); + CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); + pc_bytes_free(epcb); + pc_bytes_free(pcb2); + +} + +/* +* Strip the common bits off a stream and pack the +* remaining bits in behind. Test bit counting and +* round-trip encode/decode paths. +*/ +static void +test_sigbits_encoding() +{ + int i; + uint8_t *bytes, *ebytes; + uint16_t *bytes16, *ebytes16; + uint32_t *bytes32, *ebytes32; + size_t ebytes_size; + + uint32_t count, nelems; + uint8_t common8; + uint16_t common16; + uint32_t common32; + PCBYTES pcb, epcb, pcb2; + + /* + 01100001 a + 01100010 b + 01100011 c + 01100000 ` + */ + bytes = "abc"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + common8 = pc_bytes_sigbits_count_8(&pcb, &count); + CU_ASSERT_EQUAL(count, 6); + CU_ASSERT_EQUAL(common8, '`'); + + bytes = "abcdef"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + common8 = pc_bytes_sigbits_count_8(&pcb, &count); + CU_ASSERT_EQUAL(count, 5); + CU_ASSERT_EQUAL(common8, '`'); + + /* + 0110000101100001 aa + 0110001001100010 bb + 0110001101100011 cc + 0110000000000000 24576 + */ + bytes = "aabbcc"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT16); + count = pc_bytes_sigbits_count(&pcb); + CU_ASSERT_EQUAL(count, 6); + + /* + "abca" encoded: + base a b c a + 01100000 01 10 11 01 + */ + bytes = "abcaabcaabcbabcc"; + pcb = initbytes(bytes, strlen(bytes), PC_INT8); + epcb = pc_bytes_sigbits_encode(pcb); + CU_ASSERT_EQUAL(epcb.bytes[0], 2); /* unique bit count */ + CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */ + CU_ASSERT_EQUAL(epcb.bytes[2], 109); /* packed byte */ + CU_ASSERT_EQUAL(epcb.bytes[3], 109); /* packed byte */ + CU_ASSERT_EQUAL(epcb.bytes[4], 110); /* packed byte */ + CU_ASSERT_EQUAL(epcb.bytes[5], 111); /* packed byte */ + pc_bytes_free(epcb); + + /* + "abca" encoded: + base a b c d a b + 01100000 001 010 011 100 001 010 + */ + bytes = "abcdab"; + pcb = initbytes(bytes, strlen(bytes), PC_INT8); + epcb = pc_bytes_sigbits_encode(pcb); + CU_ASSERT_EQUAL(epcb.bytes[0], 3); /* unique bit count */ + CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */ + CU_ASSERT_EQUAL(epcb.bytes[2], 41); /* packed byte */ + CU_ASSERT_EQUAL(epcb.bytes[3], 194); /* packed byte */ + + pcb2 = pc_bytes_sigbits_decode(epcb); + CU_ASSERT_EQUAL(pcb2.bytes[0], 'a'); + CU_ASSERT_EQUAL(pcb2.bytes[1], 'b'); + CU_ASSERT_EQUAL(pcb2.bytes[2], 'c'); + CU_ASSERT_EQUAL(pcb2.bytes[3], 'd'); + CU_ASSERT_EQUAL(pcb2.bytes[4], 'a'); + CU_ASSERT_EQUAL(pcb2.bytes[5], 'b'); + pc_bytes_free(pcb2); + pc_bytes_free(epcb); + + /* Test the 16 bit implementation path */ + nelems = 6; + bytes16 = (uint16_t[]){ + 24929, /* 0110000101100001 */ + 24930, /* 0110000101100010 */ + 24931, /* 0110000101100011 */ + 24932, /* 0110000101100100 */ + 24933, /* 0110000101100101 */ + 24934 /* 0110000101100110 */ + }; + /* encoded 0110000101100 001 010 011 100 101 110 */ + bytes = (uint8_t*)bytes16; + pcb = initbytes(bytes, nelems*2, PC_INT16); + + /* Test the 16 bit implementation path */ + common16 = pc_bytes_sigbits_count_16(&pcb, &count); + CU_ASSERT_EQUAL(common16, 24928); + CU_ASSERT_EQUAL(count, 13); + epcb = pc_bytes_sigbits_encode(pcb); + ebytes16 = (uint16_t*)(epcb.bytes); + // printf("commonbits %d\n", commonbits); + CU_ASSERT_EQUAL(ebytes16[0], 3); /* unique bit count */ + CU_ASSERT_EQUAL(ebytes16[1], 24928); /* common bits */ + CU_ASSERT_EQUAL(ebytes16[2], 10699); /* packed uint16 one */ + + /* uint8_t* pc_bytes_sigbits_decode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems) */ + pcb2 = pc_bytes_sigbits_decode(epcb); + pc_bytes_free(epcb); + bytes16 = (uint16_t*)(pcb2.bytes); + CU_ASSERT_EQUAL(bytes16[0], 24929); + CU_ASSERT_EQUAL(bytes16[1], 24930); + CU_ASSERT_EQUAL(bytes16[2], 24931); + CU_ASSERT_EQUAL(bytes16[3], 24932); + CU_ASSERT_EQUAL(bytes16[4], 24933); + CU_ASSERT_EQUAL(bytes16[5], 24934); + pc_bytes_free(pcb2); + + /* Test the 32 bit implementation path */ + nelems = 6; + + bytes32 = (uint32_t[]){ + 103241, /* 0000000000000001 1001 0011 0100 1001 */ + 103251, /* 0000000000000001 1001 0011 0101 0011 */ + 103261, /* 0000000000000001 1001 0011 0101 1101 */ + 103271, /* 0000000000000001 1001 0011 0110 0111 */ + 103281, /* 0000000000000001 1001 0011 0111 0001 */ + 103291 /* 0000000000000001 1001 0011 0111 1011 */ + }; + bytes = (uint8_t*)bytes32; + pcb = initbytes(bytes, nelems*4, PC_INT32); + + common32 = pc_bytes_sigbits_count_32(&pcb, &count); + CU_ASSERT_EQUAL(count, 26); /* unique bit count */ + CU_ASSERT_EQUAL(common32, 103232); + + epcb = pc_bytes_sigbits_encode(pcb); + ebytes32 = (uint32_t*)(epcb.bytes); + CU_ASSERT_EQUAL(ebytes32[0], 6); /* unique bit count */ + CU_ASSERT_EQUAL(ebytes32[1], 103232); /* common bits */ + CU_ASSERT_EQUAL(ebytes32[2], 624388039); /* packed uint32 */ + + pcb2 = pc_bytes_sigbits_decode(epcb); + pc_bytes_free(epcb); + bytes32 = (uint32_t*)(pcb2.bytes); + CU_ASSERT_EQUAL(bytes32[0], 103241); + CU_ASSERT_EQUAL(bytes32[1], 103251); + CU_ASSERT_EQUAL(bytes32[2], 103261); + CU_ASSERT_EQUAL(bytes32[3], 103271); + CU_ASSERT_EQUAL(bytes32[4], 103281); + CU_ASSERT_EQUAL(bytes32[5], 103291); + pc_bytes_free(pcb2); + + /* What if all the words are the same? */ + nelems = 6; + bytes16 = (uint16_t[]){ + 24929, /* 0000000000000001 1001 0011 0100 1001 */ + 24929, /* 0000000000000001 1001 0011 0101 0011 */ + 24929, /* 0000000000000001 1001 0011 0101 1101 */ + 24929, /* 0000000000000001 1001 0011 0110 0111 */ + 24929, /* 0000000000000001 1001 0011 0111 0001 */ + 24929 /* 0000000000000001 1001 0011 0111 1011 */ + }; + bytes = (uint8_t*)bytes16; + pcb = initbytes(bytes, nelems*2, PC_INT16); + epcb = pc_bytes_sigbits_encode(pcb); + pcb2 = pc_bytes_sigbits_decode(epcb); + pc_bytes_free(epcb); + pc_bytes_free(pcb2); + +} + +/* +* Encode and decode a byte stream. Data matches? +*/ +static void +test_zlib_encoding() +{ + uint8_t *bytes, *ebytes; + uint32_t i; + PCBYTES pcb, epcb, pcb2; + /* + uint8_t * + pc_bytes_zlib_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems) + uint8_t * + pc_bytes_zlib_decode(const uint8_t *bytes, uint32_t interpretation) + */ + bytes = "abcaabcaabcbabcc"; + pcb = initbytes(bytes, strlen(bytes), PC_INT8); + epcb = pc_bytes_zlib_encode(pcb); + pcb2 = pc_bytes_zlib_decode(epcb); + CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); + pc_bytes_free(epcb); + pc_bytes_free(pcb2); +} + + +static void +test_rle_filter() +{ + char *bytes; + PCBYTES pcb, epcb, fpcb; + PCBITMAP *map1, *map2; + + /* + typedef struct + { + size_t size; + uint32_t npoints; + uint32_t interpretation; + uint32_t compression; + uint8_t *bytes; + } PCBYTES; + */ + + bytes = "aaaabbbbccdd"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + epcb = pc_bytes_run_length_encode(pcb); + CU_ASSERT_EQUAL(epcb.bytes[0], 4); + + map1 = pc_bytes_bitmap(&epcb, PC_GT, 'b', 'b'); + CU_ASSERT_EQUAL(map1->nset, 4); + map2 = pc_bytes_bitmap(&epcb, PC_GT, 'a', 'a'); + CU_ASSERT_EQUAL(map2->nset, 8); + + fpcb = pc_bytes_filter(&epcb, map1); + CU_ASSERT_EQUAL(fpcb.bytes[0], 2); + CU_ASSERT_EQUAL(fpcb.bytes[1], 'c'); + CU_ASSERT_EQUAL(fpcb.bytes[2], 2); + CU_ASSERT_EQUAL(fpcb.bytes[3], 'd'); + CU_ASSERT_EQUAL(fpcb.size, 4); + CU_ASSERT_EQUAL(fpcb.npoints, 4); + pc_bytes_free(fpcb); + pc_bitmap_free(map1); + + fpcb = pc_bytes_filter(&epcb, map2); + CU_ASSERT_EQUAL(fpcb.bytes[0], 4); + CU_ASSERT_EQUAL(fpcb.bytes[1], 'b'); + CU_ASSERT_EQUAL(fpcb.bytes[2], 2); + CU_ASSERT_EQUAL(fpcb.bytes[3], 'c'); + CU_ASSERT_EQUAL(fpcb.size, 6); + CU_ASSERT_EQUAL(fpcb.npoints, 8); + pc_bytes_free(fpcb); + pc_bitmap_free(map2); + pc_bytes_free(epcb); + + bytes = (uint8_t*)((uint32_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 }); + pcb = initbytes(bytes, 32, PC_UINT32); + epcb = pc_bytes_run_length_encode(pcb); + map1 = pc_bytes_bitmap(&epcb, PC_LT, 25, 25); + CU_ASSERT_EQUAL(map1->nset, 7); + fpcb = pc_bytes_filter(&epcb, map1); + CU_ASSERT_EQUAL(fpcb.size, 15); + CU_ASSERT_EQUAL(fpcb.npoints, 7); + + pc_bytes_free(fpcb); + + pc_bytes_free(epcb); +} + + + +static void +test_uncompressed_filter() +{ + char *bytes; + PCBYTES pcb, epcb, fpcb; + PCBITMAP *map1, *map2; + + /* + typedef struct + { + size_t size; + uint32_t npoints; + uint32_t interpretation; + uint32_t compression; + uint8_t *bytes; + } PCBYTES; + */ + + bytes = "aaaabbbbccdd"; + pcb = initbytes(bytes, strlen(bytes), PC_UINT8); + CU_ASSERT_EQUAL(pcb.bytes[0], 'a'); + CU_ASSERT_EQUAL(pcb.npoints, 12); + + map1 = pc_bytes_bitmap(&pcb, PC_GT, 'b', 'b'); + CU_ASSERT_EQUAL(map1->nset, 4); + + fpcb = pc_bytes_filter(&pcb, map1); + CU_ASSERT_EQUAL(fpcb.bytes[0], 'c'); + CU_ASSERT_EQUAL(fpcb.size, 4); + CU_ASSERT_EQUAL(fpcb.npoints, 4); + pc_bytes_free(fpcb); + +// pc_bytes_free(epcb); + +} + + +/* REGISTER ***********************************************************/ + +CU_TestInfo bytes_tests[] = { + PC_TEST(test_run_length_encoding), + PC_TEST(test_sigbits_encoding), + PC_TEST(test_zlib_encoding), + PC_TEST(test_rle_filter), + PC_TEST(test_uncompressed_filter), + CU_TEST_INFO_NULL +}; + +CU_SuiteInfo bytes_suite = {"bytes", init_suite, clean_suite, bytes_tests}; diff --git a/lib/cunit/cu_pc_patch.c b/lib/cunit/cu_pc_patch.c index dbb3e52..79fe0a6 100644 --- a/lib/cunit/cu_pc_patch.c +++ b/lib/cunit/cu_pc_patch.c @@ -222,323 +222,7 @@ test_schema_xy() } -static PCBYTES initbytes(uint8_t *bytes, size_t size, uint32_t interp) -{ - PCBYTES pcb; - pcb.bytes = bytes; - pcb.size = size; - pcb.interpretation = interp; - pcb.npoints = pcb.size / pc_interpretation_size(pcb.interpretation); - pcb.compression = PC_DIM_NONE; - return pcb; -} -/* -* Run-length encode a byte stream by word. -* Lots of identical words means great -* compression ratios. -*/ -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; - PCBYTES pcb, epcb, pcb2; - -/* -typedef struct -{ - size_t size; - uint32_t npoints; - uint32_t interpretation; - uint32_t compression; - uint8_t *bytes; -} PCBYTES; -*/ - - bytes = "aaaabbbbccdde"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 5); - - bytes = "a"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 1); - - bytes = "aa"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 1); - - bytes = "ab"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 2); - - bytes = "abcdefg"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 7); - - bytes = "aabcdefg"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 7); - - bytes = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - nr = pc_bytes_run_count(&pcb); - CU_ASSERT_EQUAL(nr, 1); - - epcb = pc_bytes_run_length_encode(pcb); - pcb2 = pc_bytes_run_length_decode(epcb); - - CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); - CU_ASSERT_EQUAL(pcb.size, pcb2.size); - CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); - pc_bytes_free(epcb); - pc_bytes_free(pcb2); - - bytes = "aabcdefg"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - epcb = pc_bytes_run_length_encode(pcb); - pcb2 = pc_bytes_run_length_decode(epcb); - CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); - CU_ASSERT_EQUAL(pcb.size, pcb2.size); - CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); - pc_bytes_free(epcb); - pc_bytes_free(pcb2); - - bytes = (uint8_t*)((uint32_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 }); - pcb = initbytes(bytes, 8, PC_UINT32); - epcb = pc_bytes_run_length_encode(pcb); - pcb2 = pc_bytes_run_length_decode(epcb); - CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); - CU_ASSERT_EQUAL(pcb.size, pcb2.size); - CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); - pc_bytes_free(epcb); - pc_bytes_free(pcb2); - - bytes = (uint8_t*)((uint16_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 }); - pcb = initbytes(bytes, 8, PC_UINT16); - epcb = pc_bytes_run_length_encode(pcb); - pcb2 = pc_bytes_run_length_decode(epcb); - CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); - CU_ASSERT_EQUAL(pcb.size, pcb2.size); - CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints); - pc_bytes_free(epcb); - pc_bytes_free(pcb2); - -} - -/* -* Strip the common bits off a stream and pack the -* remaining bits in behind. Test bit counting and -* round-trip encode/decode paths. -*/ -static void -test_sigbits_encoding() -{ - int i; - uint8_t *bytes, *ebytes; - uint16_t *bytes16, *ebytes16; - uint32_t *bytes32, *ebytes32; - size_t ebytes_size; - - uint32_t count, nelems; - uint8_t common8; - uint16_t common16; - uint32_t common32; - PCBYTES pcb, epcb, pcb2; - - /* - 01100001 a - 01100010 b - 01100011 c - 01100000 ` - */ - bytes = "abc"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - common8 = pc_bytes_sigbits_count_8(&pcb, &count); - CU_ASSERT_EQUAL(count, 6); - CU_ASSERT_EQUAL(common8, '`'); - - bytes = "abcdef"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT8); - common8 = pc_bytes_sigbits_count_8(&pcb, &count); - CU_ASSERT_EQUAL(count, 5); - CU_ASSERT_EQUAL(common8, '`'); - - /* - 0110000101100001 aa - 0110001001100010 bb - 0110001101100011 cc - 0110000000000000 24576 - */ - bytes = "aabbcc"; - pcb = initbytes(bytes, strlen(bytes), PC_UINT16); - count = pc_bytes_sigbits_count(&pcb); - CU_ASSERT_EQUAL(count, 6); - - /* - "abca" encoded: - base a b c a - 01100000 01 10 11 01 - */ - bytes = "abcaabcaabcbabcc"; - pcb = initbytes(bytes, strlen(bytes), PC_INT8); - epcb = pc_bytes_sigbits_encode(pcb); - CU_ASSERT_EQUAL(epcb.bytes[0], 2); /* unique bit count */ - CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */ - CU_ASSERT_EQUAL(epcb.bytes[2], 109); /* packed byte */ - CU_ASSERT_EQUAL(epcb.bytes[3], 109); /* packed byte */ - CU_ASSERT_EQUAL(epcb.bytes[4], 110); /* packed byte */ - CU_ASSERT_EQUAL(epcb.bytes[5], 111); /* packed byte */ - pc_bytes_free(epcb); - - /* - "abca" encoded: - base a b c d a b - 01100000 001 010 011 100 001 010 - */ - bytes = "abcdab"; - pcb = initbytes(bytes, strlen(bytes), PC_INT8); - epcb = pc_bytes_sigbits_encode(pcb); - CU_ASSERT_EQUAL(epcb.bytes[0], 3); /* unique bit count */ - CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */ - CU_ASSERT_EQUAL(epcb.bytes[2], 41); /* packed byte */ - CU_ASSERT_EQUAL(epcb.bytes[3], 194); /* packed byte */ - - pcb2 = pc_bytes_sigbits_decode(epcb); - CU_ASSERT_EQUAL(pcb2.bytes[0], 'a'); - CU_ASSERT_EQUAL(pcb2.bytes[1], 'b'); - CU_ASSERT_EQUAL(pcb2.bytes[2], 'c'); - CU_ASSERT_EQUAL(pcb2.bytes[3], 'd'); - CU_ASSERT_EQUAL(pcb2.bytes[4], 'a'); - CU_ASSERT_EQUAL(pcb2.bytes[5], 'b'); - pc_bytes_free(pcb2); - pc_bytes_free(epcb); - - /* Test the 16 bit implementation path */ - nelems = 6; - bytes16 = (uint16_t[]){ - 24929, /* 0110000101100001 */ - 24930, /* 0110000101100010 */ - 24931, /* 0110000101100011 */ - 24932, /* 0110000101100100 */ - 24933, /* 0110000101100101 */ - 24934 /* 0110000101100110 */ - }; - /* encoded 0110000101100 001 010 011 100 101 110 */ - bytes = (uint8_t*)bytes16; - pcb = initbytes(bytes, nelems*2, PC_INT16); - - /* Test the 16 bit implementation path */ - common16 = pc_bytes_sigbits_count_16(&pcb, &count); - CU_ASSERT_EQUAL(common16, 24928); - CU_ASSERT_EQUAL(count, 13); - epcb = pc_bytes_sigbits_encode(pcb); - ebytes16 = (uint16_t*)(epcb.bytes); - // printf("commonbits %d\n", commonbits); - CU_ASSERT_EQUAL(ebytes16[0], 3); /* unique bit count */ - CU_ASSERT_EQUAL(ebytes16[1], 24928); /* common bits */ - CU_ASSERT_EQUAL(ebytes16[2], 10699); /* packed uint16 one */ - - /* uint8_t* pc_bytes_sigbits_decode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems) */ - pcb2 = pc_bytes_sigbits_decode(epcb); - pc_bytes_free(epcb); - bytes16 = (uint16_t*)(pcb2.bytes); - CU_ASSERT_EQUAL(bytes16[0], 24929); - CU_ASSERT_EQUAL(bytes16[1], 24930); - CU_ASSERT_EQUAL(bytes16[2], 24931); - CU_ASSERT_EQUAL(bytes16[3], 24932); - CU_ASSERT_EQUAL(bytes16[4], 24933); - CU_ASSERT_EQUAL(bytes16[5], 24934); - pc_bytes_free(pcb2); - - /* Test the 32 bit implementation path */ - nelems = 6; - - bytes32 = (uint32_t[]){ - 103241, /* 0000000000000001 1001 0011 0100 1001 */ - 103251, /* 0000000000000001 1001 0011 0101 0011 */ - 103261, /* 0000000000000001 1001 0011 0101 1101 */ - 103271, /* 0000000000000001 1001 0011 0110 0111 */ - 103281, /* 0000000000000001 1001 0011 0111 0001 */ - 103291 /* 0000000000000001 1001 0011 0111 1011 */ - }; - bytes = (uint8_t*)bytes32; - pcb = initbytes(bytes, nelems*4, PC_INT32); - - common32 = pc_bytes_sigbits_count_32(&pcb, &count); - CU_ASSERT_EQUAL(count, 26); /* unique bit count */ - CU_ASSERT_EQUAL(common32, 103232); - - epcb = pc_bytes_sigbits_encode(pcb); - ebytes32 = (uint32_t*)(epcb.bytes); - CU_ASSERT_EQUAL(ebytes32[0], 6); /* unique bit count */ - CU_ASSERT_EQUAL(ebytes32[1], 103232); /* common bits */ - CU_ASSERT_EQUAL(ebytes32[2], 624388039); /* packed uint32 */ - - pcb2 = pc_bytes_sigbits_decode(epcb); - pc_bytes_free(epcb); - bytes32 = (uint32_t*)(pcb2.bytes); - CU_ASSERT_EQUAL(bytes32[0], 103241); - CU_ASSERT_EQUAL(bytes32[1], 103251); - CU_ASSERT_EQUAL(bytes32[2], 103261); - CU_ASSERT_EQUAL(bytes32[3], 103271); - CU_ASSERT_EQUAL(bytes32[4], 103281); - CU_ASSERT_EQUAL(bytes32[5], 103291); - pc_bytes_free(pcb2); - - /* What if all the words are the same? */ - nelems = 6; - bytes16 = (uint16_t[]){ - 24929, /* 0000000000000001 1001 0011 0100 1001 */ - 24929, /* 0000000000000001 1001 0011 0101 0011 */ - 24929, /* 0000000000000001 1001 0011 0101 1101 */ - 24929, /* 0000000000000001 1001 0011 0110 0111 */ - 24929, /* 0000000000000001 1001 0011 0111 0001 */ - 24929 /* 0000000000000001 1001 0011 0111 1011 */ - }; - bytes = (uint8_t*)bytes16; - pcb = initbytes(bytes, nelems*2, PC_INT16); - epcb = pc_bytes_sigbits_encode(pcb); - pcb2 = pc_bytes_sigbits_decode(epcb); - pc_bytes_free(epcb); - pc_bytes_free(pcb2); - -} - -/* -* Encode and decode a byte stream. Data matches? -*/ -static void -test_zlib_encoding() -{ - uint8_t *bytes, *ebytes; - uint32_t i; - PCBYTES pcb, epcb, pcb2; - /* - uint8_t * - pc_bytes_zlib_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems) - uint8_t * - pc_bytes_zlib_decode(const uint8_t *bytes, uint32_t interpretation) - */ - bytes = "abcaabcaabcbabcc"; - pcb = initbytes(bytes, strlen(bytes), PC_INT8); - epcb = pc_bytes_zlib_encode(pcb); - pcb2 = pc_bytes_zlib_decode(epcb); - CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0); - pc_bytes_free(epcb); - pc_bytes_free(pcb2); -} /** * Pivot a pointlist into a dimlist and back. @@ -832,9 +516,6 @@ CU_TestInfo patch_tests[] = { PC_TEST(test_patch_hex_in), PC_TEST(test_patch_hex_out), PC_TEST(test_schema_xy), - PC_TEST(test_run_length_encoding), - PC_TEST(test_sigbits_encoding), - PC_TEST(test_zlib_encoding), PC_TEST(test_patch_dimensional), PC_TEST(test_patch_dimensional_compression), PC_TEST(test_patch_union), diff --git a/lib/cunit/cu_pc_point.c b/lib/cunit/cu_pc_point.c index ca971a4..ddec4d9 100644 --- a/lib/cunit/cu_pc_point.c +++ b/lib/cunit/cu_pc_point.c @@ -82,11 +82,66 @@ test_point_hex_inout() } +static void +test_point_access() +{ + PCPOINT *pt; + int rv; + double a1, a2, a3, a4, b1, b2, b3, b4; + int idx = 0; + + pt = pc_point_make(schema); + CU_ASSERT( pt != NULL ); + + /* One at a time */ + idx = 0; + a1 = 1.5; + rv = pc_point_set_double_by_index(pt, idx, a1); + rv = pc_point_get_double_by_index(pt, idx, &b1); + // printf("d1=%g, d2=%g\n", a1, b1); + CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001); + + idx = 2; + a2 = 1501500.12; + rv = pc_point_set_double_by_index(pt, idx, a2); + rv = pc_point_get_double_by_index(pt, idx, &b2); + CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001); + + a3 = 91; + rv = pc_point_set_double_by_name(pt, "Intensity", a3); + rv = pc_point_get_double_by_name(pt, "Intensity", &b3); + CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001); + + pc_point_free(pt); + + /* All at once */ + pt = pc_point_make(schema); + a1 = 1.5; + a2 = 1501500.12; + a3 = 91; + a4 = 200; + rv = pc_point_set_double_by_index(pt, 0, a1); + rv = pc_point_set_double_by_index(pt, 1, a2); + rv = pc_point_set_double_by_name(pt, "Intensity", a3); + rv = pc_point_set_double_by_name(pt, "Z", a4); + rv = pc_point_get_double_by_index(pt, 0, &b1); + rv = pc_point_get_double_by_index(pt, 1, &b2); + rv = pc_point_get_double_by_name(pt, "Intensity", &b3); + rv = pc_point_get_double_by_name(pt, "Z", &b4); + CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001); + CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001); + CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001); + CU_ASSERT_DOUBLE_EQUAL(a4, b4, 0.0000001); + + pc_point_free(pt); + +} /* REGISTER ***********************************************************/ CU_TestInfo point_tests[] = { PC_TEST(test_point_hex_inout), + PC_TEST(test_point_access), CU_TEST_INFO_NULL }; diff --git a/lib/cunit/cu_pc_schema.c b/lib/cunit/cu_pc_schema.c index 9458289..813f272 100644 --- a/lib/cunit/cu_pc_schema.c +++ b/lib/cunit/cu_pc_schema.c @@ -115,60 +115,7 @@ test_dimension_byteoffsets() } -static void -test_point_access() -{ - PCPOINT *pt; - int rv; - double a1, a2, a3, a4, b1, b2, b3, b4; - int idx = 0; - pt = pc_point_make(schema); - CU_ASSERT( pt != NULL ); - - /* One at a time */ - idx = 0; - a1 = 1.5; - rv = pc_point_set_double_by_index(pt, idx, a1); - rv = pc_point_get_double_by_index(pt, idx, &b1); - // printf("d1=%g, d2=%g\n", a1, b1); - CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001); - - idx = 2; - a2 = 1501500.12; - rv = pc_point_set_double_by_index(pt, idx, a2); - rv = pc_point_get_double_by_index(pt, idx, &b2); - CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001); - - a3 = 91; - rv = pc_point_set_double_by_name(pt, "NumberOfReturns", a3); - rv = pc_point_get_double_by_name(pt, "NumberOfReturns", &b3); - CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001); - - pc_point_free(pt); - - /* All at once */ - pt = pc_point_make(schema); - a1 = 1.5; - a2 = 1501500.12; - a3 = 91; - a4 = 200; - rv = pc_point_set_double_by_index(pt, 0, a1); - rv = pc_point_set_double_by_index(pt, 2, a2); - rv = pc_point_set_double_by_name(pt, "NumberOfReturns", a3); - rv = pc_point_set_double_by_name(pt, "UserData", a4); - rv = pc_point_get_double_by_index(pt, 0, &b1); - rv = pc_point_get_double_by_index(pt, 2, &b2); - rv = pc_point_get_double_by_name(pt, "NumberOfReturns", &b3); - rv = pc_point_get_double_by_name(pt, "UserData", &b4); - CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001); - CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001); - CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001); - CU_ASSERT_DOUBLE_EQUAL(a4, b4, 0.0000001); - - pc_point_free(pt); - -} static void test_schema_compression(void) @@ -184,7 +131,6 @@ CU_TestInfo schema_tests[] = { PC_TEST(test_schema_size), PC_TEST(test_dimension_get), PC_TEST(test_dimension_byteoffsets), - PC_TEST(test_point_access), PC_TEST(test_schema_compression), CU_TEST_INFO_NULL }; diff --git a/lib/cunit/cu_tester.c b/lib/cunit/cu_tester.c index 349fdce..8b83b9a 100644 --- a/lib/cunit/cu_tester.c +++ b/lib/cunit/cu_tester.c @@ -17,6 +17,7 @@ extern CU_SuiteInfo schema_suite; extern CU_SuiteInfo patch_suite; extern CU_SuiteInfo point_suite; extern CU_SuiteInfo ght_suite; +extern CU_SuiteInfo bytes_suite; /* ** The main() function for setting up and running the tests. @@ -32,6 +33,7 @@ int main(int argc, char *argv[]) patch_suite, point_suite, ght_suite, + bytes_suite, CU_SUITE_INFO_NULL }; diff --git a/lib/pc_api.h b/lib/pc_api.h index a6223c3..a2c244b 100644 --- a/lib/pc_api.h +++ b/lib/pc_api.h @@ -372,7 +372,7 @@ uint8_t* pc_patch_to_wkb(const PCPATCH *patch, size_t *wkbsize); /** Returns text form of patch */ char* pc_patch_to_string(const PCPATCH *patch); -/** */ +/** Return byte buffer size of serialization */ size_t pc_patch_dimensional_serialized_size(const PCPATCH_DIMENSIONAL *patch); /** How big will the serialization be? */ @@ -402,8 +402,17 @@ int pc_patch_compute_extent(PCPATCH *patch); /** True/false if bounds intersect */ int pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2); -/** Returns newly allocated patch that only contains the points fitting the filter condition */ -PCPATCH* pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2); +/** Subset batch based on less-than condition on dimension */ +PCPATCH* pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name, double val); + +/** Subset batch based on greater-than condition on dimension */ +PCPATCH* pc_patch_filter_gt_by_name(const PCPATCH *pa, const char *name, double val); + +/** Subset batch based on equality condition on dimension */ +PCPATCH* pc_patch_filter_equal_by_name(const PCPATCH *pa, const char *name, double val); + +/** Subset batch based on range condition on dimension */ +PCPATCH* pc_patch_filter_between_by_name(const PCPATCH *pa, const char *name, double val1, double val2); #endif /* _PC_API_H */ diff --git a/lib/pc_api_internal.h b/lib/pc_api_internal.h index 0f14094..d73d72f 100644 --- a/lib/pc_api_internal.h +++ b/lib/pc_api_internal.h @@ -149,6 +149,9 @@ char* pc_dimstats_to_string(const PCDIMSTATS *pds); * PATCHES */ +/** Returns newly allocated patch that only contains the points fitting the filter condition */ +PCPATCH* pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2); + /* DIMENSIONAL PATCHES */ char* pc_patch_dimensional_to_string(const PCPATCH_DIMENSIONAL *pa); PCPATCH_DIMENSIONAL* pc_patch_dimensional_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa); diff --git a/lib/pc_bytes.c b/lib/pc_bytes.c index 0afc4e3..afb3f33 100644 --- a/lib/pc_bytes.c +++ b/lib/pc_bytes.c @@ -31,6 +31,11 @@ pc_bytes_free(PCBYTES pcb) pcfree(pcb.bytes); } +int pc_bytes_empty(const PCBYTES *pcb) +{ + return pcb->npoints == 0 || pcb->bytes == NULL || pcb->size == 0; +} + PCBYTES pc_bytes_make(const PCDIMENSION *dim, uint32_t npoints) { @@ -48,8 +53,11 @@ static PCBYTES pc_bytes_clone(PCBYTES pcb) { PCBYTES pcbnew = pcb; - pcbnew.bytes = pcalloc(pcb.size); - memcpy(pcbnew.bytes, pcb.bytes, pcb.size); + if ( ! pc_bytes_empty(&pcb) ) + { + pcbnew.bytes = pcalloc(pcb.size); + memcpy(pcbnew.bytes, pcb.bytes, pcb.size); + } pcbnew.readonly = PC_FALSE; return pcbnew; } @@ -552,6 +560,7 @@ pc_bytes_sigbits_encode_8(const PCBYTES pcb, uint8_t commonvalue, uint8_t common pcbout.size = size_out; pcbout.bytes = bytes_out; pcbout.compression = PC_DIM_SIGBITS; + pcbout.readonly = PC_FALSE; return pcbout; } @@ -643,6 +652,7 @@ pc_bytes_sigbits_encode_16(const PCBYTES pcb, uint16_t commonvalue, uint8_t comm pcbout.size = size_out; pcbout.bytes = bytes_out; pcbout.compression = PC_DIM_SIGBITS; + pcbout.readonly = PC_FALSE; return pcbout; } @@ -733,6 +743,7 @@ pc_bytes_sigbits_encode_32(const PCBYTES pcb, uint32_t commonvalue, uint8_t comm pcbout.size = size_out; pcbout.bytes = bytes_out; pcbout.compression = PC_DIM_SIGBITS; + pcbout.readonly = PC_FALSE; return pcbout; } @@ -866,6 +877,7 @@ pc_bytes_sigbits_decode_8(const PCBYTES pcb) pcbout.size = outbytes_size; pcbout.compression = PC_DIM_SIGBITS; pcbout.bytes = outbytes; + pcbout.readonly = PC_FALSE; return pcbout; } @@ -922,6 +934,7 @@ pc_bytes_sigbits_decode_16(const PCBYTES pcb) pcbout.size = outbytes_size; pcbout.compression = PC_DIM_SIGBITS; pcbout.bytes = outbytes; + pcbout.readonly = PC_FALSE; return pcbout; } @@ -979,6 +992,7 @@ pc_bytes_sigbits_decode_32(const PCBYTES pcb) pcbout.size = outbytes_size; pcbout.compression = PC_DIM_SIGBITS; pcbout.bytes = outbytes; + pcbout.readonly = PC_FALSE; return pcbout; } @@ -1059,6 +1073,7 @@ pc_bytes_zlib_encode(const PCBYTES pcb) pcbout.size = have; pcbout.bytes = pcalloc(pcbout.size); pcbout.compression = PC_DIM_ZLIB; + pcbout.readonly = PC_FALSE; memcpy(pcbout.bytes, buf, have); pcfree(buf); deflateEnd(&strm); @@ -1082,6 +1097,7 @@ pc_bytes_zlib_decode(const PCBYTES pcb) /* Set up output memory */ pcbout.bytes = pcalloc(pcbout.size); + pcbout.readonly = PC_FALSE; /* Use our own allocators */ strm.zalloc = pc_zlib_alloc; @@ -1336,6 +1352,7 @@ pc_bytes_filter(const PCBYTES *pcb, const PCBITMAP *map) case PC_DIM_NONE: return pc_bytes_uncompressed_filter(pcb, map); + case PC_DIM_RLE: case PC_DIM_SIGBITS: case PC_DIM_ZLIB: { @@ -1347,9 +1364,6 @@ pc_bytes_filter(const PCBYTES *pcb, const PCBITMAP *map) return efpcb; } - case PC_DIM_RLE: - return pc_bytes_run_length_filter(pcb, map); - default: pcerror("%s: unknown compression", __func__); } diff --git a/lib/pc_filter.c b/lib/pc_filter.c index 5efed81..63c92ad 100644 --- a/lib/pc_filter.c +++ b/lib/pc_filter.c @@ -159,7 +159,6 @@ pc_patch_dimensional_filter(const PCPATCH_DIMENSIONAL *pdl, const PCBITMAP *map) return fpdl; } - PCPATCH * pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2) { @@ -171,7 +170,13 @@ pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double case PC_NONE: { PCBITMAP *map = pc_patch_uncompressed_bitmap((PCPATCH_UNCOMPRESSED*)pa, dimnum, filter, val1, val2); - PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_filter((PCPATCH_UNCOMPRESSED*)pa, map); + PCPATCH_UNCOMPRESSED *pu; + if ( map->nset == 0 ) + { + pc_bitmap_free(map); + return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0); + } + pu = pc_patch_uncompressed_filter((PCPATCH_UNCOMPRESSED*)pa, map); pc_bitmap_free(map); paout = (PCPATCH*)pu; break; @@ -180,8 +185,15 @@ pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double { PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_from_ght((PCPATCH_GHT*)pa); PCBITMAP *map = pc_patch_uncompressed_bitmap(pu, dimnum, filter, val1, val2); - PCPATCH_UNCOMPRESSED *pu2 = pc_patch_uncompressed_filter(pu, map); - PCPATCH_GHT *pgh = pc_patch_ght_from_uncompressed(pu2); + PCPATCH_UNCOMPRESSED *pu2; + PCPATCH_GHT *pgh; + if ( map->nset == 0 ) + { + pc_bitmap_free(map); + return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0); + } + pu2 = pc_patch_uncompressed_filter(pu, map); + pgh = pc_patch_ght_from_uncompressed(pu2); pc_patch_free((PCPATCH*)pu); pc_patch_free((PCPATCH*)pu2); paout = (PCPATCH*)pgh; @@ -190,7 +202,13 @@ pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double case PC_DIMENSIONAL: { PCBITMAP *map = pc_patch_dimensional_bitmap((PCPATCH_DIMENSIONAL*)pa, dimnum, filter, val1, val2); - PCPATCH_DIMENSIONAL *pdl = pc_patch_dimensional_filter((PCPATCH_DIMENSIONAL*)pa, map); + PCPATCH_DIMENSIONAL *pdl; + if ( map->nset == 0 ) + { + pc_bitmap_free(map); + return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0); + } + pdl = pc_patch_dimensional_filter((PCPATCH_DIMENSIONAL*)pa, map); pc_bitmap_free(map); paout = (PCPATCH*)pdl; break; @@ -207,3 +225,52 @@ pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double return paout; } + +PCPATCH * +pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name, double val) +{ + /* Error out if we can't find the name */ + PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name); + if ( ! d ) return NULL; + + return pc_patch_filter(pa, d->position, PC_LT, val, val); +} + +PCPATCH * +pc_patch_filter_gt_by_name(const PCPATCH *pa, const char *name, double val) +{ + /* Error out if we can't find the name */ + PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name); + if ( ! d ) return NULL; + + return pc_patch_filter(pa, d->position, PC_GT, val, val); +} + +PCPATCH * +pc_patch_filter_equal_by_name(const PCPATCH *pa, const char *name, double val) +{ + /* Error out if we can't find the name */ + PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name); + if ( ! d ) return NULL; + + return pc_patch_filter(pa, d->position, PC_EQUAL, val, val); +} + +PCPATCH * +pc_patch_filter_between_by_name(const PCPATCH *pa, const char *name, double val1, double val2) +{ + /* Ensure val1 < val2 always */ + if ( val1 > val2 ) + { + double tmp = val1; + val1 = val2; + val2 = tmp; + } + /* Error out if we can't find the name */ + PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name); + if ( ! d ) return NULL; + + return pc_patch_filter(pa, d->position, PC_BETWEEN, val1, val2); +} + + diff --git a/lib/pc_mem.c b/lib/pc_mem.c index c92bc2b..a41547f 100644 --- a/lib/pc_mem.c +++ b/lib/pc_mem.c @@ -124,7 +124,9 @@ void pc_set_handlers(pc_allocator allocator, pc_reallocator reallocator, void * pcalloc(size_t size) { - void *mem = pc_context.alloc(size); + void *mem; + if ( ! size ) return NULL; + mem = pc_context.alloc(size); memset(mem, 0, size); /* Always clean memory */ return mem; } diff --git a/lib/pc_patch_uncompressed.c b/lib/pc_patch_uncompressed.c index 95804f7..0c01472 100644 --- a/lib/pc_patch_uncompressed.c +++ b/lib/pc_patch_uncompressed.c @@ -203,7 +203,7 @@ pc_patch_uncompressed_compute_extent(PCPATCH_UNCOMPRESSED *patch) void pc_patch_uncompressed_free(PCPATCH_UNCOMPRESSED *patch) { - if ( ! patch->readonly ) + if ( patch->data && ! patch->readonly ) { pcfree(patch->data); } diff --git a/pgsql/pc_access.c b/pgsql/pc_access.c index 097d695..f4906fe 100644 --- a/pgsql/pc_access.c +++ b/pgsql/pc_access.c @@ -22,6 +22,7 @@ Datum pcpatch_numpoints(PG_FUNCTION_ARGS); Datum pcpatch_compression(PG_FUNCTION_ARGS); Datum pcpatch_intersects(PG_FUNCTION_ARGS); Datum pcpatch_get_stat(PG_FUNCTION_ARGS); +Datum pcpatch_filter(PG_FUNCTION_ARGS); Datum pcpatch_size(PG_FUNCTION_ARGS); Datum pcpoint_size(PG_FUNCTION_ARGS); Datum pc_version(PG_FUNCTION_ARGS); @@ -633,3 +634,72 @@ Datum pcpatch_get_stat(PG_FUNCTION_ARGS) pfree(dim_str); PG_RETURN_DATUM(DirectFunctionCall1(float8_numeric, Float8GetDatum(double_result))); } + + +/** +* PC_FilterLessThan(patch pcpatch, dimname text, value) returns PcPatch +* PC_FilterGreaterThan(patch pcpatch, dimname text, value) returns PcPatch +* PC_FilterEqual(patch pcpatch, dimname text, value) returns PcPatch +* PC_FilterBetween(patch pcpatch, dimname text, value1, value2) returns PcPatch +*/ +PG_FUNCTION_INFO_V1(pcpatch_filter); +Datum pcpatch_filter(PG_FUNCTION_ARGS) +{ + SERIALIZED_PATCH *serpatch = PG_GETARG_SERPATCH_P(0); + PCSCHEMA *schema = pc_schema_from_pcid(serpatch->pcid, fcinfo); + char *dim_name = text_to_cstring(PG_GETARG_TEXT_P(1)); + float8 value1 = PG_GETARG_FLOAT8(2); + float8 value2 = PG_GETARG_FLOAT8(3); + int32 mode = PG_GETARG_INT32(4); + PCPATCH *patch; + PCPATCH *patch_filtered; + SERIALIZED_PATCH *serpatch_filtered; + + patch = pc_patch_deserialize(serpatch, schema); + if ( ! patch ) + { + elog(ERROR, "failed to deserialize patch"); + PG_RETURN_NULL(); + } + + switch ( mode ) + { + case 0: + patch_filtered = pc_patch_filter_lt_by_name(patch, dim_name, value1); + break; + case 1: + patch_filtered = pc_patch_filter_gt_by_name(patch, dim_name, value1); + break; + case 2: + patch_filtered = pc_patch_filter_equal_by_name(patch, dim_name, value1); + break; + case 3: + patch_filtered = pc_patch_filter_between_by_name(patch, dim_name, value1, value2); + break; + default: + elog(ERROR, "unknown mode \"%d\"", mode); + } + + pc_patch_free(patch); + PG_FREE_IF_COPY(serpatch, 0); + + if ( ! patch_filtered ) + { + elog(ERROR, "dimension \"%s\" does not exist", dim_name); + } + pfree(dim_name); + + if ( patch_filtered->npoints <= 0 ) + { + pc_patch_free(patch_filtered); + PG_RETURN_NULL(); + } + + serpatch_filtered = pc_patch_serialize(patch_filtered, NULL); + pc_patch_free(patch_filtered); + + PG_RETURN_POINTER(serpatch_filtered); +} + + + diff --git a/pgsql/pointcloud--1.0.sql b/pgsql/pointcloud--1.0.sql index 4716c69..f98a298 100644 --- a/pgsql/pointcloud--1.0.sql +++ b/pgsql/pointcloud--1.0.sql @@ -163,6 +163,22 @@ CREATE OR REPLACE FUNCTION PC_PatchAvg(p pcpatch, attr text, stat text default ' RETURNS numeric AS 'MODULE_PATHNAME', 'pcpatch_get_stat' LANGUAGE 'c' IMMUTABLE STRICT; +CREATE OR REPLACE FUNCTION PC_FilterLessThan(p pcpatch, attr text, v1 float8 default 0.0, v2 float8 default 0.0, mode int4 default 0) + RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_filter' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION PC_FilterGreaterThan(p pcpatch, attr text, v1 float8 default 0.0, v2 float8 default 0.0, mode int4 default 1) + RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_filter' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION PC_FilterEquals(p pcpatch, attr text, v1 float8 default 0.0, v2 float8 default 0.0, mode int4 default 2) + RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_filter' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION PC_FilterBetween(p pcpatch, attr text, v1 float8 default 0.0, v2 float8 default 0.0, mode int4 default 3) + RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_filter' + LANGUAGE 'c' IMMUTABLE STRICT; + ------------------------------------------------------------------- -- POINTCLOUD_COLUMNS -------------------------------------------------------------------