Merge branch 'feature/binary' into development

This commit is contained in:
John Wellbelove 2018-04-29 20:00:15 +01:00
commit 7d7229b5e4
5 changed files with 391 additions and 10 deletions

View File

@ -36,7 +36,6 @@ SOFTWARE.
///\ingroup utilities
#include <limits>
#include <assert.h>
#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<TValue>::value, "TValue not an integral type");
STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type");
assert(NBITS <= std::numeric_limits<TReturn>::digits);
ETL_ASSERT((NBITS <= std::numeric_limits<TReturn>::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<TValue>::value, "TValue not an integral type");
STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type");
assert(NBITS <= std::numeric_limits<TReturn>::digits);
ETL_ASSERT((NBITS <= std::numeric_limits<TReturn>::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 size_t POSITION>
const typename bit<POSITION>::value_type bit<POSITION>::value;
//***************************************************************************
/// Fills a value with a bit pattern. Compile time.
//***************************************************************************
template <typename TResult, typename TValue = void*, const TValue VALUE = (void*)0>
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<typename etl::make_unsigned<TValue>::type>::max, "Value is too large for specified type");
typedef typename etl::make_unsigned<TResult>::type unsigned_r_t;
typedef typename etl::make_unsigned<TValue>::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 <typename TResult, typename TValue, const TValue VALUE>
const TResult binary_fill<TResult, TValue, VALUE>::value;
//***************************************************************************
/// Fills a value with a bit pattern. Run time.
//***************************************************************************
template <typename TResult>
class binary_fill<TResult, void*, (void*)0>
{
private:
typedef typename etl::make_unsigned<TResult>::type unsigned_r_t;
public:
template <typename TValue>
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<TValue>::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 <typename TValue = void*, const TValue VALUE = (void*)0>
class has_zero_byte
{
private:
typedef typename etl::make_unsigned<TValue>::type unsigned_t;
static const unsigned_t mask = etl::binary_fill<TValue, uint8_t, 0x7FU>::value;
public:
static const bool test = unsigned_t(~((((unsigned_t(VALUE) & mask) + mask) | unsigned_t(VALUE)) | mask)) != 0U;
};
template <typename TValue, const TValue VALUE>
const typename etl::make_unsigned<TValue>::type has_zero_byte<TValue, VALUE>::mask;
template <typename TValue, const TValue VALUE>
const bool has_zero_byte<TValue, VALUE>::test;
//***************************************************************************
/// Detects the presence of zero bytes. Run time.
//***************************************************************************
template <>
class has_zero_byte<void*, (void*)0>
{
public:
template <typename TValue>
static bool test(TValue value)
{
typedef typename etl::make_unsigned<TValue>::type unsigned_t;
static const unsigned_t mask = etl::binary_fill<TValue, uint8_t, 0x7FU>::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 <const uint8_t N = 0, typename TValue = void*, const TValue VALUE = (void*)0>
class has_byte_n
{
public:
static const bool test = etl::has_zero_byte<TValue, TValue(VALUE ^ etl::binary_fill<TValue, uint8_t, N>::value)>::test;
};
template <const uint8_t N, typename TValue, const TValue VALUE>
const bool has_byte_n<N, TValue, VALUE>::test;
//***************************************************************************
/// Detects the presence of a byte of value N. Partial run time.
//***************************************************************************
template <const uint8_t N>
class has_byte_n<N, void*, (void*)0>
{
public:
template <typename TValue>
static bool test(TValue value)
{
return etl::has_zero_byte<>::test(TValue(value ^ etl::binary_fill<TValue, uint8_t, N>::value));
}
};
//***************************************************************************
/// Detects the presence of a byte of value N. Run time.
//***************************************************************************
template <>
class has_byte_n<0, void*, (void*)0>
{
public:
template <typename TValue>
static bool test(TValue value, uint8_t n)
{
return etl::has_zero_byte<>::test(TValue(value ^ etl::binary_fill<TValue>::template value<uint8_t>(n)));
}
};
#endif
//***************************************************************************
/// 8 bit binary constants.
//***************************************************************************
@ -702,4 +869,6 @@ namespace etl
};
}
#undef ETL_FILE
#endif

View File

@ -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
49 type_select
50 binary

View File

@ -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

View File

@ -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.

View File

@ -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<uint8_t, uint8_t, 0x12>::value));
CHECK_EQUAL(0x1212U, (etl::binary_fill<uint16_t, uint8_t, 0x12>::value));
CHECK_EQUAL(0x12121212U, (etl::binary_fill<uint32_t, uint8_t, 0x12>::value));
CHECK_EQUAL(0x1212121212121212U, (etl::binary_fill<uint64_t, uint8_t, 0x12>::value));
CHECK_EQUAL(0x12, (etl::binary_fill<int8_t, int8_t, 0x12>::value));
CHECK_EQUAL(0x1212, (etl::binary_fill<int16_t, int8_t, 0x12>::value));
CHECK_EQUAL(0x12121212, (etl::binary_fill<int32_t, int8_t, 0x12>::value));
CHECK_EQUAL(0x1212121212121212, (etl::binary_fill<int64_t, int8_t, 0x12>::value));
CHECK_EQUAL(0x1234U, (etl::binary_fill<uint16_t, uint16_t, 0x1234>::value));
CHECK_EQUAL(0x12341234U, (etl::binary_fill<uint32_t, uint16_t, 0x1234>::value));
CHECK_EQUAL(0x1234123412341234U, (etl::binary_fill<uint64_t, uint16_t, 0x1234>::value));
CHECK_EQUAL(0x1234, (etl::binary_fill<int16_t, int16_t, 0x1234>::value));
CHECK_EQUAL(0x12341234, (etl::binary_fill<int32_t, int16_t, 0x1234>::value));
CHECK_EQUAL(0x1234123412341234, (etl::binary_fill<int64_t, int16_t, 0x1234>::value));
CHECK_EQUAL(0x12345678U, (etl::binary_fill<uint32_t, uint32_t, 0x12345678>::value));
CHECK_EQUAL(0x1234567812345678U, (etl::binary_fill<uint64_t, uint32_t, 0x12345678>::value));
CHECK_EQUAL(0x12345678, (etl::binary_fill<int32_t, int32_t, 0x12345678>::value));
CHECK_EQUAL(0x1234567812345678, (etl::binary_fill<int64_t, int32_t, 0x12345678>::value));
CHECK_EQUAL(0x123456789ABCDEF0U, (etl::binary_fill<uint64_t, uint64_t, 0x123456789ABCDEF0>::value));
CHECK_EQUAL(0x123456789ABCDEF0, (etl::binary_fill<int64_t, int64_t, 0x123456789ABCDEF0>::value));
}
//*************************************************************************
TEST(test_binary_fill_run_time)
{
CHECK_EQUAL(0x12U, (etl::binary_fill<uint8_t>::value<uint8_t>(0x12)));
CHECK_EQUAL(0x1212U, (etl::binary_fill<uint16_t>::value<uint8_t>(0x12)));
CHECK_EQUAL(0x12121212U, (etl::binary_fill<uint32_t>::value<uint8_t>(0x12)));
CHECK_EQUAL(0x1212121212121212U, (etl::binary_fill<uint64_t>::value<uint8_t>(0x12)));
CHECK_EQUAL(0x12, (etl::binary_fill<int8_t>::value<int8_t>(0x12)));
CHECK_EQUAL(0x1212, (etl::binary_fill<int16_t>::value<int8_t>(0x12)));
CHECK_EQUAL(0x12121212, (etl::binary_fill<int32_t>::value<int8_t>(0x12)));
CHECK_EQUAL(0x1212121212121212, (etl::binary_fill<int64_t>::value<int8_t>(0x12)));
CHECK_EQUAL(0x1234U, (etl::binary_fill<uint16_t>::value<uint16_t>(0x1234)));
CHECK_EQUAL(0x12341234U, (etl::binary_fill<uint32_t>::value<uint16_t>(0x1234)));
CHECK_EQUAL(0x1234123412341234U, (etl::binary_fill<uint64_t>::value<uint16_t>(0x1234)));
CHECK_EQUAL(0x1234, (etl::binary_fill<int16_t>::value<int16_t>(0x1234)));
CHECK_EQUAL(0x12341234, (etl::binary_fill<int32_t>::value<int16_t>(0x1234)));
CHECK_EQUAL(0x1234123412341234, (etl::binary_fill<int64_t>::value<int16_t>(0x1234)));
CHECK_EQUAL(0x12345678U, (etl::binary_fill<uint32_t>::value<uint32_t>(0x12345678)));
CHECK_EQUAL(0x1234567812345678U, (etl::binary_fill<uint64_t>::value<uint32_t>(0x12345678)));
CHECK_EQUAL(int32_t(0x12345678), int32_t(etl::binary_fill<int32_t>::value<int32_t>(0x12345678)));
CHECK_EQUAL(int64_t(0x1234567812345678), int64_t(etl::binary_fill<int64_t>::value<int32_t>(0x12345678)));
CHECK_EQUAL(0x123456789ABCDEF0U, (etl::binary_fill<uint64_t>::value<uint64_t>(0x123456789ABCDEF0)));
CHECK_EQUAL(int64_t(0x123456789ABCDEF0), int64_t(etl::binary_fill<int64_t>::value<int64_t>(0x123456789ABCDEF0)));
}
//*************************************************************************
TEST(test_has_zero_compile_time)
{
CHECK(!(etl::has_zero_byte<uint8_t, 0x01>::test));
CHECK((etl::has_zero_byte<uint8_t, 0x00>::test));
CHECK(!(etl::has_zero_byte<int8_t, 0x01>::test));
CHECK((etl::has_zero_byte<int8_t, 0x00>::test));
CHECK(!(etl::has_zero_byte<uint16_t, 0x0123>::test));
CHECK((etl::has_zero_byte<uint16_t, 0x0100>::test));
CHECK(!(etl::has_zero_byte<int16_t, 0x0123>::test));
CHECK((etl::has_zero_byte<int16_t, 0x0100>::test));
CHECK(!(etl::has_zero_byte<uint32_t, 0x01234567>::test));
CHECK((etl::has_zero_byte<uint32_t, 0x01230067>::test));
CHECK(!(etl::has_zero_byte<int32_t, 0x01234567>::test));
CHECK((etl::has_zero_byte<int32_t, 0x01230067>::test));
CHECK(!(etl::has_zero_byte<uint64_t, 0x0123456789ABCDEF>::test));
CHECK((etl::has_zero_byte<uint64_t, 0x012345678900CDEF>::test));
CHECK(!(etl::has_zero_byte<int64_t, 0x0123456789ABCDEF>::test));
CHECK((etl::has_zero_byte<int64_t, 0x012345678900CDEF>::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)));
}
};
}