Skip to content

Instantly share code, notes, and snippets.

@berkus
Created November 14, 2014 12:58
Show Gist options
  • Save berkus/cc1e3e9af20e1d99f221 to your computer and use it in GitHub Desktop.
Save berkus/cc1e3e9af20e1d99f221 to your computer and use it in GitHub Desktop.
// * a variable sized field, where size is controlled by external bitfield with certain mapping
// - where this bitfield is
// - offset of bits
// - mask of bits
// - mapping function (bits to type)
#include <array>
#include <iostream>
#include <boost/asio/buffer.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/size.hpp>
#include <boost/fusion/include/value_at.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/define_struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/range/has_range_iterator.hpp>
#define BOOST_TEST_MODULE Test_opaque_endians
#include <boost/test/unit_test.hpp>
using namespace std;
namespace asio = boost::asio;
namespace mpl = boost::mpl;
namespace fusion = boost::fusion;
// input data stream
// flag field at start: 0 = next uint16_t, 1 = next uint32_t (bit0)
std::array<uint8_t,5> buffer = {{ 0x00, 0xab, 0xcd, 0xef, 0x12 }};
struct reader
{
mutable asio::const_buffer buf_;
explicit reader(asio::const_buffer b) : buf_(std::move(b)) {}
template <class T>
auto operator()(T& val) const -> typename std::enable_if<std::is_integral<T>::value>::type
{
val = *asio::buffer_cast<T const*>(buf_);
buf_ = buf_ + sizeof(T);
}
};
// - mapping function (bits to type)
// based on the value of some field we must choose N-th value in this struct and read it
// index 0 - bits value 0, index 1 - bits value 1 and so on
// use a sentinel type nothing_t to read nothing.
BOOST_FUSION_DEFINE_STRUCT(
(mapping), twobits,
(uint16_t, value1)
(uint32_t, value2)
);
template <class T>
using range_c = typename mpl::range_c<int, 0, mpl::size<T>::value>;
template <typename T>
struct read_field_visitor
{
T& output_;
reader& read_;
uint8_t value_;
read_field_visitor(T& out, reader& r, uint8_t val) : output_(out), read_(r), value_(val) {}
template <class N>
void operator()(N idx)
{
if (N::value == value_) {
read_(fusion::at<N>(output_));
}
}
};
struct read_fields
{
template <typename T>
void operator()(T& out, reader& r, uint8_t value)
{
mpl::for_each<range_c<T>>(read_field_visitor<T>(out, r, value));
}
};
BOOST_AUTO_TEST_CASE(basic_reader)
{
asio::const_buffer buf(buffer.data(), buffer.size());
reader r(std::move(buf));
read_fields rf;
uint8_t flags;
mapping::twobits stru;
r(flags);
rf(stru, r, flags);
BOOST_CHECK(flags == 0);
BOOST_CHECK(stru.value1 == 0xcdab);
cout << (int)flags << " / " << stru.value1 << endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment