Added template wrappers around memcpy, memmove, memcmp, memset& memchr.

Added C++23 macro
Updated version numbers
This commit is contained in:
John Wellbelove 2022-03-19 21:29:29 +00:00
parent dbed55c507
commit 6f99c2b3a9
7 changed files with 389 additions and 4 deletions

View File

@ -2133,6 +2133,225 @@ namespace etl
template <typename T, size_t N_Objects>
using uninitialized_buffer_of_t = typename uninitialized_buffer_of<T, N_Objects>::buffer;
#endif
//***************************************************************************
/// Template wrapper for memcpy.
/// Type must be trivially copyable.
/// \param source begin
/// \param source end
/// \param destination begin
/// \return A pointer to the destination.
//***************************************************************************
template <typename TPointer>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
mem_copy(const TPointer sb, const TPointer se, TPointer db) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memcpy(reinterpret_cast<void*>(db),
reinterpret_cast<void*>(sb),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(se - sb)));
}
//***************************************************************************
/// Template wrapper for memcpy.
/// Type must be trivially copyable.
/// \param source begin
/// \param source length
/// \param destination begin
//***************************************************************************
template <typename TPointer>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
mem_copy(const TPointer sb, size_t n, TPointer db) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memcpy(reinterpret_cast<void*>(db),
reinterpret_cast<void*>(sb),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n));
}
//***************************************************************************
/// Template wrapper for memmove.
/// Type must be trivially copyable.
/// \param source begin
/// \param source end
/// \param destination begin
//***************************************************************************
template <typename TPointer>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
mem_move(const TPointer sb, const TPointer se, TPointer db) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memmove(reinterpret_cast<void*>(db),
reinterpret_cast<void*>(sb),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(se - sb)));
}
//***************************************************************************
/// Template wrapper for memmove.
/// Type must be trivially copyable.
/// \param source begin
/// \param source length
/// \param destination begin
//***************************************************************************
template <typename TPointer>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
mem_move(const TPointer sb, size_t n, TPointer db) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memmove(reinterpret_cast<void*>(db),
reinterpret_cast<void*>(sb),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n));
}
//***************************************************************************
/// Template wrapper for memcmp.
/// Type must be a char, signed char or unsigned char.
/// \param source begin
/// \param source end
/// \param destination begin
/// \return < 0 The first byte that does not match in both memory blocks has a lower value in 'sb' than in 'db' when evaluated as unsigned char values.
/// 0 The contents of both memory blocks are equal
/// > 0 The first byte that does not match in both memory blocks has a greater value in 'sb' than in 'db' when evaluated as unsigned char values.
//***************************************************************************
template <typename TPointer>
ETL_NODISCARD
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, int>::type
mem_compare(const TPointer sb, const TPointer se, TPointer db) ETL_NOEXCEPT
{
return memcmp(reinterpret_cast<void*>(db),
reinterpret_cast<void*>(sb),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(se - sb));
}
//***************************************************************************
/// Template wrapper for memcmp.
/// Type must be a char, signed char or unsigned char.
/// \param sb Source begin
/// \param n Source length
/// \param db Destination begin
/// \return < 0 The first byte that does not match in both memory blocks has a lower value in 'sb' than in 'db' when evaluated as unsigned char values.
/// 0 The contents of both memory blocks are equal
/// > 0 The first byte that does not match in both memory blocks has a greater value in 'sb' than in 'db' when evaluated as unsigned char values.
//***************************************************************************
template <typename TPointer>
ETL_NODISCARD
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, int>::type
mem_compare(const TPointer sb, size_t n, TPointer db) ETL_NOEXCEPT
{
return memcmp(reinterpret_cast<void*>(db),
reinterpret_cast<void*>(sb),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n);
}
//***************************************************************************
/// Template wrapper for memset.
/// Type must be a char, signed char or unsigned char.
/// \param db Destination begin.
/// \param de Destination end.
/// \param value The value to set.
/// \return The destination
//***************************************************************************
template <typename TPointer>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
mem_set(TPointer db, const TPointer de, typename etl::iterator_traits<TPointer>::value_type value) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memset(reinterpret_cast<void*>(db),
value,
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(de - db)));
}
//***************************************************************************
/// Template wrapper for memset.
/// Type must be a char, signed char or unsigned char.
/// \param db Destination begin.
/// \param n Destination length.
/// \param value The value to set.
/// \return The destination
//***************************************************************************
template <typename TPointer>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
mem_set(const TPointer db, size_t n, typename etl::iterator_traits<TPointer>::value_type value) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memset(reinterpret_cast<void*>(db),
value,
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n));
}
//***************************************************************************
/// Template wrapper for memchr.
/// Type must be a char, signed char or unsigned char.
/// \param sb Source begin.
/// \param se Source end.
/// \param value The value to find.
/// \return The position of the char or 'se'.
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && !etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, char*>::type
mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT
{
void* result = memchr(reinterpret_cast<void*>(sb),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(se - sb));
return (result == 0U) ? reinterpret_cast<char*>(se) : reinterpret_cast<char*>(result);
}
//***************************************************************************
/// Template wrapper for memchr.
/// Type must be a char, signed char or unsigned char.
/// \param sb Source begin.
/// \param se Source end.
/// \param value The value to find.
/// \return The position of the char or 'se'.
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, const char*>::type
mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT
{
const void* result = memchr(reinterpret_cast<const void*>(sb),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(se - sb));
return (result == 0U) ? reinterpret_cast<const char*>(se) : reinterpret_cast<const char*>(result);
}
//***************************************************************************
/// Template wrapper for memchr.
/// Type must be a char, signed char or unsigned char.
/// \param sb Source begin.
/// \param n Source length.
/// \param value The value to find.
/// \return The position of the char or 'sb + n'
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && !etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, char*>::type
mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT
{
void* result = memchr(reinterpret_cast<void*>(sb),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n);
return (result == 0U) ? reinterpret_cast<char*>(sb + n) : reinterpret_cast<char*>(result);
}
//***************************************************************************
/// Template wrapper for memchr.
/// Type must be a char, signed char or unsigned char.
/// \param sb Source begin.
/// \param n Source length.
/// \param value The value to find.
/// \return The position of the char or 'sb + n'
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, const char*>::type
mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT
{
const void* result = memchr(reinterpret_cast<const void*>(sb),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n);
return (result == 0U) ? reinterpret_cast<const char*>(sb + n) : reinterpret_cast<const char*>(result);
}
}
#endif

