/*
(c) 2004-14 Filip Stoklas, aka FipS, www.4FipS.com
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
*/
#ifndef FS_HEADER__fs_common_type_h__GUARD
#define FS_HEADER__fs_common_type_h__GUARD
#include "fs_common.h"
#include <vector>
namespace fs {
// --- INDEX ---
template <typename T, typename G> // TYPE/TAG
class index_t // trivial, non-aggregate (C++11)
{
public:
static index_t make(size_t pos = null_pos) FS_NOEXCEPT
{ static_assert(std::is_trivial<index_t>::value, "");
index_t ret; ret.set(pos); return ret; }
bool valid() const FS_NOEXCEPT
{ return _pos != null_pos; }
void set(size_t pos) FS_NOEXCEPT
{ _pos = narrow_cast<T>(pos); }
size_t pos() const FS_NOEXCEPT
{ return _pos; }
private:
enum { null_pos = static_cast<T>(-1) };
T _pos;
};
template <typename T, typename G> // TYPE/TAG
class index final : public index_t<T, G>
{
public:
using base_type = index_t<T, G>;
index() FS_NOEXCEPT
{ base_type::set(base_type::make().pos()); }
explicit index(size_t pos) FS_NOEXCEPT
{ base_type::set(pos); }
};
// --- HANDLE ---
template <typename T, int B, typename G> // TYPE/POS-BITS/TAG
class handle_t // trivial, non-aggregate (C++11)
{
public:
static handle_t make() FS_NOEXCEPT
{ return make(0, null_magic); }
static handle_t make(size_t pos, T magic) FS_NOEXCEPT
{ static_assert(std::is_trivial<handle_t>::value, "");
handle_t ret; ret.set(pos, magic); return ret; }
bool valid() const FS_NOEXCEPT
{ return _magic != null_magic; }
void set(size_t pos, T magic) FS_NOEXCEPT
{ FS_ASSERT(pos <= pos_max && magic <= magic_max && "overflow");
_pos = narrow_cast<T>(pos); _magic = magic; }
size_t pos() const FS_NOEXCEPT
{ return _pos; }
T magic() const FS_NOEXCEPT
{ return _magic; }
T key() const FS_NOEXCEPT
{ return _key; }
private:
enum
{
pos_bits = B,
magic_bits = 8 * sizeof(T) - B,
pos_max = (1 << pos_bits) - 1,
magic_max = (1 << magic_bits) - 1,
null_magic = 0
};
union
{
struct
{
T _pos : pos_bits;
T _magic : magic_bits;
};
T _key;
};
};
template <typename T, int B, typename G> // TYPE/POS-BITS/TAG
class handle final : public handle_t<T, B, G>
{
public:
using base_type = handle_t<T, B, G>;
handle() FS_NOEXCEPT
{ base_type::set(base_type::make().pos(), base_type::make().magic()); }
explicit handle(T pos, T magic) FS_NOEXCEPT
{ base_type::set(pos, magic); }
};
// --- ARRAY ---
template <typename T>
class array_ref_t // trivial, non-aggregate (C++11)
{
public:
static array_ref_t make(const T *data, size_t size) FS_NOEXCEPT
{ static_assert(std::is_pod<array_ref_t>::value, "");
array_ref_t ret; ret.set(data, size); return ret; }
void set(const T *data, size_t size) FS_NOEXCEPT
{ _data = data; _size = size; }
const T * data() const FS_NOEXCEPT
{ return _data; }
size_t size() const FS_NOEXCEPT
{ return _size; }
bool empty() const FS_NOEXCEPT
{ return _size == 0; }
const T * begin() const FS_NOEXCEPT
{ return _data; }
const T * end() const FS_NOEXCEPT
{ return _data + _size; }
const T & front() const FS_NOEXCEPT
{ FS_ASSERT(!empty()); return _data[0]; }
const T & back() const FS_NOEXCEPT
{ FS_ASSERT(!empty()); return _data[_size - 1]; }
const T & operator [] (size_t idx) const FS_NOEXCEPT
{ FS_ASSERT(idx < _size); return _data[idx]; }
std::vector<T> to_vector() const FS_EXCEPT
{ return std::vector<T>(_data, _data + _size); }
private:
const T *_data;
size_t _size;
};
template <typename T>
class array_ref final : public array_ref_t<T>
{
public:
using base_type = array_ref_t<T>;
array_ref() FS_NOEXCEPT
{ base_type::set(nullptr, 0); }
array_ref(const T &value) FS_NOEXCEPT
{ base_type::set(&value, 1); }
array_ref(const T *begin, const T *end) FS_NOEXCEPT
{ base_type::set(begin, end - begin); }
array_ref(const T *data, size_t size) FS_NOEXCEPT
{ base_type::set(data, size); }
array_ref(array_ref_t<T> pod) FS_NOEXCEPT
{ base_type::set(pod.data(), pod.size()); }
array_ref(const std::vector<T> &vec) FS_NOEXCEPT
{ base_type::set(vec.empty() ? nullptr : &vec.front(), vec.size()); }
template <size_t N> array_ref(const T (&arr)[N]) FS_NOEXCEPT
{ base_type::set(arr, &arr[N] - &arr[0]); }
};
// --- BYTES ---
using bytes_ref_t = array_ref_t<uint8_t>;
using bytes_ref = array_ref<uint8_t>;
template <typename T>
bytes_ref raw_bytes(array_ref<T> arr) FS_NOEXCEPT
{
return bytes_ref(
reinterpret_cast<const uint8_t *>(arr.data()),
arr.size() * sizeof(T)
);
}
template <typename T, size_t N>
bytes_ref raw_bytes(T (&arr)[N]) FS_NOEXCEPT
{
return bytes_ref(
reinterpret_cast<const uint8_t *>(&arr[0]),
reinterpret_cast<const uint8_t *>(&arr[N])
);
}
template <typename T>
bytes_ref raw_bytes(const std::vector<T> &vec) FS_NOEXCEPT
{
return raw_bytes(array_ref<T>(vec));
}
} // namespace fs
#endif // FS_HEADER__fs_common_type_h__GUARD