mirror of https://github.com/openXC7/prjxray.git
lib: adapter to read big-endian words from a span<> containing bytes
Signed-off-by: Rick Altherr <kc8apf@kc8apf.net> Signed-off-by: Tim 'mithro' Ansell <mithro@mithis.com>
This commit is contained in:
parent
9f1e936ab0
commit
fdf0bc46a1
|
|
@ -6,6 +6,11 @@ target_include_directories(libprjxray PUBLIC "include")
|
|||
target_link_libraries(libprjxray absl::strings)
|
||||
|
||||
if (PRJXRAY_BUILD_TESTING)
|
||||
add_executable(big_endian_span_test big_endian_span_test.cc)
|
||||
target_link_libraries(big_endian_span_test libprjxray gtest_main)
|
||||
add_test(NAME big_endian_span_test
|
||||
COMMAND big_endian_span_test)
|
||||
|
||||
add_executable(bit_ops_test bit_ops_test.cc)
|
||||
target_link_libraries(bit_ops_test libprjxray gtest_main)
|
||||
add_test(NAME bit_ops_test
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
#include <prjxray/big_endian_span.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(BigEndianSpanTest, Read32WithEmptySpan) {
|
||||
std::vector<uint8_t> bytes;
|
||||
auto words = prjxray::make_big_endian_span<uint32_t>(bytes);
|
||||
EXPECT_EQ(words.size(), static_cast<size_t>(0));
|
||||
}
|
||||
|
||||
TEST(BigEndianSpanTest, Read32WithTooFewBytes) {
|
||||
std::vector<uint8_t> bytes{0x0, 0x1, 0x2};
|
||||
auto words = prjxray::make_big_endian_span<uint32_t>(bytes);
|
||||
EXPECT_EQ(words.size(), static_cast<size_t>(0));
|
||||
}
|
||||
|
||||
TEST(BigEndianSpanTest, Read32WithExactBytes) {
|
||||
std::vector<uint8_t> bytes{0x0, 0x1, 0x2, 0x3};
|
||||
auto words = prjxray::make_big_endian_span<uint32_t>(bytes);
|
||||
ASSERT_EQ(words.size(), static_cast<size_t>(1));
|
||||
EXPECT_EQ(words[0], static_cast<uint32_t>(0x00010203));
|
||||
}
|
||||
|
||||
TEST(BigEndianSpanTest, Read32WithMultipleWords) {
|
||||
std::vector<uint8_t> bytes{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
|
||||
auto words = prjxray::make_big_endian_span<uint32_t>(bytes);
|
||||
ASSERT_EQ(words.size(), static_cast<size_t>(2));
|
||||
EXPECT_EQ(words[0], static_cast<uint32_t>(0x00010203));
|
||||
EXPECT_EQ(words[1], static_cast<uint32_t>(0x04050607));
|
||||
}
|
||||
|
||||
TEST(BigEndianSpanTest, Write32) {
|
||||
std::vector<uint8_t> bytes{0x0, 0x1, 0x2, 0x3};
|
||||
auto words = prjxray::make_big_endian_span<uint32_t>(bytes);
|
||||
words[0] = 0x04050607;
|
||||
|
||||
std::vector<uint8_t> expected{0x4, 0x5, 0x6, 0x7};
|
||||
EXPECT_EQ(bytes, expected);
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
#ifndef PRJXRAY_LIB_BIG_ENDIAN_SPAN
|
||||
#define PRJXRAY_LIB_BIG_ENDIAN_SPAN
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
#include <absl/types/span.h>
|
||||
|
||||
namespace prjxray {
|
||||
|
||||
template<typename WordType, typename ByteType>
|
||||
class BigEndianSpan {
|
||||
public:
|
||||
constexpr static size_t kBytesPerElement = sizeof(WordType);
|
||||
|
||||
using byte_type = ByteType;
|
||||
using word_type = WordType;
|
||||
using size_type = std::size_t;
|
||||
|
||||
class value_type {
|
||||
public:
|
||||
operator WordType() const {
|
||||
WordType word = 0;
|
||||
for(size_t ii = 0; ii < kBytesPerElement; ++ii) {
|
||||
word |= (static_cast<WordType>(bytes_[ii]) << ((kBytesPerElement - 1 - ii) * 8));
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
value_type& operator=(WordType word) {
|
||||
for (size_t ii = 0; ii < kBytesPerElement; ++ii) {
|
||||
bytes_[ii] = ((word >> ((kBytesPerElement - 1 - ii) * 8)) & 0xFF);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class BigEndianSpan<WordType, ByteType>;
|
||||
|
||||
value_type(absl::Span<ByteType> bytes) : bytes_(bytes) {};
|
||||
|
||||
private:
|
||||
absl::Span<ByteType> bytes_;
|
||||
};
|
||||
|
||||
class iterator
|
||||
: public std::iterator<std::input_iterator_tag, value_type> {
|
||||
public:
|
||||
value_type operator*() const {
|
||||
return value_type(bytes_);
|
||||
}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return bytes_ == other.bytes_;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return bytes_ != other.bytes_;
|
||||
}
|
||||
|
||||
iterator& operator++() {
|
||||
bytes_ = bytes_.subspan(kBytesPerElement);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class BigEndianSpan<WordType, ByteType>;
|
||||
|
||||
iterator(absl::Span<ByteType> bytes) : bytes_(bytes) {};
|
||||
|
||||
private:
|
||||
absl::Span<ByteType> bytes_;
|
||||
};
|
||||
|
||||
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
BigEndianSpan(absl::Span<ByteType> bytes) : bytes_(bytes) {};
|
||||
|
||||
constexpr size_type size() const noexcept {
|
||||
return bytes_.size() / kBytesPerElement;
|
||||
};
|
||||
|
||||
constexpr size_type length() const noexcept { return size(); }
|
||||
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
value_type operator[](size_type pos) const {
|
||||
assert(pos >= 0 && pos < size());
|
||||
return value_type(bytes_.subspan((pos*kBytesPerElement)));
|
||||
}
|
||||
|
||||
constexpr reference at(size_type pos) const {
|
||||
return this->operator[](pos);
|
||||
}
|
||||
|
||||
iterator begin() const { return iterator(bytes_); }
|
||||
iterator end() const { return iterator({}); }
|
||||
|
||||
private:
|
||||
|
||||
absl::Span<ByteType> bytes_;
|
||||
};
|
||||
|
||||
template<typename WordType, typename Container>
|
||||
BigEndianSpan<WordType, typename Container::value_type> make_big_endian_span(
|
||||
Container &bytes) {
|
||||
return BigEndianSpan<WordType, typename Container::value_type>(
|
||||
absl::Span<typename Container::value_type>(bytes));
|
||||
}
|
||||
|
||||
} // namespace prjxray
|
||||
|
||||
#endif // PRJXRAY_LIB_BIG_ENDIAN_SPAN
|
||||
Loading…
Reference in New Issue