diff --git a/include/etl/binary.h b/include/etl/binary.h index 7029c3fc..c54bc1fc 100644 --- a/include/etl/binary.h +++ b/include/etl/binary.h @@ -36,7 +36,6 @@ SOFTWARE. ///\ingroup utilities #include -#include #include "platform.h" #include "type_traits.h" @@ -45,10 +44,42 @@ SOFTWARE. #include "log.h" #include "power.h" #include "smallest.h" -#include "platform.h" +#include "exception.h" +#include "error_handler.h" + +#undef ETL_FILE +#define ETL_FILE "50" namespace etl { + //*************************************************************************** + /// Exception for binary functions. + ///\ingroup binary + //*************************************************************************** + class binary_exception : public etl::exception + { + public: + + binary_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception 'for out of range' errors. + ///\ingroup binary + //*************************************************************************** + class binary_out_of_range : public etl::binary_exception + { + public: + + binary_out_of_range(string_type file_name_, numeric_type line_number_) + : etl::binary_exception(ETL_ERROR_TEXT("binary:out of range", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + //*************************************************************************** /// Maximum value that can be contained in N bits. //*************************************************************************** @@ -310,7 +341,8 @@ namespace etl STATIC_ASSERT(etl::is_integral::value, "TValue not an integral type"); STATIC_ASSERT(etl::is_integral::value, "TReturn not an integral type"); STATIC_ASSERT(etl::is_signed::value, "TReturn not a signed type"); - assert(NBITS <= std::numeric_limits::digits); + + ETL_ASSERT((NBITS <= std::numeric_limits::digits), ETL_ERROR(binary_out_of_range)); TReturn mask = TReturn(1U) << (NBITS - 1); value = value & ((1U << NBITS) - 1); @@ -329,7 +361,8 @@ namespace etl STATIC_ASSERT(etl::is_integral::value, "TValue not an integral type"); STATIC_ASSERT(etl::is_integral::value, "TReturn not an integral type"); STATIC_ASSERT(etl::is_signed::value, "TReturn not a signed type"); - assert(NBITS <= std::numeric_limits::digits); + + ETL_ASSERT((NBITS <= std::numeric_limits::digits), ETL_ERROR(binary_out_of_range)); TReturn mask = TReturn(1U) << (NBITS - 1); value = (value >> SHIFT) & ((1U << NBITS) - 1); @@ -402,6 +435,140 @@ namespace etl template const typename bit::value_type bit::value; + //*************************************************************************** + /// Fills a value with a bit pattern. Compile time. + //*************************************************************************** + template + class binary_fill + { + private: + + STATIC_ASSERT(sizeof(TResult) >= sizeof(TValue), "Result must be at least as large as the fill value"); + STATIC_ASSERT(VALUE <= etl::integral_limits::type>::max, "Value is too large for specified type"); + + typedef typename etl::make_unsigned::type unsigned_r_t; + typedef typename etl::make_unsigned::type unsigned_v_t; + + public: + + static const TResult value = TResult(unsigned_v_t(VALUE) * (unsigned_r_t(~unsigned_r_t(0U)) / unsigned_v_t(~unsigned_v_t(0U)))); + }; + + template + const TResult binary_fill::value; + + //*************************************************************************** + /// Fills a value with a bit pattern. Run time. + //*************************************************************************** + template + class binary_fill + { + private: + + typedef typename etl::make_unsigned::type unsigned_r_t; + + public: + + template + static TResult value(TValue value) + { + STATIC_ASSERT(sizeof(TResult) >= sizeof(TValue), "Result must be at least as large as the fill value"); + + typedef typename etl::make_unsigned::type unsigned_v_t; + + return TResult(unsigned_v_t(value) * (unsigned_r_t(~unsigned_r_t(0U)) / unsigned_v_t(~unsigned_v_t(0U)))); + } + }; + +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// Detects the presence of zero bytes. Compile time. + //*************************************************************************** + template + class has_zero_byte + { + private: + + typedef typename etl::make_unsigned::type unsigned_t; + + static const unsigned_t mask = etl::binary_fill::value; + + public: + + static const bool test = unsigned_t(~((((unsigned_t(VALUE) & mask) + mask) | unsigned_t(VALUE)) | mask)) != 0U; + }; + + template + const typename etl::make_unsigned::type has_zero_byte::mask; + + template + const bool has_zero_byte::test; + + //*************************************************************************** + /// Detects the presence of zero bytes. Run time. + //*************************************************************************** + template <> + class has_zero_byte + { + public: + + template + static bool test(TValue value) + { + typedef typename etl::make_unsigned::type unsigned_t; + static const unsigned_t mask = etl::binary_fill::value; + + const unsigned_t temp = unsigned_t(~((((unsigned_t(value) & mask) + mask) | unsigned_t(value)) | mask)); + + return (temp != 0U); + } + }; + + //*************************************************************************** + /// Detects the presence of a byte of value N. Compile time. + //*************************************************************************** + template + class has_byte_n + { + public: + + static const bool test = etl::has_zero_byte::value)>::test; + }; + + template + const bool has_byte_n::test; + + //*************************************************************************** + /// Detects the presence of a byte of value N. Partial run time. + //*************************************************************************** + template + class has_byte_n + { + public: + + template + static bool test(TValue value) + { + return etl::has_zero_byte<>::test(TValue(value ^ etl::binary_fill::value)); + } + }; + + //*************************************************************************** + /// Detects the presence of a byte of value N. Run time. + //*************************************************************************** + template <> + class has_byte_n<0, void*, (void*)0> + { + public: + + template + static bool test(TValue value, uint8_t n) + { + return etl::has_zero_byte<>::test(TValue(value ^ etl::binary_fill::template value(n))); + } + }; +#endif + //*************************************************************************** /// 8 bit binary constants. //*************************************************************************** @@ -702,4 +869,6 @@ namespace etl }; } +#undef ETL_FILE + #endif diff --git a/include/etl/file_error_numbers.txt b/include/etl/file_error_numbers.txt index 40d89b45..4abc3060 100644 --- a/include/etl/file_error_numbers.txt +++ b/include/etl/file_error_numbers.txt @@ -1,4 +1,4 @@ - 1 + 1 deque 2 flat_map 3 flat_multimap 4 flat_multiset @@ -46,4 +46,5 @@ 46 queue_spsc_isr 47 queue_spsc_atomic 48 queue_mpmc_mutex -49 type_select \ No newline at end of file +49 type_select +50 binary \ No newline at end of file diff --git a/include/etl/version.h b/include/etl/version.h index 85be9694..c00eabc8 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -37,9 +37,9 @@ SOFTWARE. /// Definitions of the ETL version ///\ingroup utilities -#define ETL_VERSION "11.7.0" +#define ETL_VERSION "11.8.0" #define ETL_VERSION_MAJOR 11 -#define ETL_VERSION_MINOR 7 +#define ETL_VERSION_MINOR 8 #define ETL_VERSION_PATCH 0 #endif diff --git a/support/Release notes.txt b/support/Release notes.txt index aedbe2fa..26605032 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,10 @@ +=============================================================================== +11.8.0 +Added more binary utilities. +binary_fill +has_zero_byte +has_byte_n + =============================================================================== 11.7.0 Modified header guards. diff --git a/test/test_binary.cpp b/test/test_binary.cpp index 5de74d2a..fc5ecbc4 100644 --- a/test/test_binary.cpp +++ b/test/test_binary.cpp @@ -1056,11 +1056,11 @@ namespace { uint8_t value8 = 0x2A; uint8_t value8mask = 0x3F; - + const uint32_t value_initial = 0x55555555; uint32_t value; - + // Shift 0 value = value_initial; value &= ~value8mask; @@ -1276,6 +1276,210 @@ namespace CHECK_EQUAL(N << 30, etl::b30); CHECK_EQUAL(N << 31, uint32_t(etl::b31)); } + + //************************************************************************* + TEST(test_binary_fill_compile_time) + { + CHECK_EQUAL(0x12U, (etl::binary_fill::value)); + CHECK_EQUAL(0x1212U, (etl::binary_fill::value)); + CHECK_EQUAL(0x12121212U, (etl::binary_fill::value)); + CHECK_EQUAL(0x1212121212121212U, (etl::binary_fill::value)); + + CHECK_EQUAL(0x12, (etl::binary_fill::value)); + CHECK_EQUAL(0x1212, (etl::binary_fill::value)); + CHECK_EQUAL(0x12121212, (etl::binary_fill::value)); + CHECK_EQUAL(0x1212121212121212, (etl::binary_fill::value)); + + CHECK_EQUAL(0x1234U, (etl::binary_fill::value)); + CHECK_EQUAL(0x12341234U, (etl::binary_fill::value)); + CHECK_EQUAL(0x1234123412341234U, (etl::binary_fill::value)); + + CHECK_EQUAL(0x1234, (etl::binary_fill::value)); + CHECK_EQUAL(0x12341234, (etl::binary_fill::value)); + CHECK_EQUAL(0x1234123412341234, (etl::binary_fill::value)); + + CHECK_EQUAL(0x12345678U, (etl::binary_fill::value)); + CHECK_EQUAL(0x1234567812345678U, (etl::binary_fill::value)); + + CHECK_EQUAL(0x12345678, (etl::binary_fill::value)); + CHECK_EQUAL(0x1234567812345678, (etl::binary_fill::value)); + + CHECK_EQUAL(0x123456789ABCDEF0U, (etl::binary_fill::value)); + + CHECK_EQUAL(0x123456789ABCDEF0, (etl::binary_fill::value)); + } + + //************************************************************************* + TEST(test_binary_fill_run_time) + { + CHECK_EQUAL(0x12U, (etl::binary_fill::value(0x12))); + CHECK_EQUAL(0x1212U, (etl::binary_fill::value(0x12))); + CHECK_EQUAL(0x12121212U, (etl::binary_fill::value(0x12))); + CHECK_EQUAL(0x1212121212121212U, (etl::binary_fill::value(0x12))); + + CHECK_EQUAL(0x12, (etl::binary_fill::value(0x12))); + CHECK_EQUAL(0x1212, (etl::binary_fill::value(0x12))); + CHECK_EQUAL(0x12121212, (etl::binary_fill::value(0x12))); + CHECK_EQUAL(0x1212121212121212, (etl::binary_fill::value(0x12))); + + CHECK_EQUAL(0x1234U, (etl::binary_fill::value(0x1234))); + CHECK_EQUAL(0x12341234U, (etl::binary_fill::value(0x1234))); + CHECK_EQUAL(0x1234123412341234U, (etl::binary_fill::value(0x1234))); + + CHECK_EQUAL(0x1234, (etl::binary_fill::value(0x1234))); + CHECK_EQUAL(0x12341234, (etl::binary_fill::value(0x1234))); + CHECK_EQUAL(0x1234123412341234, (etl::binary_fill::value(0x1234))); + + CHECK_EQUAL(0x12345678U, (etl::binary_fill::value(0x12345678))); + CHECK_EQUAL(0x1234567812345678U, (etl::binary_fill::value(0x12345678))); + + CHECK_EQUAL(int32_t(0x12345678), int32_t(etl::binary_fill::value(0x12345678))); + CHECK_EQUAL(int64_t(0x1234567812345678), int64_t(etl::binary_fill::value(0x12345678))); + + CHECK_EQUAL(0x123456789ABCDEF0U, (etl::binary_fill::value(0x123456789ABCDEF0))); + + CHECK_EQUAL(int64_t(0x123456789ABCDEF0), int64_t(etl::binary_fill::value(0x123456789ABCDEF0))); + } + + //************************************************************************* + TEST(test_has_zero_compile_time) + { + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + + CHECK(!(etl::has_zero_byte::test)); + CHECK((etl::has_zero_byte::test)); + } + + //************************************************************************* + TEST(test_has_zero_run_time) + { + CHECK(!(etl::has_zero_byte<>::test(uint8_t(0x01)))); + CHECK((etl::has_zero_byte<>::test(uint8_t(0x00)))); + + CHECK(!(etl::has_zero_byte<>::test(int8_t(0x01)))); + CHECK((etl::has_zero_byte<>::test(int8_t(0x00)))); + + CHECK(!(etl::has_zero_byte<>::test(uint16_t(0x0123)))); + CHECK((etl::has_zero_byte<>::test(uint16_t(0x0100)))); + + CHECK(!(etl::has_zero_byte<>::test(int16_t(0x0123)))); + CHECK((etl::has_zero_byte<>::test(int16_t(0x0100)))); + + CHECK(!(etl::has_zero_byte<>::test(uint32_t(0x01234567)))); + CHECK((etl::has_zero_byte<>::test(uint32_t(0x01230067)))); + + CHECK(!(etl::has_zero_byte<>::test(int32_t(0x01234567)))); + CHECK((etl::has_zero_byte<>::test(int32_t(0x01230067)))); + + CHECK(!(etl::has_zero_byte<>::test(uint64_t(0x0123456789ABCDEF)))); + CHECK((etl::has_zero_byte<>::test(uint64_t(0x012345678900CDEF)))); + + CHECK(!(etl::has_zero_byte<>::test(int64_t(0x0123456789ABCDEF)))); + CHECK((etl::has_zero_byte<>::test(int64_t(0x012345678900CDEF)))); + } + + //************************************************************************* + TEST(test_has_n_compile_time) + { + CHECK(!(etl::has_byte_n<0x12, uint8_t, 0x01>::test)); + CHECK((etl::has_byte_n<0x01, uint8_t, 0x01>::test)); + + CHECK(!(etl::has_byte_n<0x12, int8_t, 0x01>::test)); + CHECK((etl::has_byte_n<0x01, int8_t, 0x01>::test)); + + CHECK(!(etl::has_byte_n<0x12, uint16_t, 0x0123>::test)); + CHECK((etl::has_byte_n<0x23, uint16_t, 0x0123>::test)); + + CHECK(!(etl::has_byte_n<0x12, int16_t, 0x0123>::test)); + CHECK((etl::has_byte_n<0x23, int16_t, 0x0123>::test)); + + CHECK(!(etl::has_byte_n<0x12, uint32_t, 0x01234567>::test)); + CHECK((etl::has_byte_n<0x45, uint32_t, 0x01234567>::test)); + + CHECK(!(etl::has_byte_n<0x12, int32_t, 0x01234567>::test)); + CHECK((etl::has_byte_n<0x45, int32_t, 0x01234567>::test)); + + CHECK(!(etl::has_byte_n<0x12, uint64_t, 0x0123456789ABCDEF>::test)); + CHECK((etl::has_byte_n<0xAB, uint64_t, 0x0123456789ABCDEF>::test)); + + CHECK(!(etl::has_byte_n<0x12, int64_t, 0x0123456789ABCDEF>::test)); + CHECK((etl::has_byte_n<0xAB, int64_t, 0x0123456789ABCDEF>::test)); + } + + //************************************************************************* + TEST(test_has_n_partial_run_time) + { + CHECK(!(etl::has_byte_n<0x12>::test(uint8_t(0x01)))); + CHECK((etl::has_byte_n<0x01>::test(uint8_t(0x01)))); + + CHECK(!(etl::has_byte_n<0x12>::test(int8_t(0x01)))); + CHECK((etl::has_byte_n<0x01>::test(int8_t(0x01)))); + + CHECK(!(etl::has_byte_n<0x12>::test(uint16_t(0x0123)))); + CHECK((etl::has_byte_n<0x23>::test(uint16_t(0x0123)))); + + CHECK(!(etl::has_byte_n<0x12>::test(int16_t(0x0123)))); + CHECK((etl::has_byte_n<0x23>::test(int16_t(0x0123)))); + + CHECK(!(etl::has_byte_n<0x12>::test(uint32_t(0x01234567)))); + CHECK((etl::has_byte_n<0x45>::test(uint32_t(0x01234567)))); + + CHECK(!(etl::has_byte_n<0x12>::test(int32_t(0x01234567)))); + CHECK((etl::has_byte_n<0x45>::test(int32_t(0x01234567)))); + + CHECK(!(etl::has_byte_n<0x12>::test(uint64_t(0x0123456789ABCDEF)))); + CHECK((etl::has_byte_n<0xAB>::test(uint64_t(0x0123456789ABCDEF)))); + + CHECK(!(etl::has_byte_n<0x12>::test(int64_t(0x0123456789ABCDEF)))); + CHECK((etl::has_byte_n<0xAB>::test(int64_t(0x0123456789ABCDEF)))); + } + + //************************************************************************* + TEST(test_has_n_run_time) + { + CHECK(!(etl::has_byte_n<>::test(uint8_t(0x01), 0x12))); + CHECK((etl::has_byte_n<>::test(uint8_t(0x01), 0x01))); + + CHECK(!(etl::has_byte_n<>::test(uint8_t(0x01), 0x12))); + CHECK((etl::has_byte_n<>::test(uint8_t(0x01), 0x01))); + + CHECK(!(etl::has_byte_n<>::test(uint16_t(0x0123), 0x12))); + CHECK((etl::has_byte_n<>::test(uint16_t(0x0123), 0x23))); + + CHECK(!(etl::has_byte_n<>::test(int16_t(0x0123), 0x12))); + CHECK((etl::has_byte_n<>::test(int16_t(0x0123), 0x23))); + + CHECK(!(etl::has_byte_n<>::test(uint32_t(0x01234567), 0x12))); + CHECK((etl::has_byte_n<>::test(uint32_t(0x01234567), 0x45))); + + CHECK(!(etl::has_byte_n<>::test(int32_t(0x01234567), 0x12))); + CHECK((etl::has_byte_n<>::test(int32_t(0x01234567), 0x45))); + + CHECK(!(etl::has_byte_n<>::test(uint64_t(0x0123456789ABCDEF), 0x12))); + CHECK((etl::has_byte_n<>::test(uint64_t(0x0123456789ABCDEF), 0xAB))); + + CHECK(!(etl::has_byte_n<>::test(int64_t(0x0123456789ABCDEF), 0x12))); + CHECK((etl::has_byte_n<>::test(int64_t(0x0123456789ABCDEF), 0xAB))); + } }; }