mirror of
https://github.com/ETLCPP/etl.git
synced 2026-07-30 16:26:17 +08:00
Add missing memory functions, according the standard (#1490)
Adding: - etl::align - etl::assume_aligned - etl::is_sufficiently_aligned - etl::launder - etl::pointer_traits - etl::start_lifetime_as Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
dca6653b37
commit
84fca4cd62
@ -74,6 +74,323 @@ namespace etl
|
|||||||
return etl::to_address(itr.operator->());
|
return etl::to_address(itr.operator->());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ETL_USING_STL && ETL_USING_CPP17 && defined(__cpp_lib_launder)
|
||||||
|
using std::launder;
|
||||||
|
#else
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Obtains a pointer to the object created in the storage pointed to by p.
|
||||||
|
/// Prevents the compiler from making invalid assumptions when the lifetime of
|
||||||
|
/// an object has ended and a new object has been created in the same storage.
|
||||||
|
/// T must not be a function type nor a (possibly cv-qualified) void type.
|
||||||
|
/// https://en.cppreference.com/w/cpp/utility/launder
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD ETL_CONSTEXPR17 T* launder(T* p) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
// etl::is_function is only defined for C++11 and later.
|
||||||
|
ETL_STATIC_ASSERT(!etl::is_function<T>::value, "etl::launder argument must not be a function type");
|
||||||
|
#endif
|
||||||
|
ETL_STATIC_ASSERT(!etl::is_void<T>::value, "etl::launder argument must not be a void type");
|
||||||
|
|
||||||
|
#if defined(__has_builtin) && !defined(ETL_COMPILER_MICROSOFT)
|
||||||
|
#if __has_builtin(__builtin_launder)
|
||||||
|
return __builtin_launder(p);
|
||||||
|
#else
|
||||||
|
return p;
|
||||||
|
#endif
|
||||||
|
#elif ETL_USING_GCC_COMPILER && (ETL_COMPILER_FULL_VERSION >= 70000)
|
||||||
|
// GCC 7, 8 and 9 provide __builtin_launder but not __has_builtin.
|
||||||
|
return __builtin_launder(p);
|
||||||
|
#else
|
||||||
|
return p;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_STL && ETL_USING_CPP23 && defined(__cpp_lib_start_lifetime_as)
|
||||||
|
using std::start_lifetime_as;
|
||||||
|
using std::start_lifetime_as_array;
|
||||||
|
#else
|
||||||
|
namespace private_memory
|
||||||
|
{
|
||||||
|
//*************************************************************************
|
||||||
|
/// Implicitly create the objects in [p, p + n) and return a usable pointer
|
||||||
|
/// to the first one. Used by start_lifetime_as / start_lifetime_as_array.
|
||||||
|
//*************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
inline T* start_lifetime_as_impl(void* p, size_t n) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
if (n == 0U)
|
||||||
|
{
|
||||||
|
// No objects are created, so there is nothing to launder.
|
||||||
|
// Return the original pointer to preserve pointer identity.
|
||||||
|
return static_cast<T*>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ETL_USING_BUILTIN_MEMMOVE
|
||||||
|
void* const q = __builtin_memmove(p, p, sizeof(T) * n);
|
||||||
|
#else
|
||||||
|
void* const q = ::memmove(p, p, sizeof(T) * n);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return etl::launder(static_cast<T*>(q));
|
||||||
|
}
|
||||||
|
} // namespace private_memory
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Implicitly creates an object of type T in the storage pointed to by p and
|
||||||
|
/// starts its lifetime. T must be a trivially copyable (implicit-lifetime)
|
||||||
|
/// type. The storage must be suitably sized and aligned for T.
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/start_lifetime_as
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
T* start_lifetime_as(void* p) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<T>(p, 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
const T* start_lifetime_as(const void* p) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<const T>(const_cast<void*>(p), 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
volatile T* start_lifetime_as(volatile void* p) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<volatile T>(const_cast<void*>(p), 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
const volatile T* start_lifetime_as(const volatile void* p) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<const volatile T>(const_cast<void*>(p), 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Implicitly creates an array of n objects of type T in the storage pointed
|
||||||
|
/// to by p and starts their lifetimes. T must be a trivially copyable
|
||||||
|
/// (implicit-lifetime) type. Returns a pointer to the first element, or a
|
||||||
|
/// pointer comparing equal to p when n is zero.
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/start_lifetime_as
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
T* start_lifetime_as_array(void* p, size_t n) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<T>(p, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
const T* start_lifetime_as_array(const void* p, size_t n) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<const T>(const_cast<void*>(p), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
volatile T* start_lifetime_as_array(volatile void* p, size_t n) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<volatile T>(const_cast<void*>(p), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
const volatile T* start_lifetime_as_array(const volatile void* p, size_t n) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
return etl::private_memory::start_lifetime_as_impl<const volatile T>(const_cast<void*>(p), n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_STL && ETL_USING_CPP11
|
||||||
|
using std::pointer_traits;
|
||||||
|
#else
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
namespace private_memory
|
||||||
|
{
|
||||||
|
//*************************************************************************
|
||||||
|
/// Decomposes a pointer-like class template of the form
|
||||||
|
/// Pointer<Element, Args...> to recover its first template parameter and
|
||||||
|
/// to rebind it to a different first parameter. Left undefined for types
|
||||||
|
/// that are not such a template instantiation.
|
||||||
|
//*************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
struct pointer_traits_template;
|
||||||
|
|
||||||
|
template <template <typename, typename...> class Pointer, typename Element, typename... Args>
|
||||||
|
struct pointer_traits_template<Pointer<Element, Args...> >
|
||||||
|
{
|
||||||
|
typedef Element type;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef Pointer<U, Args...> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// Deduces the element_type of a pointer-like type. Prefers a nested
|
||||||
|
/// T::element_type, otherwise falls back to the first template parameter.
|
||||||
|
//*************************************************************************
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct pointer_traits_element_type
|
||||||
|
{
|
||||||
|
typedef typename pointer_traits_template<T>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct pointer_traits_element_type<T, etl::void_t<typename T::element_type> >
|
||||||
|
{
|
||||||
|
typedef typename T::element_type type;
|
||||||
|
};
|
||||||
|
} // namespace private_memory
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Provides information about pointer-like types. General case where the
|
||||||
|
/// type itself models the pointer (fancy / smart pointers).
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/pointer_traits
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
struct pointer_traits
|
||||||
|
{
|
||||||
|
typedef T pointer;
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
typedef typename private_memory::pointer_traits_element_type<T>::type element_type;
|
||||||
|
#else
|
||||||
|
typedef typename T::element_type element_type;
|
||||||
|
#endif
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
template <typename U>
|
||||||
|
using rebind = typename private_memory::pointer_traits_template<T>::template rebind<U>::type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ETL_NODISCARD
|
||||||
|
static ETL_CONSTEXPR pointer pointer_to(element_type& r) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return T::pointer_to(r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Provides information about pointer-like types. Raw pointer specialisation.
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/pointer_traits
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <typename T>
|
||||||
|
struct pointer_traits<T*>
|
||||||
|
{
|
||||||
|
typedef T* pointer;
|
||||||
|
typedef T element_type;
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
template <typename U>
|
||||||
|
using rebind = U*;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ETL_NODISCARD
|
||||||
|
static ETL_CONSTEXPR pointer pointer_to(element_type& r) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return etl::addressof(r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_STL && ETL_USING_CPP11
|
||||||
|
using std::align;
|
||||||
|
#else
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Aligns a pointer within a buffer. Advances 'ptr' to the next address with
|
||||||
|
/// the given 'alignment' that can hold 'size' bytes within 'space' bytes,
|
||||||
|
/// shrinking 'space' by the consumed padding. Returns the aligned pointer, or
|
||||||
|
/// ETL_NULLPTR when the buffer is too small. 'alignment' must be a power of 2;
|
||||||
|
/// the behaviour is undefined if it is not.
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/align
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
inline void* align(size_t alignment, size_t size, void*& ptr, size_t& space) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
const uintptr_t p = reinterpret_cast<uintptr_t>(ptr);
|
||||||
|
const uintptr_t aligned = (p + (alignment - 1U)) & ~(static_cast<uintptr_t>(alignment) - 1U);
|
||||||
|
const size_t padding = static_cast<size_t>(aligned - p);
|
||||||
|
|
||||||
|
if ((padding > space) || (size > (space - padding)))
|
||||||
|
{
|
||||||
|
return ETL_NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
space -= padding;
|
||||||
|
ptr = reinterpret_cast<void*>(aligned);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_STL && ETL_USING_CPP20 && defined(__cpp_lib_assume_aligned)
|
||||||
|
using std::assume_aligned;
|
||||||
|
#else
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Informs the compiler that the pointer 'ptr' is aligned to at least N bytes
|
||||||
|
/// and returns it. N must be a power of 2. Behaviour is undefined if 'ptr' is
|
||||||
|
/// not actually aligned to N.
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/assume_aligned
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <size_t N, typename T>
|
||||||
|
ETL_NODISCARD ETL_CONSTEXPR T* assume_aligned(T* ptr) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
#if defined(__has_builtin) && !defined(ETL_COMPILER_MICROSOFT)
|
||||||
|
#if __has_builtin(__builtin_assume_aligned)
|
||||||
|
return static_cast<T*>(__builtin_assume_aligned(ptr, N));
|
||||||
|
#else
|
||||||
|
return ptr;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return ptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_STL && ETL_USING_CPP26 && defined(__cpp_lib_is_sufficiently_aligned)
|
||||||
|
using std::is_sufficiently_aligned;
|
||||||
|
#else
|
||||||
|
//*****************************************************************************
|
||||||
|
/// Checks whether 'ptr' is aligned to at least Alignment bytes.
|
||||||
|
/// Alignment must be a power of 2.
|
||||||
|
/// https://en.cppreference.com/w/cpp/memory/is_sufficiently_aligned
|
||||||
|
///\ingroup memory
|
||||||
|
//*****************************************************************************
|
||||||
|
template <size_t Alignment, typename T>
|
||||||
|
ETL_NODISCARD
|
||||||
|
bool is_sufficiently_aligned(T* ptr) ETL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return (reinterpret_cast<uintptr_t>(ptr) % Alignment) == 0U;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ETL_USING_STL
|
#if ETL_USING_STL
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
/// Fills uninitialised memory range with a value.
|
/// Fills uninitialised memory range with a value.
|
||||||
|
|||||||
@ -167,6 +167,15 @@ SOFTWARE.
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ETL_COMPILER_MICROSOFT) // The Microsoft compiler supports the __is_trivially_copyable
|
||||||
|
// intrinsic directly. __has_builtin is not used for Microsoft
|
||||||
|
// (see above) to avoid a VS2022 intellisense issue, so the
|
||||||
|
// intrinsic is enabled here for the no-STL configuration.
|
||||||
|
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
|
||||||
|
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// The default. Set to 0, if not already set.
|
// The default. Set to 0, if not already set.
|
||||||
#if !defined(ETL_USING_BUILTIN_IS_ASSIGNABLE)
|
#if !defined(ETL_USING_BUILTIN_IS_ASSIGNABLE)
|
||||||
#define ETL_USING_BUILTIN_IS_ASSIGNABLE 0
|
#define ETL_USING_BUILTIN_IS_ASSIGNABLE 0
|
||||||
|
|||||||
@ -158,6 +158,33 @@ namespace
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//***********************************
|
||||||
|
// A minimal fancy pointer with a nested element_type and a static
|
||||||
|
// pointer_to. Used to exercise etl::pointer_traits' primary template.
|
||||||
|
template <typename T>
|
||||||
|
struct fancy_pointer
|
||||||
|
{
|
||||||
|
typedef T element_type;
|
||||||
|
|
||||||
|
T* raw;
|
||||||
|
|
||||||
|
static fancy_pointer pointer_to(T& r)
|
||||||
|
{
|
||||||
|
fancy_pointer p;
|
||||||
|
p.raw = etl::addressof(r);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//***********************************
|
||||||
|
// A fancy pointer without a nested element_type, so pointer_traits must
|
||||||
|
// deduce the element type from the first template parameter.
|
||||||
|
template <typename T>
|
||||||
|
struct bare_pointer
|
||||||
|
{
|
||||||
|
T* raw;
|
||||||
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -1808,6 +1835,157 @@ namespace
|
|||||||
CHECK_EQUAL(plist_item, etl::to_address(itr));
|
CHECK_EQUAL(plist_item, etl::to_address(itr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_launder)
|
||||||
|
{
|
||||||
|
int i = 42;
|
||||||
|
int* p = etl::launder(&i);
|
||||||
|
CHECK_EQUAL(&i, p);
|
||||||
|
CHECK_EQUAL(42, *p);
|
||||||
|
|
||||||
|
// Launder a new object created in reused storage.
|
||||||
|
struct quad_t
|
||||||
|
{
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t c;
|
||||||
|
uint8_t d;
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(quad_t) unsigned char buffer[sizeof(quad_t)];
|
||||||
|
quad_t* q = ::new (buffer) quad_t{1, 2, 3, 4};
|
||||||
|
quad_t* lq = etl::launder(q);
|
||||||
|
CHECK(reinterpret_cast<unsigned char*>(lq) == buffer);
|
||||||
|
CHECK_EQUAL(1, lq->a);
|
||||||
|
CHECK_EQUAL(2, lq->b);
|
||||||
|
CHECK_EQUAL(3, lq->c);
|
||||||
|
CHECK_EQUAL(4, lq->d);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_start_lifetime_as)
|
||||||
|
{
|
||||||
|
struct quad_t
|
||||||
|
{
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t c;
|
||||||
|
uint8_t d;
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(quad_t) unsigned char buffer[sizeof(quad_t)] = {1, 2, 3, 4};
|
||||||
|
|
||||||
|
quad_t* p = etl::start_lifetime_as<quad_t>(buffer);
|
||||||
|
CHECK(reinterpret_cast<unsigned char*>(p) == buffer);
|
||||||
|
CHECK_EQUAL(1, p->a);
|
||||||
|
CHECK_EQUAL(2, p->b);
|
||||||
|
CHECK_EQUAL(3, p->c);
|
||||||
|
CHECK_EQUAL(4, p->d);
|
||||||
|
|
||||||
|
const void* cbuffer = buffer;
|
||||||
|
const quad_t* cp = etl::start_lifetime_as<quad_t>(cbuffer);
|
||||||
|
CHECK(reinterpret_cast<const unsigned char*>(cp) == buffer);
|
||||||
|
CHECK_EQUAL(1, cp->a);
|
||||||
|
CHECK_EQUAL(4, cp->d);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_start_lifetime_as_array)
|
||||||
|
{
|
||||||
|
alignas(uint16_t) unsigned char buffer[sizeof(uint16_t) * 3] = {0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
uint16_t* p = etl::start_lifetime_as_array<uint16_t>(buffer, 3);
|
||||||
|
CHECK(reinterpret_cast<unsigned char*>(p) == buffer);
|
||||||
|
p[0] = 1;
|
||||||
|
p[2] = 2;
|
||||||
|
CHECK_EQUAL(1, p[0]);
|
||||||
|
CHECK_EQUAL(2, p[2]);
|
||||||
|
|
||||||
|
// n == 0 returns a pointer comparing equal to p.
|
||||||
|
uint16_t* p0 = etl::start_lifetime_as_array<uint16_t>(buffer, 0);
|
||||||
|
CHECK(reinterpret_cast<unsigned char*>(p0) == buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_pointer_traits)
|
||||||
|
{
|
||||||
|
typedef etl::pointer_traits<int*> traits;
|
||||||
|
|
||||||
|
CHECK((std::is_same<int*, traits::pointer>::value));
|
||||||
|
CHECK((std::is_same<int, traits::element_type>::value));
|
||||||
|
CHECK((std::is_same<ptrdiff_t, traits::difference_type>::value));
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
CHECK((std::is_same<char*, traits::rebind<char> >::value));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int i = 42;
|
||||||
|
int* p = traits::pointer_to(i);
|
||||||
|
CHECK_EQUAL(&i, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_pointer_traits_fancy_pointer)
|
||||||
|
{
|
||||||
|
typedef etl::pointer_traits<fancy_pointer<int> > traits;
|
||||||
|
|
||||||
|
CHECK((std::is_same<fancy_pointer<int>, traits::pointer>::value));
|
||||||
|
CHECK((std::is_same<int, traits::element_type>::value));
|
||||||
|
CHECK((std::is_same<ptrdiff_t, traits::difference_type>::value));
|
||||||
|
CHECK((std::is_same<fancy_pointer<char>, traits::rebind<char> >::value));
|
||||||
|
|
||||||
|
int i = 42;
|
||||||
|
fancy_pointer<int> p = traits::pointer_to(i);
|
||||||
|
CHECK_EQUAL(&i, p.raw);
|
||||||
|
|
||||||
|
// element_type and rebind are deduced from the first template parameter
|
||||||
|
// when there is no nested element_type.
|
||||||
|
CHECK((std::is_same<int, etl::pointer_traits<bare_pointer<int> >::element_type>::value));
|
||||||
|
CHECK((std::is_same<bare_pointer<char>, etl::pointer_traits<bare_pointer<int> >::rebind<char> >::value));
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_align)
|
||||||
|
{
|
||||||
|
alignas(16) unsigned char buffer[64];
|
||||||
|
|
||||||
|
void* ptr = buffer + 1; // Deliberately misaligned.
|
||||||
|
size_t space = sizeof(buffer) - 1;
|
||||||
|
|
||||||
|
void* aligned = etl::align(16, 8, ptr, space);
|
||||||
|
|
||||||
|
// 'buffer' is 16-aligned, so aligning 'buffer + 1' to 16 skips 15 bytes of
|
||||||
|
// padding, landing on 'buffer + 16' and shrinking 'space' by that padding.
|
||||||
|
CHECK(aligned != ETL_NULLPTR);
|
||||||
|
CHECK(reinterpret_cast<unsigned char*>(aligned) == buffer + 16);
|
||||||
|
CHECK(reinterpret_cast<unsigned char*>(ptr) == buffer + 16);
|
||||||
|
CHECK_EQUAL(sizeof(buffer) - 1 - 15, space);
|
||||||
|
|
||||||
|
// Not enough space returns nullptr.
|
||||||
|
void* small_ptr = buffer + 1;
|
||||||
|
size_t small_space = 2;
|
||||||
|
CHECK(etl::align(16, 8, small_ptr, small_space) == ETL_NULLPTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_assume_aligned)
|
||||||
|
{
|
||||||
|
alignas(16) int data[4] = {1, 2, 3, 4};
|
||||||
|
|
||||||
|
int* p = etl::assume_aligned<16>(&data[0]);
|
||||||
|
CHECK_EQUAL(&data[0], p);
|
||||||
|
CHECK_EQUAL(1, *p);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_is_sufficiently_aligned)
|
||||||
|
{
|
||||||
|
alignas(16) unsigned char buffer[32];
|
||||||
|
|
||||||
|
CHECK(etl::is_sufficiently_aligned<16>(buffer));
|
||||||
|
CHECK(etl::is_sufficiently_aligned<8>(buffer));
|
||||||
|
CHECK(!etl::is_sufficiently_aligned<16>(buffer + 1));
|
||||||
|
}
|
||||||
|
|
||||||
#if ETL_USING_CPP17
|
#if ETL_USING_CPP17
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
TEST(test_ranges_uninitialized_copy_iterator_trivial)
|
TEST(test_ranges_uninitialized_copy_iterator_trivial)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user