View File

@ -36,7 +36,16 @@ SOFTWARE.
#include "determine_compiler.h"
// Determine C++23 support
#define ETL_CPP23_SUPPORTED 0
#if !defined(ETL_CPP23_SUPPORTED)
#define ETL_CPP23_SUPPORTED 0
#endif
#if ETL_CPP23_SUPPORTED
#define ETL_CPP11_SUPPORTED 1
#define ETL_CPP14_SUPPORTED 1
#define ETL_CPP17_SUPPORTED 1
#define ETL_CPP20_SUPPORTED 1
#endif
// Determine C++20 support
#if !defined(ETL_CPP20_SUPPORTED)
@ -134,6 +143,7 @@ SOFTWARE.
#define ETL_CPP14_NOT_SUPPORTED (!ETL_CPP14_SUPPORTED)
#define ETL_CPP17_NOT_SUPPORTED (!ETL_CPP17_SUPPORTED)
#define ETL_CPP20_NOT_SUPPORTED (!ETL_CPP20_SUPPORTED)
#define ETL_CPP23_NOT_SUPPORTED (!ETL_CPP23_SUPPORTED)
#if !defined(ETL_NO_NULLPTR_SUPPORT)
#define ETL_NO_NULLPTR_SUPPORT ETL_CPP11_NOT_SUPPORTED
@ -147,10 +157,12 @@ SOFTWARE.
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
#endif
// 'Using' macros
#define ETL_USING_CPP11 (ETL_CPP11_SUPPORTED == 1)
#define ETL_USING_CPP14 (ETL_CPP14_SUPPORTED == 1)
#define ETL_USING_CPP17 (ETL_CPP17_SUPPORTED == 1)
#define ETL_USING_CPP20 (ETL_CPP20_SUPPORTED == 1)
#define ETL_USING_CPP23 (ETL_CPP23_SUPPORTED == 1)
// NAN not defined or Rowley CrossWorks
#if !defined(NAN) || defined(__CROSSWORKS_ARM) || defined(ETL_COMPILER_ARM5) || defined(ARDUINO)

View File

