Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/etl/file_error_numbers.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,6 @@ SOFTWARE.
#define ETL_EXPECTED_FILE_ID "70"
#define ETL_ALIGNMENT_FILE_ID "71"
#define ETL_BASE64_FILE_ID "72"
#define ETL_UNALIGNED_TYPE_FILE_ID "73"

#endif
110 changes: 110 additions & 0 deletions include/etl/unaligned_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ SOFTWARE.
#include "platform.h"
#include "type_traits.h"
#include "endianness.h"
#include "error_handler.h"
#include "exception.h"
#include "iterator.h"
#include "algorithm.h"
#include "bit.h"
Expand All @@ -46,6 +48,34 @@ SOFTWARE.

namespace etl
{
//***************************************************************************
/// The base class for unaligned_type exceptions.
///\ingroup pool
//***************************************************************************
struct unaligned_type_exception : public etl::exception
{
public:

unaligned_type_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
: exception(reason_, file_name_, line_number_)
{
}
};

//***************************************************************************
/// The base class for unaligned_type buffer overflow.
///\ingroup pool
//***************************************************************************
class unaligned_type_buffer_size : public unaligned_type_exception
{
public:

unaligned_type_buffer_size(string_type file_name_, numeric_type line_number_)
: unaligned_type_exception(ETL_ERROR_TEXT("unaligned_type:buffer size", ETL_UNALIGNED_TYPE_FILE_ID"A"), file_name_, line_number_)
{
}
};

namespace private_unaligned_type
{
//*************************************************************************
Expand Down Expand Up @@ -729,6 +759,86 @@ namespace etl
}
}
};

//*******************************************
/// at_address
///\brief Helps to reinterprete memory as unaligned_type. Overload for write access.
///\param address Pointer to memory to be reinterpreted.
///\return Reference to unaligned_type object at location specified by address
//*******************************************
static unaligned_type<T, Endian_>& at_address(void* address)
{
return *reinterpret_cast<unaligned_type<T, Endian_>*>(address);
}

//*******************************************
/// at_address
///\brief Helps to reinterprete memory as unaligned_type. Overload for read only access to const memory.
///\param address Pointer to memory to be reinterpreted.
///\return Reference to unaligned_type object at location specified by address
//*******************************************
static const unaligned_type<T, Endian_>& at_address(const void* address)
{
return *reinterpret_cast<const unaligned_type<T, Endian_>*>(address);
}

//*******************************************
/// at_address
///\brief Helps to reinterprete memory as unaligned_type. Overload for write access.
///\param address Pointer to memory to be reinterpreted.
///\param buffer_size Size in bytes for run time size check
///\return Reference to unaligned_type object at location specified by address
//*******************************************
static unaligned_type<T, Endian_>& at_address(void* address, size_t buffer_size)
{
ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::unaligned_type_buffer_size));

return *reinterpret_cast<unaligned_type<T, Endian_>*>(address);
}

//*******************************************
/// at_address
///\brief Helps to reinterprete memory as unaligned_type. Overload for read only access to const memory.
///\param address Pointer to memory to be reinterpreted.
///\param buffer_size Size in bytes for runtime size check
///\return Reference to unaligned_type object at location specified by address
//*******************************************
static const unaligned_type<T, Endian_>& at_address(const void* address, size_t buffer_size)
{
ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::unaligned_type_buffer_size));

return *reinterpret_cast<const unaligned_type<T, Endian_>*>(address);
}

//*******************************************
/// at_address
///\brief Helps to reinterprete memory as unaligned_type. Overload for write access.
///\tparam BufferSize Size in bytes for compile time size check
///\param address Pointer to memory to be reinterpreted.
///\return Reference to unaligned_type object at location specified by address
//*******************************************
template <size_t BufferSize>
static unaligned_type<T, Endian_>& at_address(void* address)
{
ETL_STATIC_ASSERT(sizeof(T) <= BufferSize, "Buffer size to small for type");

return *reinterpret_cast<unaligned_type<T, Endian_>*>(address);
}

//*******************************************
/// at_address
///\brief Helps to reinterprete memory as unaligned_type. Overload for read only access to const memory.
///\tparam BufferSize Size in bytes for compile time size check
///\param address Pointer to memory to be reinterpreted.
///\return Reference to unaligned_type object at location specified by address
//*******************************************
template <size_t BufferSize>
static const unaligned_type<T, Endian_>& at_address(const void* address)
{
ETL_STATIC_ASSERT(sizeof(T) <= BufferSize, "Buffer size to small for type");

return *reinterpret_cast<const unaligned_type<T, Endian_>*>(address);
}
};

