diff --git a/lib/cmp_icu_new.c b/lib/cmp_icu_new.c index f4bec3665d54726e3910055fc0f20a0f02053aca..d69ab0f543b238e26dfb11f6736a6c6cdec356fc 100644 --- a/lib/cmp_icu_new.c +++ b/lib/cmp_icu_new.c @@ -307,8 +307,8 @@ static int encode_normal(uint32_t value, int stream_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 + * @brief subtract the model from the data, encode the result and put it into + * bitstream, for encodeing outlier use the zero escape symbol mechanism * * @param data data to encode * @param model model of the data (0 if not used) @@ -316,9 +316,11 @@ static int encode_normal(uint32_t value, int stream_len, * @param setup pointer to the encoder setup * * @returns the bit length of the bitstream with the added encoded value on - * success; negative on error + * success; negative on error, CMP_ERROR_SAMLL_BUF if the bitstream buffer + * is too small to put the value in the bitstream * * @note no check if data or model are in the allowed range + * @note no check if the setup->outlier_par is in the allowed range */ static int encode_value_zero(uint32_t data, uint32_t model, int stream_len, @@ -328,13 +330,13 @@ static int encode_value_zero(uint32_t data, uint32_t model, int stream_len, 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: + /* For performance reasons, we check to see if there is an outlier + * before adding one, rather than the other way around: * data++; * if (data < setup->outlier_par && data != 0) * return ... */ - if (data < (setup->outlier_par - 1)) { + if (data < (setup->outlier_par - 1)) { /* detect r */ data++; /* add 1 to every value so we can use 0 as escape symbol */ return encode_normal(data, stream_len, setup); } @@ -355,74 +357,57 @@ static int encode_value_zero(uint32_t data, uint32_t model, int 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; -} - +/** + * @brief subtract the model from the data, encode the result and put it into + * bitstream, for encoding outlier use the multi 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, CMP_ERROR_SAMLL_BUF if the bitstream buffer + * is too small to put the value in the bitstream + * + * @note no check if data or model are in the allowed range + * @note no check if the setup->outlier_par is in the allowed ragne + */ -#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; + uint32_t escape_sym, escape_sym_offset; data -= model; /* possible underflow is intended */ data = map_to_pos(data, setup->max_value_bits); - if (data < setup->outlier_par) + if (data < setup->outlier_par) /* detect non-outlier */ 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 - * .. + * 0, 1, 2 bits needed for unencoded data -> escape symbol is outlier_par + 0 + * 3, 4 bits needed for unencoded data -> escape symbol is outlier_par + 1 + * 5, 6 bits needed for unencoded data -> escape symbol is outlier_par + 2 + * and so on */ - 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; + if (!unencoded_data) /* catch __builtin_clz(0) because the result is undefined.*/ + escape_sym_offset = 0; + else + escape_sym_offset = (31U - (uint32_t)__builtin_clz(unencoded_data)) >> 1; + + escape_sym = setup->outlier_par + escape_sym_offset; + unencoded_data_len = (escape_sym_offset + 1U) << 1; /* put the escape symbol in the bitstream */ stream_len = encode_normal(escape_sym, stream_len, setup); @@ -435,4 +420,3 @@ static int encode_value_multi(uint32_t data, uint32_t model, int stream_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 986b7b648a0f73c5ab800860afa720fc72f37502..a0d9109e72c3dd25a971ce47e6179dce6cfb8ede 100644 --- a/test/cmp_icu/test_cmp_icu_new.c +++ b/test/cmp_icu/test_cmp_icu_new.c @@ -8,8 +8,8 @@ /** -* @test map_to_pos -*/ + * @test map_to_pos + */ void test_map_to_pos(void) { @@ -780,7 +780,7 @@ void test_encode_value_zero(void) TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); /* maximum negative value to encode */ - data = -32U; model = 0; + data = 0; model = 32; stream_len = encode_value_zero(data, model, stream_len, &setup); TEST_ASSERT_EQUAL_INT(53, stream_len); TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); @@ -795,8 +795,100 @@ void test_encode_value_zero(void) 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_INT(CMP_ERROR_SAMLL_BUF, stream_len); TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); } + + +/** + * @test encode_value_multi + */ + +void test_encode_value_multi(void) +{ + uint32_t data, model; + int stream_len; + struct encoder_setupt setup = {0}; + uint32_t bitstream[4] = {0}; + + /* setup the setup */ + setup.encoder_par1 = 1; + setup.encoder_par2 = (uint32_t)ilog_2(setup.encoder_par1); + setup.outlier_par = 16; + 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_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(1, stream_len); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + data = 0; model = 1; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(3, stream_len); + TEST_ASSERT_EQUAL_HEX(0x40000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + data = 1+23; model = 0+23; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(6, stream_len); + TEST_ASSERT_EQUAL_HEX(0x58000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* highest value without multi outlier encoding */ + data = 0+42; model = 8+42; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(22, stream_len); + TEST_ASSERT_EQUAL_HEX(0x5BFFF800, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* lowest value with multi outlier encoding */ + data = 8+42; model = 0+42; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(41, stream_len); + TEST_ASSERT_EQUAL_HEX(0x5BFFFBFF, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFC000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* highest value with multi outlier encoding */ + data = INT32_MIN; model = 0; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(105, stream_len); + TEST_ASSERT_EQUAL_HEX(0x5BFFFBFF, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFC7FFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFF7FFFFF, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0xF7800000, bitstream[3]); + + /* small buffer error */ + data = 0; model = 38; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SAMLL_BUF, stream_len); + + /* small buffer error when creating the multi escape symbol*/ + bitstream[0] = 0; + bitstream[1] = 0; + setup.max_bit_len = 32; + + stream_len = 32; + data = 31; model = 0; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SAMLL_BUF, stream_len); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); +}