Skip to content

Commit

Permalink
util/Unaligned: new library
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKellermann committed Nov 6, 2023
1 parent 20016a9 commit 9b9203e
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/util/Unaligned.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: BSD-2-Clause
// author: Max Kellermann <[email protected]>

#pragma once

#include <cstring> // for std::memcpy()
#include <type_traits>

/**
* Load an unaligned (maybe misaligned) value from memory.
*/
template<typename T>
requires std::is_standard_layout_v<T> && std::is_trivially_copyable_v<T>
[[nodiscard]] [[gnu::pure]] [[gnu::nonnull]]
static inline T
LoadUnaligned(const void *src) noexcept
{
T value;
std::memcpy(&value, src, sizeof(value));
return value;
}

/**
* Store a value to an unaligned (maybe misaligned) pointer.
*/
template<typename T>
requires std::is_standard_layout_v<T> && std::is_trivially_copyable_v<T>
[[gnu::nonnull]]
static inline void
StoreUnaligned(void *dest, const T &value) noexcept
{
std::memcpy(dest, &value, sizeof(value));
}
57 changes: 57 additions & 0 deletions test/util/TestUnaligned.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: BSD-2-Clause
// author: Max Kellermann <[email protected]>

#include "util/Unaligned.hxx"
#include "util/ByteOrder.hxx"

#include <gtest/gtest.h>

#include <array>

TEST(Unaligned, Unaligned)
{
struct Foo {
// this member defines the alignment of this struct
uint64_t dummy;

std::array<std::byte, 9> buffer;
} foo;

std::fill(foo.buffer.begin(), foo.buffer.end(), std::byte{0xff});
EXPECT_EQ(LoadUnaligned<uint64_t>(foo.buffer.data() + 1),
0xffffffffffffffffULL);

constexpr uint64_t token = 0xc0ffeedeadbeef;

StoreUnaligned(foo.buffer.data() + 1, token);
EXPECT_EQ(LoadUnaligned<uint64_t>(foo.buffer.data() + 1),
token);

std::fill(foo.buffer.begin(), foo.buffer.end(), std::byte{0xff});
EXPECT_EQ(LoadUnaligned<uint64_t>(foo.buffer.data() + 1),
0xffffffffffffffffULL);
EXPECT_EQ(foo.buffer[1], std::byte{0xff});
EXPECT_EQ(foo.buffer[2], std::byte{0xff});
EXPECT_EQ(foo.buffer[3], std::byte{0xff});
EXPECT_EQ(foo.buffer[4], std::byte{0xff});
EXPECT_EQ(foo.buffer[5], std::byte{0xff});
EXPECT_EQ(foo.buffer[6], std::byte{0xff});
EXPECT_EQ(foo.buffer[7], std::byte{0xff});
EXPECT_EQ(foo.buffer[8], std::byte{0xff});

StoreUnaligned(foo.buffer.data() + 1, ToBE64(token));
EXPECT_EQ(foo.buffer[1], std::byte{0x00});
EXPECT_EQ(foo.buffer[2], std::byte{0xc0});
EXPECT_EQ(foo.buffer[3], std::byte{0xff});
EXPECT_EQ(foo.buffer[4], std::byte{0xee});
EXPECT_EQ(foo.buffer[5], std::byte{0xde});
EXPECT_EQ(foo.buffer[6], std::byte{0xad});
EXPECT_EQ(foo.buffer[7], std::byte{0xbe});
EXPECT_EQ(foo.buffer[8], std::byte{0xef});
EXPECT_EQ(LoadUnaligned<uint64_t>(foo.buffer.data() + 1),
ToBE64(token));
EXPECT_EQ(LoadUnaligned<uint32_t>(foo.buffer.data() + 1),
ToBE32(static_cast<uint32_t>(token >> 32)));
EXPECT_EQ(LoadUnaligned<uint32_t>(foo.buffer.data() + 5),
ToBE32(static_cast<uint32_t>(token)));
}
1 change: 1 addition & 0 deletions test/util/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ test(
'TestStaticCache.cxx',
'TestStringStrip.cxx',
'TestTemplateString.cxx',
'TestUnaligned.cxx',
'TestVCircularBuffer.cxx',
include_directories: inc,
dependencies: [gtest, util_dep],
Expand Down

0 comments on commit 9b9203e

Please sign in to comment.