template <typename T, int Endian_>
Expand Down
62 changes: 62 additions & 0 deletions test/test_unaligned_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,68 @@ namespace
CHECK_EQUAL(0x12, bev0);
CHECK_EQUAL(0x34, bev1);
}

//*************************************************************************
TEST(test_at_address)
{
uint8_t data[] = {0x01, 0x02, 0x03, 0x04};

CHECK_EQUAL(etl::be_uint32_t::at_address(data), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address(data), 0x04030201);

// with overflow checks: at runtime
CHECK_EQUAL(etl::be_uint32_t::at_address(data, sizeof(data)), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address(data, sizeof(data)), 0x04030201);
CHECK_EQUAL(etl::be_uint32_t::at_address(data, sizeof(data) + 1), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address(data, sizeof(data) + 1), 0x04030201);
CHECK_THROW(etl::be_uint32_t::at_address(data, sizeof(data) - 1), etl::unaligned_type_buffer_size);
CHECK_THROW(etl::le_uint32_t::at_address(data, sizeof(data) - 1), etl::unaligned_type_buffer_size);
CHECK_THROW(etl::be_uint32_t::at_address(data, 0), etl::unaligned_type_buffer_size);
CHECK_THROW(etl::le_uint32_t::at_address(data, 0), etl::unaligned_type_buffer_size);

// with overflow checks: at compile time
CHECK_EQUAL(etl::be_uint32_t::at_address<sizeof(data)>(data), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address<sizeof(data)>(data), 0x04030201);
CHECK_EQUAL(etl::be_uint32_t::at_address<sizeof(data) + 1>(data), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address<sizeof(data) + 1>(data), 0x04030201);
// static_assert:
//CHECK_THROW(etl::be_uint32_t::at_address<sizeof(data) - 1>(data), etl::unaligned_type_buffer_size);
//CHECK_THROW(etl::le_uint32_t::at_address<sizeof(data) - 1>(data), etl::unaligned_type_buffer_size);
//CHECK_THROW(etl::be_uint32_t::at_address<0>(data), etl::unaligned_type_buffer_size);
//CHECK_THROW(etl::le_uint32_t::at_address<0>(data), etl::unaligned_type_buffer_size);

etl::be_uint32_t::at_address(data) = 0x12345678;
CHECK_EQUAL(etl::le_uint32_t::at_address(data), 0x78563412);
}

TEST(test_const_at_address)
{
const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};

CHECK_EQUAL(etl::be_uint32_t::at_address(data), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address(data), 0x04030201);

// with overflow checks: at runtime
CHECK_EQUAL(etl::be_uint32_t::at_address(data, sizeof(data)), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address(data, sizeof(data)), 0x04030201);
CHECK_EQUAL(etl::be_uint32_t::at_address(data, sizeof(data) + 1), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address(data, sizeof(data) + 1), 0x04030201);
CHECK_THROW(etl::be_uint32_t::at_address(data, sizeof(data) - 1), etl::unaligned_type_buffer_size);
CHECK_THROW(etl::le_uint32_t::at_address(data, sizeof(data) - 1), etl::unaligned_type_buffer_size);
CHECK_THROW(etl::be_uint32_t::at_address(data, 0), etl::unaligned_type_buffer_size);
CHECK_THROW(etl::le_uint32_t::at_address(data, 0), etl::unaligned_type_buffer_size);

// with overflow checks: at compile time
CHECK_EQUAL(etl::be_uint32_t::at_address<sizeof(data)>(data), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address<sizeof(data)>(data), 0x04030201);
CHECK_EQUAL(etl::be_uint32_t::at_address<sizeof(data) + 1>(data), 0x01020304);
CHECK_EQUAL(etl::le_uint32_t::at_address<sizeof(data) + 1>(data), 0x04030201);
// static_assert:
//CHECK_THROW(etl::be_uint32_t::at_address<sizeof(data) - 1>(data), etl::unaligned_type_buffer_size);
//CHECK_THROW(etl::le_uint32_t::at_address<sizeof(data) - 1>(data), etl::unaligned_type_buffer_size);
//CHECK_THROW(etl::be_uint32_t::at_address<0>(data), etl::unaligned_type_buffer_size);
//CHECK_THROW(etl::le_uint32_t::at_address<0>(data), etl::unaligned_type_buffer_size);
}
};
}

Expand Down
Loading