@ -1,6 +1,6 @@
{
"name": "Embedded Template Library",
"version": "20.25.0",
"version": "20.26.0",
"authors": {
"name": "John Wellbelove",
"email": "john.wellbelove@etlcpp.com"

View File

@ -1,5 +1,5 @@
name=Embedded Template Library
version=20.25.0
version=20.26.0
author= John Wellbelove <john.wellbelove@etlcpp.com>
maintainer=John Wellbelove <john.wellbelove@etlcpp.com>
license=MIT

View File

@ -8,7 +8,7 @@ project('etl',
'cpp_std=c++17', 'build.cpp_std=c++17',
],
meson_version: '>=0.54.0',
version: '20.25.0'
version: '20.26.0'
)
compile_args = []

View File

@ -1,3 +1,13 @@
===============================================================================
20.26.0
Added constexpr support for etl::unaligned_type.
Added etl::traits namespace containing traits mirroring many ETL macros.
Removed some uses of GCC builtins due to compatibilty with constexpr.
etl::swap is now ETL_CONSTEXPR14.
Changed ETL_ENDIANNESS_IS_CONSTEXPR to ETL_HAS_CONSTEXPR_ENDIANNESS.
Changed ETL_CONSTEXPR17 to ETL_CONSTEXPR14 for reverse iterators
Added template wrappers around memcpy, memmove, memcmp, memset& memchr.
===============================================================================
20.25.0
Added message_timer_interrupt

View File

@ -1151,5 +1151,149 @@ namespace
CHECK_EQUAL(expected, alignment);
}
//*************************************************************************
TEST(test_mem_copy_pointer_pointer_pointer)
{
uint32_t src[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t dst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
etl::mem_copy(src, src + 8, dst);
CHECK(std::equal(src, src + 8, dst));
}
//*************************************************************************
TEST(test_mem_copy_pointer_length_pointer)
{
uint32_t src[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t dst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
etl::mem_copy(src, 8, dst);
CHECK(std::equal(src, src + 8, dst));
}
//*************************************************************************
TEST(test_mem_move_pointer_pointer_pointer)
{
uint32_t expected[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t data[12] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201, 0, 0, 0, 0 };
etl::mem_move(data, data + 8, data + 4);
CHECK(std::equal(expected, expected + 8, data + 4));
}
//*************************************************************************
TEST(test_mem_move_pointer_length_pointer)
{
uint32_t expected[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t data[12] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201, 0, 0, 0, 0 };
etl::mem_move(data, 8, data + 4);
CHECK(std::equal(expected, expected + 8, data + 4));
}
//*************************************************************************
TEST(test_mem_compare_pointer_pointer_pointer)
{
uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t same[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t grtr[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67235501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t less[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67134501, 0x45016723, 0x01324576, 0x76453201 };
CHECK(etl::mem_compare(data, data + 8, same) == 0);
CHECK(etl::mem_compare(data, data + 8, grtr) > 0);
CHECK(etl::mem_compare(data, data + 8, less) < 0);
}
//*************************************************************************
TEST(test_mem_compare_pointer_length_pointer)
{
uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t same[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t grtr[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67235501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t less[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67134501, 0x45016723, 0x01324576, 0x76453201 };
CHECK(etl::mem_compare(data, 8, same) == 0);
CHECK(etl::mem_compare(data, 8, grtr) > 0);
CHECK(etl::mem_compare(data, 8, less) < 0);
}
//*************************************************************************
TEST(test_mem_set_pointer_pointer)
{
uint32_t data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t expected[8] = { 0, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0, 0, 0 };
etl::mem_set(data + 1, data + 5, 0x5A);
CHECK(std::equal(expected, expected + 8, data));
}
//*************************************************************************
TEST(test_mem_set_pointer_length)
{
uint32_t data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t expected[8] = { 0, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0, 0, 0 };
etl::mem_set(data + 1, 4, 0x5A);
CHECK(std::equal(expected, expected + 8, data));
}
//*************************************************************************
TEST(test_mem_char_pointer_pointer)
{
uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
char *p1 = etl::mem_char(data, data + 8, 0x29);
char* p2 = etl::mem_char(data, data + 8, 0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<char*>(data) + 18) == p1);
CHECK((reinterpret_cast<char*>(data) + 32) == p2);
}
//*************************************************************************
TEST(test_mem_char_pointer_pointer_const)
{
const uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
const char* p1 = etl::mem_char(data, data + 8, 0x29);
const char* p2 = etl::mem_char(data, data + 8, 0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<const char*>(data) + 18) == p1);
CHECK((reinterpret_cast<const char*>(data) + 32) == p2);
}
//*************************************************************************
TEST(test_mem_char_pointer_length)
{
uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
char* p1 = etl::mem_char(data, 8, 0x29);
char* p2 = etl::mem_char(data, 8, 0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<char*>(data) + 18) == p1);
CHECK((reinterpret_cast<char*>(data) + 32) == p2);
}
//*************************************************************************
TEST(test_mem_char_pointer_length_const)
{
const uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
const char* p1 = etl::mem_char(data, 8, 0x29);
const char* p2 = etl::mem_char(data, 8, 0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<const char*>(data) + 18) == p1);
CHECK((reinterpret_cast<const char*>(data) + 32) == p2);
}
};
}