/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=813
*/
#include <vector>
#include <cstdint> // uint8_t, ...
#include <cassert>
/// A reference to an array (data mapper) with a rich STL-like interface, safe & cheep to pass around.
template <typename T>
class Array_ref
{
public:
Array_ref() : _data(nullptr), _size(0) {}
Array_ref(const T &value) : _data(&value), _size(1) {}
Array_ref(const T *begin, const T *end) : _data(begin), _size(end - begin) { assert(begin <= end); }
Array_ref(const T *data, size_t size) : _data(data), _size(size) {}
Array_ref(const std::vector<T> &vec) : _data(vec.empty() ? nullptr : &vec.front()), _size(vec.size()) {}
bool empty() const { return _size == 0; }
const T * begin() const { return _data; }
const T * end() const { return _data + _size; }
size_t size() const { return _size; }
const T * data() const { return _data; }
const T & front() const { assert(!empty()); return _data[0]; }
const T & back() const { assert(!empty()); return _data[_size - 1]; }
const T & operator [] (size_t index) const { assert(index < _size); return _data[index]; }
//... other convenient stuff
private:
const T *_data;
size_t _size;
};
/// A helper that conveniently translates a raw array to the Array_ref.
template <typename T, size_t N>
Array_ref<T> make_array_ref(const T (&array)[N]) // a reference to array is used here, to preserve N
{
return Array_ref<T>(&array[0], &array[N]);
}
//--- DEMO ---
struct Color { uint8_t r, g, b; };
typedef Array_ref<Color> Color_array_ref;
/// A traditional way to refer data, but it's unsafe and requires 2 params to manage.
void pass_color_data_ugly1(const Color *data, size_t size)
{
printf("pass_color_data_ugly1():\n");
for(size_t i = 0; i < size; ++i)
{
const Color &c = data[i];
printf("%02x %02x %02x\n", c.r, c.g, c.b);
}
}
/// A traditional way to refer data, but it's unsafe and requires 2 params to manage.
void pass_color_data_ugly2(const Color *begin, const Color *end)
{
printf("pass_color_data_ugly2():\n");
for(const Color *c = begin; c < end; ++c)
{
printf("%02x %02x %02x\n", c->r, c->g, c->b);
}
}
/// A safe C++ish way to refer data, but it requires an unnecessary initial copy :(
void pass_color_data_ugly3(const std::vector<Color> &data)
{
printf("pass_color_data_ugly3():\n");
for(std::vector<Color>::const_iterator c = data.begin(), end = data.end(); c < end; ++c)
{
printf("%02x %02x %02x\n", c->r, c->g, c->b);
}
}
/// A safe way to refer data, no initial copy needed, it's just a mapping!
void pass_color_data_cool(Color_array_ref color_arr)
{
printf("pass_color_data_cool():\n");
for(size_t i = 0; i < color_arr.size(); ++i)
{
const Color &c = color_arr[i];
printf("%02x %02x %02x\n", c.r, c.g, c.b);
}
}
int main()
{
// This represents raw data. It might be a raw array like this or just
// a bunch of bytes, somewhere it the middle of a BLOB.
const Color data[] = {
{ 0xff, 0x00, 0x00 }, { 0x00, 0xff, 0x00 },
{ 0x00, 0x00, 0xff }, { 0x00, 0x00, 0x00 }
};
pass_color_data_ugly1(&data[0], sizeof(data) / sizeof(data[0]));
pass_color_data_ugly2(&data[0], &data[sizeof(data) / sizeof(data[0])]);
pass_color_data_ugly3(std::vector<Color>(&data[0], &data[sizeof(data) / sizeof(data[0])]));
pass_color_data_cool(make_array_ref(data)); // Pure beauty, isn't it?
return 0;
}
// output:
// pass_color_data_ugly1():
// ff 00 00
// 00 ff 00
// 00 00 ff
// 00 00 00
// pass_color_data_ugly2():
// ff 00 00
// 00 ff 00
// 00 00 ff
// 00 00 00
// pass_color_data_ugly3():
// ff 00 00
// 00 ff 00
// 00 00 ff
// 00 00 00
// pass_color_data_cool():
// ff 00 00
// 00 ff 00
// 00 00 ff
// 00 00 00