This finally makes it possible to expose APIs that take StridedArrayView
instances as an input, until now the type information was always lost,
making all views plain bytes and thus impossible to check whether the
types passed were a large enough size at least, if nothing else.
Preserving the type means there has to be type-dependent implementation
for __getitem__() and __setitem__(). So far this is only done for the
very basic builtin types, similarly to what Python's own array supports.
In the buffer protocol it used to advertise untyped data with B as the
format string, but the __getitem__ and __setitem__ were using the char
type (implicitly coming from the fact that the type exposed is
ArrayView<char>, StridedArrayViewND<char> or their const variants),
resulting in the data being treated as characters by Python. Which
was extremely annoying and inconsistent with how the bytes and bytearray
behaves.
Now ArrayView bindings always operate with std::uint8_t, and for
StridedArrayView there's a special case for the <char> type, which makes
it treated as std::uint8_t as well. Furthermore, to hint that the <char>
is "general data", the format string for it is null / None instead of B.
Changed those to be IndexError instead of ValueError, since those are
indexing dimensions. Plus added a new check for broadcasted dimension
size as otherwise it'd blow up on a C++ assert.