Specialize ByteConverter template to support read/write of custom type with ByteVector/ByteView

dependabot/npm_and_yarn/Src/WebController/UI/websocket-extensions-0.1.4
Pawel Kurowski 2019-09-19 11:24:44 +02:00
parent a44f9ba632
commit 5201a2391d
2 changed files with 94 additions and 0 deletions

View File

@ -8,6 +8,52 @@ namespace MWR
class ByteView;
class ByteVector;
/// Empty template of class that can convert data from and to byte form.
/// @tparam T. Custom type that will work with byte containers using this converter type.
/// Specialize this class to add methods:
/// static ByteVector To(T const&);
/// Used to write data.
/// static T From(ByteView&);
/// Used to retrieve data.
/// Function must move ByteView& argument to position after the data that was retrieved.
/// static size_t Size(T const&);
/// Used to calculate size that type will need to be stored in ByteVector.
/// This function is not mandatory. If not provided function `To` will be called twice.
/// Once to calculate size for ByteVector allocation, and a second time to copy data.
template <typename T>
struct ByteConverter {};
/// Example code of specializing ByteConverter for custom type A.
//struct A
//{
// uint16_t m_a, m_b;
// A(uint16_t a, uint16_t b) : m_a(a), m_b(b) {}
//};
//namespace MWR
//{
// template <>
// struct ByteConverter<A>
// {
// static ByteVector To(A const& a)
// {
// return ByteVector::Create(a.m_a, a.m_b);
// }
// static size_t Size(A const& a)
// {
// return 2 * sizeof(uint16_t);
// }
// static A From(ByteView& bv)
// {
// auto [a, b] = bv.Read<uint16_t, uint16_t>();
// return A(a, b);
// }
// };
//}
/// Idiom for detecting tuple types.
template <typename T>
constexpr bool IsTuple = false;
@ -25,6 +71,17 @@ namespace MWR
template<class...Ts>
using CanStoreType = MWR::Utils::CanApply<StoreReturnType, ByteVector, Ts...>;
/// Check if MWR namespace has function to get size of type T when it is stored to ByteVector.
template <typename T>
class GotByteSize
{
template <typename C> static uint8_t test(decltype(MWR::ByteConverter<T>::Size(std::declval<T>())));
template <typename C> static uint16_t test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(uint8_t) };
};
/// An owning container.
class ByteVector : std::vector<std::uint8_t>
{
@ -217,6 +274,16 @@ namespace MWR
return *this;
}
/// Store custom type.
/// tparam T. Type to be stored. There must exsist MWR::ToBytes(T const&) method avalible to store custom type.
/// @return itself to allow chaining.
template<typename T, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), MWR::ByteVector >, int> = 0>
ByteVector & Store(bool unused, T const& arg)
{
Concat(MWR::ByteConverter<T>::To(arg));
return *this;
}
/// Store all arguments at the end of ByteVector.
/// @param storeSize if true four byte header will be added to types in T that does not have size defined at compile time.
/// @tparam T. Parameter pack to be written. Types are deduced from function call.
@ -279,6 +346,24 @@ namespace MWR
return sizeof(T);
}
/// Calculate the size that the argument will take in memory
/// tparam T. Type to be stored. There must exsist MWR::ByteConverter<T>::To(T const&) function and MWR::ByteConverter<T>::Size(T const&)
/// @return size_t number of bytes needed.
template<typename T, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), ByteVector> && GotByteSize<T>::value, int> = 0>
static size_t CalculateStoreSize(bool unused, T const& arg)
{
return MWR::ByteConverter<T>::Size(arg);
}
/// Calculate the size that the argument will take in memory
/// tparam T. Type to be stored. There must exsist MWR::ByteConverter<T>::To(T const&) method avalible to store custom type.
/// @return size_t number of bytes needed.
template<typename T, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), ByteVector> && !GotByteSize<T>::value, int> = 0>
static size_t CalculateStoreSize(bool unused, T const& arg)
{
return MWR::ByteConverter<T>::To(arg).size();
}
/// Calculate the size that the arguments will take in memory. This function is responsible for unwrapping variadic arguments calls.
/// @param storeSizeHeader. If true function writes 4 bytes header with size for types that have variable buffer length.
/// @param args. arguments to be stored.

View File

@ -219,6 +219,15 @@ namespace MWR
return retVal;
}
/// Read custom type and remove it from ByteView.
/// @tparam T. Type to return;
/// @returns T.
template<typename T>
std::enable_if_t < std::is_same_v<decltype(MWR::ByteConverter<T>::From(std::declval<ByteView>())), T > , T > Read()
{
return ByteConverter<T>::From(*this);
}
/// Read tuple type.
/// @tparam T. Tuple type to return;
/// @returns T. Owning container with the read bytes.