1. 4FIPS
  2. PHOTOS
  3. VIDEOS
  4. APPS
  5. CODE
  6. FORUMS
  7. ABOUT
/*
(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