diff --git a/include/etl/memory.h b/include/etl/memory.h index d0e0398c..a3aba030 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -2133,6 +2133,225 @@ namespace etl template using uninitialized_buffer_of_t = typename uninitialized_buffer_of::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 etl::enable_if::value_type>::value, TPointer>::type + mem_copy(const TPointer sb, const TPointer se, TPointer db) ETL_NOEXCEPT + { + return reinterpret_cast(memcpy(reinterpret_cast(db), + reinterpret_cast(sb), + sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb))); + } + + //*************************************************************************** + /// Template wrapper for memcpy. + /// Type must be trivially copyable. + /// \param source begin + /// \param source length + /// \param destination begin + //*************************************************************************** + template + typename etl::enable_if::value_type>::value, TPointer>::type + mem_copy(const TPointer sb, size_t n, TPointer db) ETL_NOEXCEPT + { + return reinterpret_cast(memcpy(reinterpret_cast(db), + reinterpret_cast(sb), + sizeof(typename etl::iterator_traits::value_type) * n)); + } + + //*************************************************************************** + /// Template wrapper for memmove. + /// Type must be trivially copyable. + /// \param source begin + /// \param source end + /// \param destination begin + //*************************************************************************** + template + typename etl::enable_if::value_type>::value, TPointer>::type + mem_move(const TPointer sb, const TPointer se, TPointer db) ETL_NOEXCEPT + { + return reinterpret_cast(memmove(reinterpret_cast(db), + reinterpret_cast(sb), + sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb))); + } + + //*************************************************************************** + /// Template wrapper for memmove. + /// Type must be trivially copyable. + /// \param source begin + /// \param source length + /// \param destination begin + //*************************************************************************** + template + typename etl::enable_if::value_type>::value, TPointer>::type + mem_move(const TPointer sb, size_t n, TPointer db) ETL_NOEXCEPT + { + return reinterpret_cast(memmove(reinterpret_cast(db), + reinterpret_cast(sb), + sizeof(typename etl::iterator_traits::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 + ETL_NODISCARD + typename etl::enable_if::value_type>::value, int>::type + mem_compare(const TPointer sb, const TPointer se, TPointer db) ETL_NOEXCEPT + { + return memcmp(reinterpret_cast(db), + reinterpret_cast(sb), + sizeof(typename etl::iterator_traits::value_type) * static_cast(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 + ETL_NODISCARD + typename etl::enable_if::value_type>::value, int>::type + mem_compare(const TPointer sb, size_t n, TPointer db) ETL_NOEXCEPT + { + return memcmp(reinterpret_cast(db), + reinterpret_cast(sb), + sizeof(typename etl::iterator_traits::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 etl::enable_if::value_type>::value, TPointer>::type + mem_set(TPointer db, const TPointer de, typename etl::iterator_traits::value_type value) ETL_NOEXCEPT + { + return reinterpret_cast(memset(reinterpret_cast(db), + value, + sizeof(typename etl::iterator_traits::value_type) * static_cast(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 etl::enable_if::value_type>::value, TPointer>::type + mem_set(const TPointer db, size_t n, typename etl::iterator_traits::value_type value) ETL_NOEXCEPT + { + return reinterpret_cast(memset(reinterpret_cast(db), + value, + sizeof(typename etl::iterator_traits::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 + ETL_NODISCARD + typename etl::enable_if::value && !etl::is_const::type>::value, char*>::type + mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT + { + void* result = memchr(reinterpret_cast(sb), + static_cast(value), + sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb)); + + return (result == 0U) ? reinterpret_cast(se) : reinterpret_cast(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 + ETL_NODISCARD + typename etl::enable_if::value && etl::is_const::type>::value, const char*>::type + mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT + { + const void* result = memchr(reinterpret_cast(sb), + static_cast(value), + sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb)); + + return (result == 0U) ? reinterpret_cast(se) : reinterpret_cast(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 + ETL_NODISCARD + typename etl::enable_if::value && !etl::is_const::type>::value, char*>::type + mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT + { + void* result = memchr(reinterpret_cast(sb), + static_cast(value), + sizeof(typename etl::iterator_traits::value_type) * n); + + return (result == 0U) ? reinterpret_cast(sb + n) : reinterpret_cast(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 + ETL_NODISCARD + typename etl::enable_if::value && etl::is_const::type>::value, const char*>::type + mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT + { + const void* result = memchr(reinterpret_cast(sb), + static_cast(value), + sizeof(typename etl::iterator_traits::value_type) * n); + + return (result == 0U) ? reinterpret_cast(sb + n) : reinterpret_cast(result); + } } #endif diff --git a/include/etl/profiles/determine_compiler_language_support.h b/include/etl/profiles/determine_compiler_language_support.h index fe7e7e9b..9d276026 100644 --- a/include/etl/profiles/determine_compiler_language_support.h +++ b/include/etl/profiles/determine_compiler_language_support.h @@ -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) diff --git a/library.json b/library.json index 1ef11d79..0fcfd068 100644 --- a/library.json +++ b/library.json @@ -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" diff --git a/library.properties b/library.properties index ebdf3ef1..f66b214d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=20.25.0 +version=20.26.0 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/meson.build b/meson.build index ce6705fe..44ad078b 100644 --- a/meson.build +++ b/meson.build @@ -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 = [] diff --git a/support/Release notes.txt b/support/Release notes.txt index 3186381c..d0f63c25 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -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 diff --git a/test/test_memory.cpp b/test/test_memory.cpp index e6fdbfd4..9ab7e522 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -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(data) + 18) == p1); + CHECK((reinterpret_cast(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(data) + 18) == p1); + CHECK((reinterpret_cast(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(data) + 18) == p1); + CHECK((reinterpret_cast(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(data) + 18) == p1); + CHECK((reinterpret_cast(data) + 32) == p2); + } }; }