Compare commits
4 Commits
06d69fb976
...
462086b13c
| Author | SHA1 | Date | |
|---|---|---|---|
| 462086b13c | |||
| 530232ba16 | |||
| dd808b4d57 | |||
| f5a3a443af |
@@ -17,9 +17,9 @@ void SwapBytes(T& value) {
|
||||
}
|
||||
|
||||
bool IsSystemBigEndian() {
|
||||
std::uint16_t test = 0;
|
||||
reinterpret_cast<std::uint8_t*>(&test)[1] = 1;
|
||||
return test == 1;
|
||||
static constexpr std::uint16_t test = 10;
|
||||
static const bool isBigEndian = reinterpret_cast<const std::uint8_t*>(&test)[1] == 10;
|
||||
return isBigEndian;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,4 +9,45 @@ namespace sp {
|
||||
template <typename... input_t>
|
||||
using tuple_cat_t = decltype(std::tuple_cat(std::declval<input_t>()...));
|
||||
|
||||
namespace details {
|
||||
|
||||
template <std::size_t TRem>
|
||||
class TupleForEachHelper {
|
||||
public:
|
||||
template <typename TTuple, typename TFunc>
|
||||
static void Exec(TTuple&& tuple, TFunc&& func) {
|
||||
using Tuple = typename std::decay<TTuple>::type;
|
||||
static const std::size_t TupleSize = std::tuple_size<Tuple>::value;
|
||||
static_assert(TRem <= TupleSize, "Incorrect parameters");
|
||||
|
||||
// Invoke function with current element
|
||||
static const std::size_t Idx = TupleSize - TRem;
|
||||
func(std::get<Idx>(std::forward<TTuple>(tuple)));
|
||||
|
||||
// Compile time recursion - invoke function with the remaining elements
|
||||
TupleForEachHelper<TRem - 1>::Exec(std::forward<TTuple>(tuple), std::forward<TFunc>(func));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class TupleForEachHelper<0> {
|
||||
public:
|
||||
// Stop compile time recursion
|
||||
template <typename TTuple, typename TFunc>
|
||||
static void Exec(TTuple&& tuple, TFunc&& func) {
|
||||
static_cast<void>(tuple);
|
||||
static_cast<void>(func);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename TFunc, typename TTuple>
|
||||
void TupleForEach(TFunc&& func, TTuple&& tuple) {
|
||||
using Tuple = typename std::decay<TTuple>::type;
|
||||
static const std::size_t TupleSize = std::tuple_size<Tuple>::value;
|
||||
|
||||
details::TupleForEachHelper<TupleSize>::Exec(std::forward<TTuple>(tuple), std::forward<TFunc>(func));
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -5,32 +5,81 @@
|
||||
|
||||
namespace sp {
|
||||
|
||||
template <typename ValueType>
|
||||
/**
|
||||
* \brief Example usage :
|
||||
* sp::BitField<std::uint16_t, sp::Field<std::uint16_t, 12>, sp::Field<std::uint8_t, 4>>;
|
||||
*/
|
||||
template <typename TContainer, typename... TFields>
|
||||
class BitField {
|
||||
using AllFields = std::tuple<TFields...>;
|
||||
|
||||
public:
|
||||
template <typename... T>
|
||||
BitField(const std::tuple<T...>& args) {
|
||||
Apply<0, T...>(args);
|
||||
}
|
||||
|
||||
BitField() {}
|
||||
|
||||
template <typename... T>
|
||||
BitField& operator=(const std::tuple<T...>& args) {
|
||||
Apply<0, T...>(args);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AllFields& GetFields() {
|
||||
return m_Fields;
|
||||
}
|
||||
|
||||
const AllFields& GetFields() const {
|
||||
return m_Fields;
|
||||
}
|
||||
|
||||
template <std::size_t FIndex>
|
||||
auto& GetField() {
|
||||
return std::get<FIndex>(this->GetFields()).GetValue();
|
||||
}
|
||||
|
||||
private:
|
||||
template <int IOffset, typename... T, std::enable_if_t<IOffset >= sizeof...(T), bool> = true>
|
||||
void Apply(const std::tuple<T...>& args) {}
|
||||
|
||||
template <int IOffset, typename... T, std::enable_if_t<!(IOffset >= sizeof...(T)), bool> = true>
|
||||
void Apply(const std::tuple<T...>& args) {
|
||||
this->GetField<IOffset>() = std::get<IOffset>(args);
|
||||
Apply<1 + IOffset, T...>(args);
|
||||
}
|
||||
|
||||
TContainer m_Value;
|
||||
AllFields m_Fields;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* \tparam ValueType the type of the value to store
|
||||
* \tparam IAlignment 0 means no alignment
|
||||
*/
|
||||
template <typename ValueType, int IAlignment>
|
||||
class Field {
|
||||
public:
|
||||
// Provide an access to the stored value
|
||||
ValueType& GetValue() {
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
const ValueType& GetValue() const {
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
// Read (deserialise) and update internal value
|
||||
void Read(DataBuffer& buffer) {
|
||||
buffer >> m_Value;
|
||||
}
|
||||
|
||||
// Write (serialise) internal value
|
||||
void Write(DataBuffer& buffer) const {
|
||||
buffer << m_Value;
|
||||
}
|
||||
|
||||
Field& operator=(const ValueType& value) {
|
||||
m_Value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr int GetAlignment() const {
|
||||
return IAlignment;
|
||||
}
|
||||
|
||||
private:
|
||||
ValueType m_Value;
|
||||
};
|
||||
@@ -52,7 +101,7 @@ struct FieldsBuilder<std::tuple<TFields...>> {
|
||||
|
||||
template <typename TField, typename... TFields>
|
||||
struct FieldsBuilder<TField, TFields...> {
|
||||
using Type = sp::tuple_cat_t<std::tuple<Field<TField>>, typename FieldsBuilder<TFields...>::Type>;
|
||||
using Type = sp::tuple_cat_t<std::tuple<Field<TField, 0>>, typename FieldsBuilder<TFields...>::Type>;
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ class MessageImplFieldsBase : public TBase {
|
||||
AllFields& GetFields() {
|
||||
return m_Fields;
|
||||
}
|
||||
|
||||
const AllFields& GetFields() const {
|
||||
return m_Fields;
|
||||
}
|
||||
@@ -119,23 +120,75 @@ class MessageImplFieldsBase : public TBase {
|
||||
|
||||
template <typename TBase>
|
||||
class MessageImplFieldsReadBase : public TBase {
|
||||
protected:
|
||||
private:
|
||||
// normal reading
|
||||
template <typename TField>
|
||||
void ReadField(Field<TField, 0>& field, DataBuffer& buffer) {
|
||||
this->ReadData(field.GetValue(), buffer);
|
||||
}
|
||||
|
||||
// reading field in bitfield
|
||||
template <typename TFieldType, typename TField, int IAlignment>
|
||||
void ReadField(Field<TField, IAlignment>& field, TFieldType data, std::size_t offset) {
|
||||
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
|
||||
// we suppose that the first element is at the highest bits
|
||||
field.GetValue() = (data >> TotalBitCount - IAlignment - offset) & ((1 << IAlignment) - 1);
|
||||
}
|
||||
|
||||
// reading bitfield
|
||||
template <typename TContainer, typename TFirst, typename... TFields>
|
||||
void ReadField(Field<BitField<TContainer, TFirst, TFields...>, 0>& field, DataBuffer& buffer) {
|
||||
TContainer data;
|
||||
this->ReadData(data, buffer);
|
||||
std::size_t offset = 0;
|
||||
TupleForEach(
|
||||
[data, this, &offset](auto& field) {
|
||||
this->ReadField(field, data, offset);
|
||||
offset += field.GetAlignment();
|
||||
},
|
||||
field.GetValue().GetFields());
|
||||
}
|
||||
|
||||
void ReadImpl(DataBuffer& buffer) override {
|
||||
auto& allFields = this->GetFields();
|
||||
std::apply([&buffer, this](auto& field) {
|
||||
this->ReadData(field.GetValue(), buffer);
|
||||
}, allFields);
|
||||
TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TBase>
|
||||
class MessageImplFieldsWriteBase : public TBase {
|
||||
protected:
|
||||
private:
|
||||
// normal writing
|
||||
template <typename TField>
|
||||
void WriteField(Field<TField, 0>& field, DataBuffer& buffer) {
|
||||
this->WriteData(field.GetValue(), buffer);
|
||||
}
|
||||
|
||||
// writing field in bitfield
|
||||
template <typename TFieldType, typename TField, int IAlignment>
|
||||
void WriteField(Field<TField, IAlignment>& field, TFieldType& data, std::size_t offset) {
|
||||
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
|
||||
// we suppose that the first element is at the highest bits
|
||||
data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset;
|
||||
}
|
||||
|
||||
// writing bitfield
|
||||
template <typename TContainer, typename TFirst, typename... TFields>
|
||||
void WriteField(Field<BitField<TContainer, TFirst, TFields...>, 0>& field, DataBuffer& buffer) {
|
||||
TContainer data = 0;
|
||||
std::size_t offset = 0;
|
||||
TupleForEach(
|
||||
[&data, this, &offset](auto& field) {
|
||||
this->WriteField(field, data, offset);
|
||||
offset += field.GetAlignment();
|
||||
},
|
||||
field.GetValue().GetFields());
|
||||
this->WriteData(data, buffer);
|
||||
}
|
||||
|
||||
void WriteImpl(DataBuffer& buffer) override {
|
||||
auto& allFields = this->GetFields();
|
||||
std::apply([&buffer, this](auto& field) {
|
||||
this->WriteData(field.GetValue(), buffer);
|
||||
}, allFields);
|
||||
TupleForEach([&buffer, this](auto& field) { this->WriteField(field, buffer); }, allFields);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user