Created
November 14, 2014 12:58
-
-
Save berkus/cc1e3e9af20e1d99f221 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// * 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