patterncppMinor
GSL-like array_view implementation
Viewed 0 times
implementationgsllikearray_view
Problem
I've seen a couple GSL-like
My implementation is a simplified
```
#include
#include
#include
#include
#include
#include
#include
namespace cr
{
template
class array_view final
{
public:
//
// Nested types:
//
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = std::add_pointer_t;
using reference = std::add_lvalue_reference_t;
using const_pointer = std::add_pointer_t;
using const_reference = std::add_lvalue_reference_t;
using iterator = array_iterator_base;
using const_iterator = array_iterator_base;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
//
// Constructors / assignment:
//
constexpr array_view() noexcept
: m_pointer{ nullptr }
, m_size_in_items{ 0 }
{ }
template
constexpr explicit array_view(ArrayType (&arr)[ArraySize]) noexcept
: m_pointer{ arr }
, m_size_in_items{ ArraySize }
{ }
template
constexpr explicit array_view(ContainerType & container) noexcept
: m_pointer{ container.data() }
, m_size_in_items{ container.size() }
{ }
template
constexpr array_view(ConvertibleType * array_ptr, const size_type size_in_items) noexcept
: m_pointer{ array_ptr }
, m_size_in_items{ size_in_items }
{ }
tem
string_view-ish implementations on CR recently, but don't recall seeing anything like array_view yet (AKA span in the GSL), so I wrote one just for fun!My implementation is a simplified
array_view that doesn't support the bounds and indexing in the same way the GSL span does. I also didn't add support for multidimensional arrays, data is always assumed to be a flat 1D array. Here's the documentation for a complete array_view class that might some day make into the Standard library.```
#include
#include
#include
#include
#include
#include
#include
namespace cr
{
template
class array_view final
{
public:
//
// Nested types:
//
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = std::add_pointer_t;
using reference = std::add_lvalue_reference_t;
using const_pointer = std::add_pointer_t;
using const_reference = std::add_lvalue_reference_t;
using iterator = array_iterator_base;
using const_iterator = array_iterator_base;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
//
// Constructors / assignment:
//
constexpr array_view() noexcept
: m_pointer{ nullptr }
, m_size_in_items{ 0 }
{ }
template
constexpr explicit array_view(ArrayType (&arr)[ArraySize]) noexcept
: m_pointer{ arr }
, m_size_in_items{ ArraySize }
{ }
template
constexpr explicit array_view(ContainerType & container) noexcept
: m_pointer{ container.data() }
, m_size_in_items{ container.size() }
{ }
template
constexpr array_view(ConvertibleType * array_ptr, const size_type size_in_items) noexcept
: m_pointer{ array_ptr }
, m_size_in_items{ size_in_items }
{ }
tem
Solution
Implementation
Template restrictions
if(slice_ptr > end_ptr)insidearray_view::slice(const size_type, const size_type)might invoke undefined behavior (it's undefined if the condition would returntrueand the original allocation of the underlying contiguous memory ends atend_ptr). However, it could easily be replaced with the logically equivalentif(start_offset > size()). Also, the comparison should be>=instead of>, asend_ptralready points 1 past the last covered element, so starting a non-empty array slice there isn't possible.
if (slice_size > (size() - start_offset))in the same function could be combined with the check above toif (end_offset
- The comparison operators invoke undefined behavior unless both array_view
s are slices of the same underlying array. This could be fixed by usingstd::less(or corresponding equivalents) to do the comparison, but what would be a use case of comparing the addresses of the two arrays relatively to each other?
Template restrictions
- array_view::value_type
should probably be restricted tostd::remove_reference, as there can not be an array of references.
- ArrayType
(of thearray_viewconstructor) can only ever legally be the same asarray_view::value_type, so this template parameter is not necessary. With the lack of proper restrictions, it would allow to assign an array of objects derived fromarray_view::value_type, which cannot be indexed correctly (m_pointer[1]might not point to the address ofarr[1]ifsizeof(array_view::value_type)
- I don't think
ConvertibleType(see the two constructors and the assignment operator) is treated correctly either:
- If
ConvertibleTypeis derived fromarray_view::value_type, the same problem as withArrayTypeabove occurs.
- If
ConvertibleTypeis has a conversion operator toarray_view::value_type, the pointer cannot be correctly assigned tom_pointerlegally (only legal forarray_view::pointeror derived types).
Context
StackExchange Code Review Q#117508, answer score: 3
Revisions (0)
No revisions yet.