Skip to content

Instantly share code, notes, and snippets.

@jonitis
Created November 20, 2017 10:28
Show Gist options
  • Save jonitis/797712c7b8c61fb29cc9f06e675f1fff to your computer and use it in GitHub Desktop.
Save jonitis/797712c7b8c61fb29cc9f06e675f1fff to your computer and use it in GitHub Desktop.
array_view with std::byte
namespace impl
{
template <typename T>
using array_iterator = T*;
template <typename T>
auto make_array_iterator(T* data, uint32_t size, uint32_t index = 0) noexcept
{
return data + index;
}
}
template <typename From, typename To = From>
constexpr bool can_cast_from_std_byte =
sizeof(To) == 1 && std::is_same_v<std::remove_cv_t<From>, std::byte>;
template <typename T>
struct array_view {
using value_type = T;
using size_type = uint32_t;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = value_type*;
using const_pointer = value_type const*;
using iterator = impl::array_iterator<value_type>;
using const_iterator = impl::array_iterator<value_type const>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
array_view() noexcept = default;
template <typename C>
array_view(C* first, C* last,
std::enable_if_t<!can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
m_data(first),
m_size(static_cast<size_type>(last - first))
{}
template <typename C>
array_view(C* first, C* last,
std::enable_if_t<can_cast_from_std_byte<C, T>, C>* = nullptr) noexcept :
m_data(reinterpret_cast<T*>(first)),
m_size(static_cast<size_type>(last - first))
{}
#if 1
array_view(std::initializer_list<value_type> value) noexcept :
array_view(value.begin(), static_cast<size_type>(value.size()))
{}
#else
// I give up
#endif
template <typename C, size_type N>
array_view(C(&value)[N],
std::enable_if_t<!can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
array_view(value, N)
{}
template <typename C, size_type N>
array_view(C(&value)[N],
std::enable_if_t<can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
array_view(reinterpret_cast<T*>(value), N)
{}
template <typename C>
array_view(std::vector<C>& value,
std::enable_if_t<!can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C>
array_view(std::vector<C> const& value,
std::enable_if_t<!can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C>
array_view(std::vector<C>& value,
std::enable_if_t<can_cast_from_std_byte<C, T>, C>* = nullptr) noexcept :
array_view(reinterpret_cast<T*>(value.data()), static_cast<size_type>(value.size()))
{}
template <typename C>
array_view(std::vector<C> const& value,
std::enable_if_t<can_cast_from_std_byte<C, T>, C>* = nullptr) noexcept :
array_view(reinterpret_cast<T*>(value.data()), static_cast<size_type>(value.size()))
{}
template <typename C, size_type N>
array_view(std::array<C, N>& value,
std::enable_if_t<!can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C, size_type N>
array_view(std::array<C, N> const& value,
std::enable_if_t<!can_cast_from_std_byte<C, T>, T>* = nullptr) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C, size_type N>
array_view(std::array<C, N>& value,
std::enable_if_t<can_cast_from_std_byte<C, T>, C>* = nullptr) noexcept :
array_view(reinterpret_cast<T*>(value.data()), static_cast<size_type>(value.size()))
{}
template <typename C, size_type N>
array_view(std::array<C, N> const& value,
std::enable_if_t<can_cast_from_std_byte<C, T>, C>* = nullptr) noexcept :
array_view(reinterpret_cast<T*>(value.data()), static_cast<size_type>(value.size()))
{}
reference operator[](size_type const pos) noexcept
{
WINRT_ASSERT(pos < size());
return m_data[pos];
}
const_reference operator[](size_type const pos) const noexcept
{
WINRT_ASSERT(pos < size());
return m_data[pos];
}
reference at(size_type const pos)
{
if (size() <= pos) {
throw std::out_of_range("Invalid array subscript");
}
return m_data[pos];
}
const_reference at(size_type const pos) const
{
if (size() <= pos) {
throw std::out_of_range("Invalid array subscript");
}
return m_data[pos];
}
reference front() noexcept
{
WINRT_ASSERT(m_size > 0);
return*m_data;
}
const_reference front() const noexcept
{
WINRT_ASSERT(m_size > 0);
return*m_data;
}
reference back() noexcept
{
WINRT_ASSERT(m_size > 0);
return m_data[m_size - 1];
}
const_reference back() const noexcept
{
WINRT_ASSERT(m_size > 0);
return m_data[m_size - 1];
}
pointer data() noexcept
{
return m_data;
}
const_pointer data() const noexcept
{
return m_data;
}
iterator begin() noexcept
{
return impl::make_array_iterator(m_data, m_size);
}
const_iterator begin() const noexcept
{
return impl::make_array_iterator<value_type const>(m_data, m_size);
}
const_iterator cbegin() const noexcept
{
return impl::make_array_iterator<value_type const>(m_data, m_size);
}
iterator end() noexcept
{
return impl::make_array_iterator(m_data, m_size, m_size);
}
const_iterator end() const noexcept
{
return impl::make_array_iterator<value_type const>(m_data, m_size, m_size);
}
const_iterator cend() const noexcept
{
return impl::make_array_iterator<value_type const>(m_data, m_size, m_size);
}
reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept
{
return rbegin();
}
reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const noexcept
{
return rend();
}
bool empty() const noexcept
{
return m_size == 0;
}
size_type size() const noexcept
{
return m_size;
}
protected:
array_view(pointer data, uint32_t size) noexcept :
m_data(data),
m_size(size)
{}
pointer m_data{ nullptr };
uint32_t m_size{ 0 };
};
static void WriteBytes(const std::string& description, array_view<const uint8_t> buffer)
{
printf("WriteBytes(%s) --> array_view<const uint8_t>[%u]\n", description.c_str(), (int)buffer.size());
for (const auto& b : buffer) {
printf(" %u\n", b);
}
}
void WriteDwords(const std::string& description, array_view<uint32_t const> buffer)
{
printf("WriteDwords(%s) --> array_view<const uint32_t>[%u]\n", description.c_str(), (int)buffer.size());
for (const auto& b : buffer) {
printf(" %u\n", b);
}
}
static void ReadBytes(const std::string& description, array_view<uint8_t> buffer)
{
printf("ReadBytes(%s) --> array_view<uint8_t>[%u]\n", description.c_str(), (int)buffer.size());
uint8_t cnt = 0;
for (auto& b : buffer) {
b = cnt++;
}
}
void ReadDwords(const std::string& description, array_view<uint32_t> buffer)
{
printf("ReadDwords(%s) --> array_view<uint32_t>[%u]\n", description.c_str(), (int)buffer.size());
uint32_t cnt = 0;
for (auto& b : buffer) {
b = cnt++;
}
}
int main()
{
enum class Octet : uint8_t {};
// std::initializer_list (underlying array const T[N])
std::initializer_list<uint8_t> initializerListUint8 = { 1, 2, 3 };
std::initializer_list<std::byte> initializerListByte = { std::byte{1}, std::byte{2}, std::byte{3} };
std::initializer_list<Octet> initializerListOctet = { Octet{1}, Octet{2}, Octet{3} };
std::initializer_list<uint32_t> initializerListUint32 = { 1, 2, 3 };
std::initializer_list<const uint8_t> initializerListConstUint8 = { 1, 2, 3 };
std::initializer_list<const std::byte> initializerListConstByte = { std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
// raw C arrays (arrays themselves can't be constant)
uint8_t rawArrayUint8[] = { 1, 2, 3 };
std::byte rawArrayByte[] = { std::byte{1}, std::byte{2}, std::byte{3} };
Octet rawArrayOctet[] = { Octet{1}, Octet{2}, Octet{3} };
uint32_t rawArrayUint32[] = { 1, 2, 3 };
const uint8_t rawArrayConstUint8[] = { 1, 2, 3 };
const std::byte rawArrayConstByte[] = { std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
const Octet rawArrayConstOctet[] = { Octet{ 1 }, Octet{ 2 }, Octet{ 3 } };
const uint32_t rawArrayConstUint32[] = { 1, 2, 3 };
// std::array
std::array<uint8_t,3> arrayUint8 = { 1, 2, 3 };
std::array<std::byte, 3> arrayByte = { std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
std::array<Octet, 3> arrayOctet = { Octet{ 1 }, Octet{ 2 }, Octet{ 3 } };
std::array<uint32_t, 3> arrayUint32 = { 1, 2, 3 };
std::array<const uint8_t, 3> arrayConstUint8 = { 1, 2, 3 };
std::array<const std::byte, 3> arrayConstByte = { std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
std::array<const Octet, 3> arrayConstOctet = { Octet{ 1 }, Octet{ 2 }, Octet{ 3 } };
std::array<const uint32_t, 3> arrayConstUint32 = { 1, 2, 3 };
const std::array<uint8_t, 3> constArrayUint8 = { 1, 2, 3 };
const std::array<std::byte, 3> constArrayByte = { std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
const std::array<Octet, 3> constArrayOctet = { Octet{ 1 }, Octet{ 2 }, Octet{ 3 } };
const std::array<uint32_t, 3> constArrayUint32 = { 1, 2, 3 };
const std::array<const uint8_t, 3> constArrayConstUint8 = { 1, 2, 3 };
const std::array<const std::byte, 3> constArrayConstByte = { std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
const std::array<const Octet, 3> constArrayConstOctet = { Octet{ 1 }, Octet{ 2 }, Octet{ 3 } };
const std::array<const uint32_t, 3> constArrayConstUint32 = { 1, 2, 3 };
// std::vector (can't contain constant elements, since need to be resizable)
std::vector<uint8_t> vectorUint8 = { 1, 2, 3 };
std::vector<std::byte> vectorByte{ std::byte{1}, std::byte{2}, std::byte{3} };
std::vector<Octet> vectorOctet = { Octet{1}, Octet{2}, Octet{3} };
std::vector<uint32_t> vectorUint32 = { 1, 2, 3 };
const std::vector<uint8_t> constVectorUint8 = { 1, 2, 3 };
const std::vector<std::byte> constVectorByte{ std::byte{ 1 }, std::byte{ 2 }, std::byte{ 3 } };
const std::vector<Octet> constVectorOctet = { Octet{ 1 }, Octet{ 2 }, Octet{ 3 } };
const std::vector<uint32_t> constVectorUint32 = { 1, 2, 3 };
// pair of pointers
uint8_t* ptrUint8First = vectorUint8.data();
uint8_t* ptrUint8Last = ptrUint8First + vectorUint8.size();
std::byte* ptrByteFirst = vectorByte.data();
std::byte* ptrByteLast = ptrByteFirst + vectorByte.size();
Octet* ptrOctetFirst = vectorOctet.data();
Octet* ptrOctetLast = ptrOctetFirst + vectorOctet.size();
uint32_t* ptrUint32First = vectorUint32.data();
uint32_t* ptrUint32Last = ptrUint32First + vectorUint32.size();
const uint8_t* ptrConstUint8First = constVectorUint8.data();
const uint8_t* ptrConstUint8Last = ptrConstUint8First + constVectorUint8.size();
const std::byte* ptrConstByteFirst = constVectorByte.data();
const std::byte* ptrConstByteLast = ptrConstByteFirst + constVectorByte.size();
uint8_t* const constPtrUint8First = vectorUint8.data();
uint8_t* const constPtrUint8Last = constPtrUint8First + vectorUint8.size();
std::byte* const constPtrByteFirst = vectorByte.data();
std::byte* const constPtrByteLast = constPtrByteFirst + vectorByte.size();
const uint8_t* const constPtrConstUint8First = constVectorUint8.data();
const uint8_t* const constPtrConstUint8Last = constPtrConstUint8First + constVectorUint8.size();
const std::byte* const constPtrConstByteFirst = constVectorByte.data();
const std::byte* const constPtrConstByteLast = constPtrConstByteFirst + constVectorByte.size();
//--- 1. pointer first, pointer last -------------------------------------------------------------
WriteBytes("uint8_t* first, uint8_t* last", array_view<const uint8_t> ( ptrUint8First, ptrUint8Last ));
WriteBytes("const uint8_t* first, const uint8_t* last", { ptrConstUint8First, ptrConstUint8Last });
WriteBytes("uint8_t* const first, uint8_t* const last", { constPtrUint8First, constPtrUint8Last });
WriteBytes("const uint8_t* const first, const uint8_t* const last", { constPtrConstUint8First, constPtrConstUint8Last });
WriteBytes("std::byte* first, std::byte* last", { ptrByteFirst, ptrByteLast });
WriteBytes("const std::byte* first, const std::byte* last", { ptrConstByteFirst, ptrConstByteLast });
WriteBytes("std::byte* const first, std::byte* const last", { constPtrByteFirst, constPtrByteLast });
WriteBytes("const std::byte* const first, const std::byte* const last", { constPtrConstByteFirst, constPtrConstByteLast });
//WriteBytes("Octet* first, Octet* last", { ptrOctetFirst, ptrOctetLast }); // Error: Octet not convertible to uint8_t
//WriteBytes("uint32_t* first, uint32_t* last", { ptrUint32First, ptrUint32Last }); // Error: uint32_t not convertible to uint8_t
//--- 2. std::initializer_list ------------------------------------------------------------------
// WriteBytes("std::initializer_list<uint8_t>", initializerListUint8);
//WriteBytes("std::initializer_list<const uint8_t>", initializerListConstUint8);
WriteBytes("std::initializer_list<uint8_t>", { 1, 2, 3 });
// WriteBytes("std::initializer_list<std::byte>", initializerListByte);
// WriteBytes("std::initializer_list<uint8_t>", { std::byte{1}, std::byte{2}, std::byte{3} });
//WriteBytes("std::initializer_list<Octet>", initializerListOctet); // Error: Octet not convertible to uint8_t
//WriteBytes("std::initializer_list<uint32_t>", initializerListUint32); // Error: uint32_t not convertible to uint8_t
//--- 3. raw C array ----------------------------------------------------------------------------
WriteBytes("uint8_t[]", rawArrayUint8);
WriteBytes("const uint8_t[]", rawArrayConstUint8);
WriteBytes("std::byte[]", rawArrayByte);
WriteBytes("const std::byte[]", rawArrayConstByte);
//WriteBytes("Octet[]", rawArrayOctet); // Error: Octet not convertible to uint8_t
//WriteBytes("uint32_t[]", rawArrayUint32); // Error: uint32_t not convertible to uint8_t
ReadBytes("uint8_t[]", rawArrayUint8);
//ReadBytes("const uint8_t[]", rawArrayConstUint8); // Error: const uint8_t not convertible to uint8_t
ReadBytes("std::byte[]", rawArrayByte);
//ReadBytes("const std::byte[]", rawArrayConstByte); // Error: const uint8_t not convertible to uint8_t
//ReadBytes("Octet[]", rawArrayOctet); // Error: Octet not convertible to uint8_t
//ReadBytes("uint32_t[]", rawArrayUint32); // Error: uint32_t not convertible to uint8_t
//--- 4. std::vector ----------------------------------------------------------------------------
WriteBytes("std::vector<uint8_t>", vectorUint8);
WriteBytes("const std::vector<uint8_t>", constVectorUint8);
WriteBytes("std::vector<std::byte>", vectorByte);
WriteBytes("const std::vector<std::byte>", constVectorByte);
//WriteBytes("std::vector<Octet>", vectorOctet); // Error: Octet not convertible to uint8_t
//WriteBytes("std::vector<uint32_t>", vectorUint32); // Error: uint32_t not convertible to uint8_t
//WriteDwords("std::vector<uint8_t>", vectorUint8); // Error: uint8_t not covertible to uint32_t
//WriteDwords("std::vector<std::byte>", vectorByte); // Error: std::byte not convertible to uint32_t
WriteDwords("std::vector<uint32_t>", vectorUint32);
ReadBytes("std::vector<uint8_t>", vectorUint8);
//ReadBytes("const std::vector<uint8_t>", constVectorUint8); // Error: const uint8_t not convertible to uint8_t
ReadBytes("std::vector<std::byte>", vectorByte);
//ReadBytes("const std::vector<std::byte>", constVectorByte); // Error: const std::byte not convertible to uint8_t
//ReadBytes("std::vector<Octet>", vectorOctet); // Error: Octet not convertible to uint8_t
//ReadBytes("std::vector<uint32_t>", vectorUint32); // Error: uint32_t not convertible to uint8_t
//--- 5. std::array -----------------------------------------------------------------------------
WriteBytes("std::array<uint8_t>", arrayUint8);
WriteBytes("std::array<const uint8_t>", arrayConstUint8);
WriteBytes("const std::array<uint8_t>", constArrayUint8);
WriteBytes("const std::array<const uint8_t>", constArrayConstUint8);
WriteBytes("std::array<std::byte>", arrayByte);
WriteBytes("std::array<const std::byte>", arrayConstByte);
WriteBytes("const std::array<std::byte>", constArrayByte);
WriteBytes("const std::array<const std::byte>", constArrayConstByte);
//WriteBytes("std::array<Octet>", arrayOctet); // Error: Octet not convertible to uint8_t
//WriteBytes("std::array<uint32_t>", arrayUint32); // Error: uint32_t not convertible to uint8_t
ReadBytes("std::array<uint8_t>", arrayUint8);
//ReadBytes("std::array<const uint8_t>", arrayConstUint8); // Error: const uint8_t not convertible to uint8_t
//ReadBytes("const std::array<uint8_t>", constArrayUint8); // Error: const uint8_t not convertible to uint8_t
//ReadBytes("const std::array<const uint8_t>", constArrayConstUint8); // Error: const uint8_t not convertible to uint8_t
ReadBytes("std::array<std::byte>", arrayByte);
//ReadBytes("std::array<const std::byte>", arrayConstByte); // Error: const uint8_t not convertible to uint8_t
//ReadBytes("const std::array<std::byte>", constArrayByte); // Error: const uint8_t not convertible to uint8_t
//ReadBytes("const std::array<const std::byte>", constArrayConstByte); // Error: const uint8_t not convertible to uint8_t
//ReadBytes("std::array<Octet>", arrayOctet); // Error: Octet not convertible to uint8_t
//ReadBytes("std::array<uint32_t>", arrayUint32); // Error: uint32_t not convertible to uint8_t
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment