diff --git a/lib/cmp_icu_new.c b/lib/cmp_icu_new.c index e6f6752e6297f68c8cae3971066191cb8ae3ca9b..f4bec3665d54726e3910055fc0f20a0f02053aca 100644 --- a/lib/cmp_icu_new.c +++ b/lib/cmp_icu_new.c @@ -26,6 +26,52 @@ /* return code if the bitstream buffer is too small to store the whole bitstream */ #define CMP_ERROR_SAMLL_BUF -2 +/* pointer to a code word generation function */ +typedef uint32_t (*generate_cw_pt)(uint32_t value, uint32_t encoder_par1, + uint32_t encoder_par2, uint32_t *cw); + +/* typedef uint32_t (*next_model_f_pt)(uint32_t model_mode_val, uint32_t diff_model_var); */ + +struct encoder_setupt { + /* unsigned int lossy_par; */ + /* next_model_f_pt *next_model_f; */ + generate_cw_pt generate_cw; /* pointer to the code word generation function */ + /* uint32_t updated_model; */ + uint32_t encoder_par1; + uint32_t encoder_par2; + uint32_t outlier_par; + uint32_t model_value; + uint32_t max_value_bits; /* how many bits are needed to represent the highest possible value */ + uint32_t max_bit_len; /* maximum length of the bitstream/icu_output_buf in bits */ + uint32_t *bitstream_adr; +}; + + +/** + * @brief map a signed value into a positive value range + * + * @param value_to_map signed value to map + * @param max_value_bits how many bits are needed to represent the + * highest possible value + * + * @returns the positive mapped value + */ + +static uint32_t map_to_pos(uint32_t value_to_map, unsigned int max_value_bits) +{ + uint32_t mask = (~0U >> (32 - max_value_bits)); /* mask the used bits */ + + value_to_map &= mask; + if (value_to_map >> (max_value_bits - 1)) { /* check the leading signed bit */ + value_to_map |= ~mask; /* convert to 32-bit signed integer */ + /* map negative values to uneven numbers */ + return (-value_to_map) * 2 - 1; /* possible integer overflow is intended */ + } else { + /* map positive values to even numbers */ + return value_to_map * 2; /* possible integer overflow is intended */ + } +} + /** * @brief put the value of up to 32 bits into a bitstream accessed as 32-bit @@ -43,8 +89,6 @@ * @returns length in bits of the generated bitstream on success; returns * negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF if * the bitstream buffer is too small to put the value in the bitstream - * @note a value with more bits set as the n_bits parameter is considered as an - * erroneous input. */ static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset, @@ -60,21 +104,11 @@ static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset, return -1; if (n_bits == 0) - return 0; + return stream_len; if (n_bits > 32) return -1; - /* (M) is the n_bits parameter large enough to cover all value bits; the - * calculations can be re-used in the unsegmented code, so we have no overhead - */ - shiftRight = 32 - n_bits; - mask = 0xFFFFFFFFU >> shiftRight; - if (value & ~mask) { - debug_print("Error: Not all set bits in the put value are added to the bitstream. Check value n_bits parameter combination.\n"); - return -1; - } - /* Do we need to write data to the bitstream? */ if (!bitstream_adr) return stream_len; @@ -85,6 +119,13 @@ static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset, return CMP_ERROR_SAMLL_BUF; } + /* (M) is the n_bits parameter large enough to cover all value bits; the + * calculations can be re-used in the unsegmented code, so we have no overhead + */ + shiftRight = 32 - n_bits; + mask = 0xFFFFFFFFU >> shiftRight; + value &= mask; + /* Separate the bit_offset into word offset (set local_adr pointer) and local bit offset (bitsLeft) */ local_adr = bitstream_adr + (bit_offset >> 5); bitsLeft = bit_offset & 0x1F; @@ -163,3 +204,235 @@ static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset, return stream_len; } + +/** + * @brief forms the codeword according to the Rice code + * + * @param value value to be encoded + * @param m Golomb parameter, only m's which are power of 2 are allowed + * @param log2_m Rice parameter, is log_2(m) calculate outside function + * for better performance + * @param cw address were the encode code word is stored + * + * @returns the length of the formed code word in bits + * @note no check if the generated code word is not longer than 32 bits. + */ + +static uint32_t Rice_encoder(uint32_t value, uint32_t m, uint32_t log2_m, + uint32_t *cw) +{ + uint32_t g; /* quotient of value/m */ + uint32_t q; /* quotient code without ending zero */ + uint32_t r; /* remainder of value/m */ + uint32_t rl; /* remainder length */ + + g = value >> log2_m; /* quotient, number of leading bits */ + q = (1U << g) - 1; /* prepare the quotient code without ending zero */ + + r = value & (m-1); /* calculate the remainder */ + rl = log2_m + 1; /* length of the remainder (+1 for the 0 in the quotient code) */ + *cw = (q << rl) | r; /* put the quotient and remainder code together */ + /* + * NOTE: If log2_m = 31 -> rl = 32, (q << rl) leads to an undefined + * behavior. However, in this case, a valid code with a maximum of 32 + * bits can only be formed if q = 0. Any shift with 0 << x always + * results in 0, which forms the correct codeword in this case. For + * performance reasons, this undefined behaviour is not caught. + */ + + return rl + g; /* calculate the length of the code word */ +} + + +/** + * @brief forms a codeword according to the Golomb code + * + * @param value value to be encoded + * @param m Golomb parameter (have to be bigger than 0) + * @param log2_m is log_2(m) calculate outside function for better + * performance + * @param cw address were the formed code word is stored + * + * @returns the length of the formed code word in bits + */ + +static uint32_t Golomb_encoder(uint32_t value, uint32_t m, uint32_t log2_m, + uint32_t *cw) +{ + uint32_t len0, b, g, q, lg; + uint32_t len; + uint32_t cutoff; + + len0 = log2_m + 1; /* codeword length in group 0 */ + cutoff = (1U << (log2_m + 1)) - m; /* members in group 0 */ + + if (value < cutoff) { /* group 0 */ + *cw = value; + len = len0; + } else { /* other groups */ + g = (value-cutoff) / m; /* this group is which one */ + b = cutoff << 1; /* form the base codeword */ + lg = len0 + g; /* it has lg remainder bits */ + q = (1U << g) - 1; /* prepare the left side in unary */ + *cw = (q << (len0+1)) + b + (value-cutoff) - g*m; /* composed codeword */ + len = lg + 1; /* length of the codeword */ + } + return len; +} + + +/** + * @brief generate a code word without a outlier mechanism and put in the + * bitstream + * + * @param value value to encode in the bitstream + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup + * + * @returns the bit length of the bitstream with the added encoded value on + * success; negative on error + */ + +static int encode_normal(uint32_t value, int stream_len, + struct encoder_setupt *setup) +{ + uint32_t code_word, cw_len; + + cw_len = setup->generate_cw(value, setup->encoder_par1, + setup->encoder_par2, &code_word); + + return put_n_bits32(code_word, cw_len, stream_len, setup->bitstream_adr, + setup->max_bit_len); +} + + +/** + * @brief subtract the model from the data and encode the result and put it into + * bitstream, for outlier use the zero escape symbol mechanism + * + * @param data data to encode + * @param model model of the data (0 if not used) + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup + * + * @returns the bit length of the bitstream with the added encoded value on + * success; negative on error + * + * @note no check if data or model are in the allowed range + */ + +static int encode_value_zero(uint32_t data, uint32_t model, int stream_len, + struct encoder_setupt *setup) +{ + data -= model; + + data = map_to_pos(data, setup->max_value_bits); + + /* For performance reasons we check if there is an outlier before adding + * one to the data, than the other way around: + * data++; + * if (data < setup->outlier_par && data != 0) + * return ... + */ + if (data < (setup->outlier_par - 1)) { + data++; /* add 1 to every value so we can use 0 as escape symbol */ + return encode_normal(data, stream_len, setup); + } + + data++; /* add 1 to every value so we can use 0 as escape symbol */ + + /* use zero as escape symbol */ + stream_len = encode_normal(0, stream_len, setup); + if (stream_len <= 0) + return stream_len; + + /* put the data unencoded in the bitstream */ + stream_len = put_n_bits32(data, setup->max_value_bits, stream_len, + setup->bitstream_adr, setup->max_bit_len); + + return stream_len; + +} + + +static int cal_multi_offset(unsigned int unencoded_data) +{ + if (unencoded_data <= 0x3) + return 0; + if (unencoded_data <= 0xF) + return 1; + if (unencoded_data <= 0x3F) + return 2; + if (unencoded_data <= 0xFF) + return 3; + if (unencoded_data <= 0x3FF) + return 4; + if (unencoded_data <= 0xFFF) + return 5; + if (unencoded_data <= 0x3FFF) + return 6; + if (unencoded_data <= 0xFFFF) + return 7; + if (unencoded_data <= 0x3FFFF) + return 8; + if (unencoded_data <= 0xFFFFF) + return 9; + if (unencoded_data <= 0x3FFFFF) + return 10; + if (unencoded_data <= 0xFFFFFF) + return 11; + if (unencoded_data <= 0x3FFFFFF) + return 12; + if (unencoded_data <= 0xFFFFFFF) + return 13; + if (unencoded_data <= 0x3FFFFFFF) + return 14; + else + return 15; +} + + +#if 0 +static int encode_value_multi(uint32_t data, uint32_t model, int stream_len, + struct encoder_setupt *setup) +{ + uint32_t unencoded_data; + unsigned int unencoded_data_len; + uint32_t escape_sym; + uint32_t escape_sym_offset; + + data -= model; /* possible underflow is intended */ + + data = map_to_pos(data, setup->max_value_bits); + + if (data < setup->outlier_par) + return encode_normal(data, stream_len, setup); + /* + * In this mode we put the difference between the data and the spillover + * threshold value (unencoded_data) after a encoded escape symbol, which + * indicate that the next codeword is unencoded. + * We use different escape symbol depended on the size the needed bit of + * unencoded data: + * 0, 1, 2 bits needed for unencoded data -> escape symbol is spill + 0 + * 3, 4 bits needed for unencoded data -> escape symbol is spill + 1 + * .. + */ + + unencoded_data = data - setup->outlier_par; + + escape_sym_offset = cal_multi_offset(unencoded_data); + escape_sym = setup->outlier_par + escape_sym_offset; + unencoded_data_len = (escape_sym_offset + 1) * 2; + + /* put the escape symbol in the bitstream */ + stream_len = encode_normal(escape_sym, stream_len, setup); + if (stream_len <= 0) + return stream_len; + + /* put the unencoded data in the bitstream */ + stream_len = put_n_bits32(unencoded_data, unencoded_data_len, stream_len, + setup->bitstream_adr, setup->max_bit_len); + + return stream_len; +} +#endif diff --git a/test/cmp_icu/test_cmp_icu_new.c b/test/cmp_icu/test_cmp_icu_new.c index 6e5761528a50305999b110a74120a05f70508e01..986b7b648a0f73c5ab800860afa720fc72f37502 100644 --- a/test/cmp_icu/test_cmp_icu_new.c +++ b/test/cmp_icu/test_cmp_icu_new.c @@ -2,10 +2,99 @@ #include "unity.h" +#include "cmp_support.h" /* this is a hack to test static functions */ #include "../lib/cmp_icu_new.c" +/** +* @test map_to_pos +*/ + +void test_map_to_pos(void) +{ + uint32_t value_to_map; + uint32_t max_value_bits; + uint32_t mapped_value; + + /* test mapping 32 bits values */ + max_value_bits = 32; + + value_to_map = 0; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(0, mapped_value); + + value_to_map = -1U; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = 1; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(2, mapped_value); + + value_to_map = 42; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(84, mapped_value); + + value_to_map = INT32_MAX; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_HEX(UINT32_MAX-1, mapped_value); + + value_to_map = INT32_MIN; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_HEX(UINT32_MAX, mapped_value); + + /* test mapping 16 bits values */ + max_value_bits = 16; + + value_to_map = -1U; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + /* test mapping 6 bits values */ + max_value_bits = 6; + + value_to_map = 0; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(0, mapped_value); + + value_to_map = -1U; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = UINT32_MAX; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = -1U & 0x3FU; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = 63; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = 1; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(2, mapped_value); + + value_to_map = 31; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(62, mapped_value); + + value_to_map = -33U; /* aka 31 */ + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(62, mapped_value); + + value_to_map = -32U; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(63, mapped_value); + + value_to_map = 32; + mapped_value = map_to_pos(value_to_map, max_value_bits); + TEST_ASSERT_EQUAL_INT(63, mapped_value); +} + /** * @test put_n_bits32 @@ -42,7 +131,11 @@ void test_put_n_bits32(void) init_PB32_arrays(testarray0, testarray1); TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + TEST_ASSERT(testarray0[2] == 0); TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + TEST_ASSERT(testarray1[2] == 0xffffffff); /*** n=0 ***/ @@ -56,7 +149,9 @@ void test_put_n_bits32(void) TEST_ASSERT_EQUAL_INT(0, rval); TEST_ASSERT(testarray1[0] == 0xffffffff); - /* TODO: not a valid test */ + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(0, rval); + v = 0xffffffff; n = 0; o = 0; rval = put_n_bits32(v, n, o, testarray0, l); TEST_ASSERT_EQUAL_INT(0, rval); @@ -66,27 +161,35 @@ void test_put_n_bits32(void) TEST_ASSERT_EQUAL_INT(0, rval); TEST_ASSERT(testarray1[0] == 0xffffffff); + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(0, rval); + /* do not write, right border */ - v = 0; n = 0; o = 31; + v = 0; n = 0; o = l; rval = put_n_bits32(v, n, o, testarray0, l); - TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT_EQUAL_INT(l, rval); TEST_ASSERT(testarray0[0] == 0); rval = put_n_bits32(v, n, o, testarray1, l); - TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT_EQUAL_INT(l, rval); TEST_ASSERT(testarray1[0] == 0xffffffff); - /* TODO: not a valid test */ + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(l, rval); + /* test value = 0xffffffff; N = 0 */ - v = 0xffffffff; n = 0; o = 31; + v = 0xffffffff; n = 0; o = l; rval = put_n_bits32(v, n, o, testarray0, l); - TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT_EQUAL_INT(l, rval); TEST_ASSERT(testarray0[0] == 0); rval = put_n_bits32(v, n, o, testarray1, l); - TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT_EQUAL_INT(l, rval); TEST_ASSERT(testarray1[0] == 0xffffffff); + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(l, rval); + /*** n=1 ***/ /* left border, write 0 */ @@ -114,10 +217,12 @@ void test_put_n_bits32(void) rval = put_n_bits32(v, n, o, testarray0, l); TEST_ASSERT_EQUAL_INT(rval, 32); TEST_ASSERT(testarray0[0] == 0xf0f0abcd); + TEST_ASSERT(testarray0[1] == 0); rval = put_n_bits32(v, n, o, testarray1, l); TEST_ASSERT_EQUAL_INT(rval, 32); TEST_ASSERT(testarray1[0] == 0xf0f0abcd); + TEST_ASSERT(testarray1[1] == 0xffffffff); /* re-init input arrays after clobbering */ init_PB32_arrays(testarray0, testarray1); @@ -317,26 +422,49 @@ void test_put_n_bits32(void) rval = put_n_bits32(v, n, o, NULL, l); TEST_ASSERT_EQUAL_INT(rval, 97); /* rval can be longer than l */ - /* error cases */ - /* n too large */ - v = 0x0; n = 33; o = 1; + /* value larger than n allows */ + v = 0x7f; n = 6; o = 10; rval = put_n_bits32(v, n, o, testarray0, l); - TEST_ASSERT_EQUAL_INT(rval, -1); - TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray0[0] == 0x003f0000); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(16, rval); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + v = 0xffffffff; n = 6; o = 10; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray0[0] == 0x003f0000); TEST_ASSERT(testarray0[1] == 0); + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + rval = put_n_bits32(v, n, o, NULL, l); - TEST_ASSERT_EQUAL_INT(rval, -1); + TEST_ASSERT_EQUAL_INT(16, rval); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); - /* value larger than n allows */ - v = 0x7f; n = 6; o = 10; + /*** error cases ***/ + /* n too large */ + v = 0x0; n = 33; o = 1; rval = put_n_bits32(v, n, o, testarray0, l); - TEST_ASSERT_EQUAL_INT(-1, rval); + TEST_ASSERT_EQUAL_INT(rval, -1); TEST_ASSERT(testarray0[0] == 0); TEST_ASSERT(testarray0[1] == 0); rval = put_n_bits32(v, n, o, NULL, l); - TEST_ASSERT_EQUAL_INT(-1, rval); + TEST_ASSERT_EQUAL_INT(rval, -1); /* try to put too much in the bitstream */ v = 0x1; n = 1; o = 96; @@ -346,11 +474,11 @@ void test_put_n_bits32(void) TEST_ASSERT(testarray0[1] == 0); TEST_ASSERT(testarray0[2] == 0); - /* this should work */ + /* this should work (if bitstream=NULL no length check) */ rval = put_n_bits32(v, n, o, NULL, l); TEST_ASSERT_EQUAL_INT(97, rval); - /* offset lager than max_bit_len */ + /* offset lager than max_bit_len(l) */ v = 0x0; n = 32; o = INT32_MAX; rval = put_n_bits32(v, n, o, testarray1, l); TEST_ASSERT_EQUAL_INT(CMP_ERROR_SAMLL_BUF, rval); @@ -370,4 +498,305 @@ void test_put_n_bits32(void) rval = put_n_bits32(v, n, o, NULL, l); TEST_ASSERT_EQUAL_INT(-1, rval); + + v = 0x0; n = 0; o = -2; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(-1, rval); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(-1, rval); +} + + +/** + * @test Rice_encoder + */ + +void test_Rice_encoder(void) +{ + uint32_t value, g_par, log2_g_par, cw, cw_len; + + /* test minimum Golomb parameter */ + value = 0; log2_g_par = (uint32_t)ilog_2(MIN_ICU_GOLOMB_PAR); g_par = 1U << log2_g_par; cw = ~0U; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(1, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 31; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, cw); + + /* test some arbitrary values */ + value = 0; log2_g_par = 4; g_par = 1U << log2_g_par; cw = ~0U; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 42; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(7, cw_len); + TEST_ASSERT_EQUAL_HEX(0x6a, cw); + + value = 446; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEE, cw); + + value = 447; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEF, cw); + + /* test maximum Golomb parameter for Rice_encoder */ + value = 0; log2_g_par = (uint32_t)ilog_2(MAX_ICU_GOLOMB_PAR); g_par = 1U << log2_g_par; cw = ~0U; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 0x7FFFFFFE; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFE, cw); + + value = 0x7FFFFFFF; + cw_len = Rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, cw); +} + + +/** + * @test Golomb_encoder + */ + +void test_Golomb_encoder(void) +{ + uint32_t value, g_par, log2_g_par, cw, cw_len; + + /* test minimum Golomb parameter */ + value = 0; g_par = MIN_ICU_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(1, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 31; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, cw); + + + /* test some arbitrary values with g_par = 16 */ + value = 0; g_par = 16; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 42; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(7, cw_len); + TEST_ASSERT_EQUAL_HEX(0x6a, cw); + + value = 446; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEE, cw); + + value = 447; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEF, cw); + + + /* test some arbitrary values with g_par = 3 */ + value = 0; g_par = 3; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(2, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(3, cw_len); + TEST_ASSERT_EQUAL_HEX(0x2, cw); + + value = 42; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(16, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFC, cw); + + value = 44; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(17, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1FFFB, cw); + + value = 88; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFA, cw); + + value = 89; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFB, cw); + + + /* test maximum Golomb parameter for Golomb_encoder */ + value = 0; g_par = MAX_ICU_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; g_par = MAX_ICU_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 0x7FFFFFFE; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFE, cw); + + value = 0x7FFFFFFF; + cw_len = Golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, cw); +} + + +/** + * @test encode_value_zero + */ + +void test_encode_value_zero(void) +{ + uint32_t data, model; + int stream_len; + struct encoder_setupt setup = {0}; + uint32_t bitstream[3] = {0}; + + /* setup the setup */ + setup.encoder_par1 = 1; + setup.encoder_par2 = (uint32_t)ilog_2(setup.encoder_par1); + setup.outlier_par = 32; + setup.max_value_bits = 32; + setup.generate_cw = Rice_encoder; + setup.bitstream_adr = bitstream; + setup.max_bit_len = sizeof(bitstream) * CHAR_BIT; + + stream_len = 0; + + data = 0; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(2, stream_len); + TEST_ASSERT_EQUAL_HEX(0x80000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + data = 5; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(14, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFF80000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + data = 2; model = 7; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(25, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + /* zero escape mechanism */ + data = 100; model = 42; + /* (100-42)*2+1=117 -> cw 0 + 0x0000_0000_0000_0075 */ + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(58, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00001D40, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + /* test overflow */ + data = INT32_MIN; model = 0; + /* (INT32_MIN)*-2-1+1=0(overflow) -> cw 0 + 0x0000_0000_0000_0000 */ + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(91, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00001D40, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + /* small buffer error */ + data = 23; model = 26; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SAMLL_BUF, stream_len); + + /* reset bitstream to all bits set */ + bitstream[0] = ~0U; + bitstream[1] = ~0U; + bitstream[2] = ~0U; + stream_len = 0; + + /* we use now values with maximum 6 bits */ + setup.max_value_bits = 6; + + /* lowest value before zero encoding */ + data = 53; model = 38; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(32, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* lowest value with zero encoding */ + data = 0; model = 16; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(39, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x41FFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* maximum positive value to encode */ + data = 31; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(46, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x40FFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* maximum negative value to encode */ + data = -32U; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(53, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x40FC07FF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* small buffer error when creating the zero escape symbol*/ + bitstream[0] = 0; + bitstream[1] = 0; + bitstream[2] = 0; + stream_len = 32; + setup.max_bit_len = 32; + data = 31; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(-2, stream_len); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); }