Compare commits
4 Commits
06d69fb976
...
462086b13c
| Author | SHA1 | Date | |
|---|---|---|---|
| 462086b13c | |||
| 530232ba16 | |||
| dd808b4d57 | |||
| f5a3a443af |
@@ -17,9 +17,9 @@ void SwapBytes(T& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsSystemBigEndian() {
|
bool IsSystemBigEndian() {
|
||||||
std::uint16_t test = 0;
|
static constexpr std::uint16_t test = 10;
|
||||||
reinterpret_cast<std::uint8_t*>(&test)[1] = 1;
|
static const bool isBigEndian = reinterpret_cast<const std::uint8_t*>(&test)[1] == 10;
|
||||||
return test == 1;
|
return isBigEndian;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,4 +9,45 @@ namespace sp {
|
|||||||
template <typename... input_t>
|
template <typename... input_t>
|
||||||
using tuple_cat_t = decltype(std::tuple_cat(std::declval<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
|
} // namespace sp
|
||||||
|
|||||||
@@ -5,32 +5,81 @@
|
|||||||
|
|
||||||
namespace sp {
|
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 {
|
class Field {
|
||||||
public:
|
public:
|
||||||
// Provide an access to the stored value
|
// Provide an access to the stored value
|
||||||
ValueType& GetValue() {
|
ValueType& GetValue() {
|
||||||
return m_Value;
|
return m_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ValueType& GetValue() const {
|
const ValueType& GetValue() const {
|
||||||
return m_Value;
|
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) {
|
Field& operator=(const ValueType& value) {
|
||||||
m_Value = value;
|
m_Value = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr int GetAlignment() const {
|
||||||
|
return IAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ValueType m_Value;
|
ValueType m_Value;
|
||||||
};
|
};
|
||||||
@@ -52,7 +101,7 @@ struct FieldsBuilder<std::tuple<TFields...>> {
|
|||||||
|
|
||||||
template <typename TField, typename... TFields>
|
template <typename TField, typename... TFields>
|
||||||
struct FieldsBuilder<TField, 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
|
} // namespace details
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ class MessageImplFieldsBase : public TBase {
|
|||||||
AllFields& GetFields() {
|
AllFields& GetFields() {
|
||||||
return m_Fields;
|
return m_Fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AllFields& GetFields() const {
|
const AllFields& GetFields() const {
|
||||||
return m_Fields;
|
return m_Fields;
|
||||||
}
|
}
|
||||||
@@ -119,23 +120,75 @@ class MessageImplFieldsBase : public TBase {
|
|||||||
|
|
||||||
template <typename TBase>
|
template <typename TBase>
|
||||||
class MessageImplFieldsReadBase : public 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 {
|
void ReadImpl(DataBuffer& buffer) override {
|
||||||
auto& allFields = this->GetFields();
|
auto& allFields = this->GetFields();
|
||||||
std::apply([&buffer, this](auto& field) {
|
TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields);
|
||||||
this->ReadData(field.GetValue(), buffer);
|
|
||||||
}, allFields);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TBase>
|
template <typename TBase>
|
||||||
class MessageImplFieldsWriteBase : public 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 {
|
void WriteImpl(DataBuffer& buffer) override {
|
||||||
auto& allFields = this->GetFields();
|
auto& allFields = this->GetFields();
|
||||||
std::apply([&buffer, this](auto& field) {
|
TupleForEach([&buffer, this](auto& field) { this->WriteField(field, buffer); }, allFields);
|
||||||
this->WriteData(field.GetValue(), buffer);
|
|
||||||
}, allFields);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user