Created
November 20, 2017 10:28
-
-
Save jonitis/797712c7b8c61fb29cc9f06e675f1fff to your computer and use it in GitHub Desktop.
array_view with std::byte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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