Skip to content

Instantly share code, notes, and snippets.

@nlyan
Created May 4, 2020 11:27
Show Gist options
  • Save nlyan/6a1ba372acd7051f75aeed0a75ff1e8b to your computer and use it in GitHub Desktop.
Save nlyan/6a1ba372acd7051f75aeed0a75ff1e8b to your computer and use it in GitHub Desktop.
#include <array>
#include <boost/fusion/adapted/adt/adapt_adt.hpp>
#include <boost/preprocessor.hpp>
#include <stdexcept>
#include "faef.hpp"
#define DEFINE_INIT_LIST_PLACEHOLDER_0_END
#define DEFINE_INIT_LIST_PLACEHOLDER_1_END
#define DEFINE_INIT_LIST_PLACEHOLDER_0(X, Y, Z) \
((X, Y, Z)) DEFINE_INIT_LIST_PLACEHOLDER_1
#define DEFINE_INIT_LIST_PLACEHOLDER_1(X, Y, Z) \
((X, Y, Z)) DEFINE_INIT_LIST_PLACEHOLDER_0
#define DEFINE_INIT_LIST_STRIP_PARENS(Z, N, ARGS) \
BOOST_PP_REMOVE_PARENS (BOOST_PP_SEQ_ELEM (N, ARGS))
#define DEFINE_INIT_LIST(EXPRS) \
BOOST_PP_ENUM (BOOST_PP_SEQ_SIZE (BOOST_PP_VARIADIC_SEQ_TO_SEQ (EXPRS)), \
DEFINE_INIT_LIST_STRIP_PARENS, \
BOOST_PP_CAT (DEFINE_INIT_LIST_PLACEHOLDER_0 EXPRS, _END))
#define DEFINE_FIX_FIELD_ACCESSORS(TAG, TYPE, NAME) \
auto NAME () const { \
faef::Field field; \
if (!d_message->getField (&field, TAG)) { \
throw std::runtime_error ("Access to missing '" #NAME \
"'' field (tag " #TAG ")"); \
} \
return faef::FieldExtractor<faef::getBaseType ( \
faef::DataType::e_##TYPE)>::getValue (field); \
} \
\
template <typename T> \
auto NAME (T&&) { \
faef::Field field; \
}
#define DEFINE_FIX_FIELD_ACCESSORS_FROM_SEQ(R, ARG, FIELD) \
BOOST_PP_EXPAND (DEFINE_FIX_FIELD_ACCESSORS FIELD)
struct FieldDescriptor {
int tag;
char const* type;
char const* name;
};
#define INIT_FIELD_DESCRIPTOR(TAG, TYPE, NAME) \
(FieldDescriptor{TAG, #TYPE, #NAME})
#define INIT_FIELD_DESCRIPTOR_FROM_SEQ(R, ARG, FIELD) \
BOOST_PP_EXPAND (INIT_FIELD_DESCRIPTOR FIELD)
#define INIT_ALL_FIELD_DESCRIPTORS(FIELDS) \
DEFINE_INIT_LIST ( \
BOOST_PP_SEQ_FOR_EACH (INIT_FIELD_DESCRIPTOR_FROM_SEQ, \
_, \
BOOST_PP_VARIADIC_SEQ_TO_SEQ (FIELDS)))
#define ADAPT_FIELD(TAG, TYPE, NAME) (obj.NAME (), obj.NAME (val))
#define ADAPT_FIELDS(R, ARG, FIELD) BOOST_PP_EXPAND (ADAPT_FIELD FIELD)
#define DEFINE_FIX_MESSAGE(NAME, FIELDS) \
class NAME { \
public: \
explicit NAME (faef::Message* message) noexcept \
: d_message (message) { \
} \
\
BOOST_PP_SEQ_FOR_EACH (DEFINE_FIX_FIELD_ACCESSORS_FROM_SEQ, _, \
BOOST_PP_VARIADIC_SEQ_TO_SEQ (FIELDS)); \
\
inline static std::array< \
FieldDescriptor, BOOST_PP_SEQ_SIZE (BOOST_PP_VARIADIC_SEQ_TO_SEQ ( \
FIELDS))> const constexpr fields = { \
INIT_ALL_FIELD_DESCRIPTORS (FIELDS)}; \
\
private: \
faef::Message* d_message = 0; \
}; \
\
BOOST_FUSION_ADAPT_ADT ( \
NAME, \
BOOST_PP_SEQ_FOR_EACH ( \
ADAPT_FIELDS, _, BOOST_PP_VARIADIC_SEQ_TO_SEQ (FIELDS)));
/* clang-format off */
DEFINE_FIX_MESSAGE (
Trade,
(100, String, id)
(101, Price, price)
(102, Integer, volume)
(104, UTCTimestamp, time)
);
/* clang-format on */
#include <iostream>
#include <boost/fusion/algorithm/transformation/zip.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/functional/invocation/invoke.hpp>
#include <boost/fusion/adapted/std_array.hpp>
namespace bf = ::boost::fusion;
int
main () {
faef::Message message; // Underlying faef::Message is still exposed
Trade trade (&message); // Construction is practically free
bf::for_each (bf::zip (Trade::fields, trade), [] (auto zipped) {
bf::invoke (
[] (auto const& field, auto const& value) {
std::cout << "<" << field.name << " tag=\"" << field.tag << "\""
<< " type=\"" << field.type << "\">" << value.get ()
<< "</" << field.name << ">"
<< "\n";
},
zipped);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment