This class was inspired from Microsoft's array_view.
It intended to use with mmap-ed memory for easily check bounds and so on.
I probably will need to throw exceptions, but this is not my usual way of working.
Any comments are welcome.
I left some casts like C-style casts because I see Alexandrescu is using the same and I am not alone :)
I also added a method for relative as(). It uses pointer and pointer arithmetic.
First here is some real usage:
/* BlobRef blob */
size_type const nodesCount = blob.size() / sizeof(Node);
const Node *nodes = blob.as<const Node>(0, nodesCount);
if (!nodes){
log__("Problem, switch alternative");
return false;
}
size_type pos = 0;
while(pos < nodesCount){
const Node &node = nodes[pos];
// ...
}
Here is the class:
#include <cstddef> // size_t
#include <type_traits> // is_pod
class BlobRef{
public:
BlobRef() = default;
BlobRef(const void *mem, size_t const size) noexcept :
mem_( (const char *) mem ),
size_(size){}
template<size_t N>
BlobRef(const char(&mem)[N]) noexcept:
BlobRef(mem, N){}
public:
bool empty() const noexcept{
return mem_ == nullptr || size_ == 0;
}
size_t size() const noexcept{
return size_;
}
const void *data_() const noexcept{
return mem_;
}
void reset() noexcept{
mem_ = nullptr;
size_ = 0;
}
public:
const void *safeAccessMemory(size_t const pos, size_t const size) const noexcept{
if (empty() || size == 0 || pos + size > size_)
return nullptr;
return & mem_[pos];
}
const void *safeAccessMemory(const void *ptr, size_t const size) const noexcept{
const char *ptrc = (const char *) ptr;
if (empty() || size == 0 || ptrc == nullptr || ptrc < mem_)
return nullptr;
/* long int */ auto const pos = ptrc - mem_;
return safeAccessMemory((size_t) pos, size);
}
public:
template <class T>
const T *as(size_t const pos, size_t const elements = 1) const noexcept{
static_assert(std::is_pod<T>::value, "T must be POD type");
return reinterpret_cast<const T *>( safeAccessMemory(pos, elements * sizeof(T)) );
}
template <class T>
const T *as(const void *ptr, size_t const elements = 1) const noexcept{
static_assert(std::is_pod<T>::value, "T must be POD type");
return reinterpret_cast<const T *>( safeAccessMemory(ptr, elements * sizeof(T)) );
}
// ambiguous call guard fpr 0
template <class T>
const T *as(int const pos = 0, size_t const elements = 1) const noexcept{
return as<T>( (size_t) pos, elements );
}
private:
const char *mem_ = nullptr;
size_t size_ = 0;
};
Here are the tests:
#include "blobref.h"
#include <cstdint>
#include <cstring>
#include <assert.h>
#include <endian.h>
#include <iostream>
#include <iomanip>
int test_blobref(){
constexpr size_t SIZE = 256;
char mem[SIZE];
for(int i = 0; i < SIZE; ++i)
mem[i] = (char) i;
BlobRef br{ mem };
assert(*br.as<uint16_t>(0x00) == htobe16(0x0001) );
assert(*br.as<uint16_t>(0x0E) == htobe16(0x0E0F) );
assert(*br.as<uint32_t>(0x10) == htobe32(0x10111213) );
{
const char *s = br.as<char>('a', 5);
assert(strncmp(s, "abcde", 5) == 0);
// relative
assert(*br.as<char>(s + 5) == 'f');
}
{
struct TestStruct{
uint16_t i;
char c;
char s[4];
}__attribute__((__packed__));
const TestStruct *st = br.as<TestStruct>(0x50);
assert(st->i == htobe16(0x5051) );
assert(st->c == 0x52 );
assert(st->s[0] == 0x53 );
assert(st->s[1] == 0x54 );
assert(st->s[2] == 0x55 );
assert(st->s[3] == 0x56 );
// relative
const char *stc = (const char *) st;
assert(*br.as<char>(stc + sizeof(TestStruct)) == 0x57);
}
{
size_t const max = SIZE / sizeof(uint64_t);
const uint64_t *u64 = br.as<uint64_t>(0, max);
assert(u64 != nullptr );
assert(u64[ 0] == htobe64(0x0001020304050607) );
assert(u64[max - 1] == htobe64(0xf8f9fafbFCFDFEFF) );
// relative
const uint64_t *p = & u64[max - 2];
assert(*br.as<uint64_t>(p + 1) == u64[max - 1] );
}
{
size_t const max = SIZE / sizeof(uint64_t) ;
// after last
assert(br.as<uint64_t>(0, max + 1 ) == nullptr );
}
{
size_t const max = SIZE / sizeof(uint64_t) ;
const uint64_t *u64 = br.as<uint64_t>(0, max);
// relative
// after last
const uint64_t *p = & u64[max - 1];
assert(br.as<uint64_t>(p + 1) == nullptr );
}
// zero size
assert(br.as<char>(0x00, 0) == nullptr );
// nullptr
assert(br.as<char>(nullptr) == nullptr );
return 0;
}
int main(){
test_blobref();
}
static_cast
so I think it's likely you do not understand these casts properly. \$\endgroup\$ – cloakedlearning Sep 13 '16 at 8:35