#ifndef TOS__UTILS__STRUCT_HPP__
#define TOS__UTILS__STRUCT_HPP__
#include <limits>
#include <type_traits>
#include "utils/conv.hpp"
template <typename T>
struct NetOrder
{
static_assert(std::is_integral<T>::value,
"NetOrder accepts only integral types!");
constexpr NetOrder() = default;
explicit constexpr NetOrder(T value) : BE(value)
{
}
friend constexpr bool operator==(NetOrder lhs, NetOrder rhs)
{
return (lhs.BE == rhs.BE);
}
T BE;
};
template <typename T>
constexpr NetOrder<T>
netOrder(T value)
{
return NetOrder<T>(value);
}
template <typename T>
constexpr NetOrder<T>
toNetOrder(T value)
{
return NetOrder<T>(hton(value));
}
template <std::size_t O, std::size_t N, typename T>
class NetField
{
static_assert(std::is_integral<T>::value,
"NetField accepts only integral types!");
static_assert(!std::is_signed<T>::value,
"NetField accepts only unsigned types!");
static_assert(N <= sizeof(T),
"NetField width can't be bigger than size of the type!");
static_assert(N > 0U,
"NetField can't handle field of zero width!");
public:
static constexpr std::size_t offset = O;
static constexpr std::size_t size = N;
public:
explicit NetField(std::uint8_t data[]) : ptr(data + O), cached({})
{
for (std::size_t i = N; i != 0U; --i) {
cached.BE = (cached.BE << 8) | ptr[i - 1U];
}
}
// Fields aren't supposed to be copied or assigned in any way.
NetField(NetField &&rhs) = delete;
NetField & operator=(NetField &&rhs) = delete;
public:
NetField & operator=(NetOrder<T> value)
{
cached = value;
for (std::size_t i = 0; i < N; ++i) {
ptr[i] = value.BE & 0xff;
value.BE >>= 8;
}
return *this;
}
operator NetOrder<T>() const
{
return cached;
}
const T &BE = cached.BE;
private:
std::uint8_t *ptr;
NetOrder<T> cached;
};
template <typename T, std::size_t N = sizeof(T)>
class Field
{
static_assert(std::is_integral<T>::value,
"Field accepts only integral types!");
static_assert(!std::is_signed<T>::value,
"Field accepts only unsigned types!");
static_assert(N <= sizeof(T),
"Field width can't be bigger than size of the type!");
static_assert(N > 0U,
"Field can't handle field of zero width!");
public:
static constexpr std::size_t size = N;
public:
explicit Field(std::uint8_t *&data) : ptr(data), cached()
{
for (std::size_t i = N; i != 0U; --i) {
cached = (cached << 8) | ptr[i - 1U];
}
data += N;
}
// Fields aren't supposed to be copied or assigned in any way.
Field(Field &&rhs) = delete;
Field & operator=(Field &&rhs) = delete;
public:
Field & operator=(T value)
{
cached = value;
for (std::size_t i = 0; i < N; ++i) {
ptr[i] = value & 0xff;
value >>= 8;
}
return *this;
}
operator T() const
{
return cached;
}
private:
std::uint8_t *ptr;
T cached;
};
template <typename T, bool = std::is_integral<T>::value>
class ArrayField
{
public:
static constexpr std::size_t N = T::size();
static constexpr std::size_t size = N;
public:
explicit ArrayField(std::uint8_t *&data) : field(data)
{
}
// Fields aren't supposed to be copied or assigned in any way.
ArrayField(ArrayField &&rhs) = delete;
ArrayField & operator=(ArrayField &&rhs) = delete;
public:
operator T&()
{
return field;
}
T * operator->()
{
return &field;
}
private:
T field;
};
template <typename T>
class ArrayField<T, true>
{
static_assert(!std::is_signed<T>::value,
"ArrayField accepts only unsigned types!");
public:
static constexpr std::size_t N = sizeof(T);
static constexpr std::size_t size = N;
public:
explicit ArrayField(std::uint8_t *&data) : ptr(data), cached()
{
for (std::size_t i = N; i != 0U; --i) {
cached = (cached << 8) | ptr[i - 1U];
}
data += N;
}
// Fields aren't supposed to be copied or assigned in any way.
ArrayField(ArrayField &&rhs) = delete;
ArrayField & operator=(ArrayField &&rhs) = delete;
public:
ArrayField & operator=(T value)
{
cached = value;
for (std::size_t i = 0; i < N; ++i) {
ptr[i] = value & 0xff;
value >>= 8;
}
return *this;
}
operator T() const
{
return cached;
}
private:
std::uint8_t *ptr;
T cached;
};
template <typename T, std::size_t C>
class Fields
{
static_assert(C > 0U, "Fields can't have zero size!");
public:
static constexpr std::size_t size = C*ArrayField<T>::size();
public:
explicit Fields(std::uint8_t *&data)
{
for (std::size_t i = 0U; i < C; ++i) {
fields[i] = new(&datas[i].field) ArrayField<T>(data);
}
}
~Fields()
{
for (Data &field : datas) {
field.field.~ArrayField();
}
}
// Fields aren't supposed to be copied or assigned in any way.
Fields(Fields &&rhs) = delete;
Fields & operator=(Fields &&rhs) = delete;
public:
ArrayField<T> & operator[](std::size_t idx)
{
return *fields[idx];
}
private:
union Data {
ArrayField<T> field;
Data() {}
~Data() {}
};
Data datas[C];
ArrayField<T> *fields[C];
};
#endif // TOS__UTILS__STRUCT_HPP__
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"
Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos
Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos
You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a
pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master