37 #ifndef FIX8_MESSAGE_HPP_
38 #define FIX8_MESSAGE_HPP_
41 #if defined FIX8_PREENCODE_MSG_SUPPORT
56 using Groups = std::map<unsigned short, GroupBase *>;
69 GroupBase(
const unsigned short fnum) : _fnum(fnum) {}
99 size_t size()
const {
return _msgs.size(); }
113 void clear(
bool reuse=
true);
159 template<
typename T,
typename R>
162 #if defined FIX8_HAVE_EXTENDED_METADATA
166 template<
typename T,
typename R =
void>
167 static const TraitHelper& _make_traits()
169 static const TraitHelper _helper { T::get_traits(), T::get_fieldcnt() };
176 std::function<Message *(bool)>
_do;
177 #if defined FIX8_HAVE_EXTENDED_METADATA
178 const TraitHelper& (&_get_traits)();
183 template<
typename T,
typename... args>
185 #if defined FIX8_HAVE_EXTENDED_METADATA
186 , _get_traits(
_gen::_make_traits<T, args...>)
204 using ReverseMsgTable = std::map<const char * const, const BaseMsgEntry *, c_str_compare>;
234 static bool _comp(
const char *p1,
const char *p2) { return ::strcmp(p1, p2) < 0; }
243 : _version(version), _bme(bme), _be(be), _cn(cn),
244 _flu_sz(_be.at(_be.size() - 1)->_key + 1), _flu(new const
BaseEntry *[_flu_sz]),
245 _mk_hdr(_bme.find_ref(
"header")._create._do), _mk_trl(_bme.find_ref(
"trailer")._create._do),
246 _beginStr(bg), _preamble_sz(2 + _beginStr.size() + 1 + 3),
247 _reverse_msgtable(
_comp), _reverse_fieldtable(
_comp)
250 throw f8Exception(
"F8MetaCntx initialisation incomplete");
251 std::fill(_flu, _flu + _flu_sz,
nullptr);
252 for (
unsigned offset(0); offset < _be.
size(); ++offset)
256 { _reverse_fieldtable.emplace(std::make_pair(pp.second()._name, &pp.second())); });
258 { _reverse_msgtable.emplace(std::make_pair(pp.second()._name, &pp.second())); });
268 {
return fnum < _flu_sz ? _flu[fnum] :
nullptr; }
275 if (fieldstr && *fieldstr)
277 auto itr(_reverse_fieldtable.find(fieldstr));
278 return itr != _reverse_fieldtable.cend() ? itr->second :
nullptr;
288 if (fieldstr && *fieldstr)
290 auto itr(_reverse_fieldtable.find(fieldstr));
291 return itr != _reverse_fieldtable.cend() ? itr->second->_fnum : 0;
326 auto itr(_reverse_msgtable.find(msgstr));
327 return itr != _reverse_msgtable.cend() ? itr->second :
nullptr;
337 return bme ? bme->
_create.
_do(deepctor) :
nullptr;
347 return bme ? bme->
_create.
_do(deepctor) :
nullptr;
358 #if defined FIX8_HAVE_EXTENDED_METADATA
363 using const_internal_result = std::pair<const_iterator, const_iterator>;
364 static const_iterator find(
unsigned short fnum,
const TraitHelper& from)
366 const const_internal_result res(std::equal_range (from._traits, from._traits + from._fieldcnt,
368 return res.first != res.second ? res.first :
nullptr;
371 static const_iterator begin(
const TraitHelper& from) {
return from._traits; }
372 static const_iterator end(
const TraitHelper& from) {
return from._traits + from._fieldcnt; }
377 using Fields = std::map <unsigned short, BaseField *>;
378 using Positions = std::multimap<unsigned short, BaseField *>;
418 template<
typename InputIterator>
421 _msgType(msgType), _ctx(ctx) {}
435 std::for_each(_fields.begin(), _fields.end(), [](Fields::value_type& pp) {
delete pp.second; pp.second =
nullptr; });
436 std::for_each(_groups.begin(), _groups.end(), [](Groups::value_type& pp) {
delete pp.second; pp.second =
nullptr; });
459 F8API unsigned decode(
const f8String& from,
unsigned offset,
unsigned ignore=0,
bool permissive_mode=
false);
469 unsigned s_offset,
unsigned ignore);
520 if (_unknown.size() && to)
531 if (tbe && tbe->_rlm)
532 where->
_rlm = tbe->_rlm;
546 _fields.insert({fnum, what});
547 _pos.insert({pos, what});
560 glout_debug << _msgType <<
" replacing field:" << fnum;
561 delete replace(fnum, itr, what);
565 _fields.insert({fnum, what});
566 _pos.insert({pos, what});
576 void add_field(
const unsigned short fnum, Fields::iterator fitr,
const unsigned pos,
BaseField *what,
bool check=
true)
581 glout_debug << _msgType <<
" replacing field:" << fnum;
582 delete replace(fnum, itr, what);
586 _fields.insert(fitr, {fnum, what});
587 _pos.insert({pos, what});
601 glout_debug << _msgType <<
" replacing field:" << fnum;
602 delete replace(fnum, itr, what);
606 _fields.insert({fnum, what});
607 _pos.insert({pos, what});
624 if (_fp.
has(T::get_field_id(), itr))
626 add_field(T::get_field_id(), itr, _fp.
getPos(T::get_field_id(), itr), what,
true);
639 const unsigned short& fnum(what->
_fnum);
641 if (_fp.
has(fnum, itr))
671 bool get(T& to)
const
673 Fields::const_iterator fitr(_fields.find(T::get_field_id()));
674 if (fitr == _fields.end())
676 to.set(fitr->second->from<T>().get());
677 if (fitr->second->_rlm)
678 to._rlm = fitr->second->_rlm;
686 bool has()
const {
return _fp.
get(T::get_field_id()); }
691 bool is_legal(
unsigned short fnum)
const {
return _fp.
has(fnum); }
705 Fields::const_iterator fitr(_fields.find(T::get_field_id()));
706 return fitr == _fields.cend() ?
nullptr : &fitr->second->from<T>();
730 Fields::const_iterator
find_field(
const unsigned short fnum)
const {
return _fields.find(fnum); }
737 auto itr(_fields.find(fnum));
738 return itr != _fields.cend() ? itr->second :
nullptr;
747 return itr != _fields.cend() ? itr->second :
nullptr;
752 Fields::const_iterator
fields_begin()
const {
return _fields.begin(); }
756 Fields::const_iterator
fields_end()
const {
return _fields.end(); }
799 auto gitr(_groups.find(fnum));
800 return gitr != _groups.cend() ? gitr->second :
nullptr;
816 auto gitr(_groups.find(fnum));
817 if (gitr != _groups.end())
828 void append_group(T *what) { _groups.insert(_groups.end(), {T::_fnum, what}); }
846 unsigned short getPos(
const unsigned short field)
const {
return _fp.
getPos(field); }
857 template<
typename InputIterator>
858 void add_trait(
const InputIterator begin,
const size_t cnt) { _fp.
add(begin, cnt); }
863 F8API virtual void print(std::ostream& os,
int depth=0)
const;
868 F8API virtual void print_field(
const unsigned short fnum, std::ostream& os)
const;
874 F8API virtual void print_group(
const unsigned short fnum, std::ostream& os,
int depth=0)
const;
886 static unsigned extract_element(
const char *from,
const unsigned sz,
char *tag,
char *val)
888 enum { get_tag,
get_value } state(get_tag);
890 for (
unsigned ii(0); ii < sz; ++ii)
895 if (!isdigit(from[ii]))
898 return *val = *tag = 0;
914 return *val = *tag = 0;
927 for (
unsigned ii(0); ii < sz; ++ii)
929 if(isdigit(from[ii]))
938 ::memcpy(val, &from[ii], val_sz);
940 return ii + val_sz + 1;
942 return *val = *tag = 0;
953 enum { get_tag,
get_value } state(get_tag);
957 for (
unsigned ii(0); ii < sz; ++ii)
962 if (!isdigit(from[ii]))
1035 #if defined FIX8_CODECTIMING
1036 struct codec_timings
1039 unsigned _msg_count;
1041 codec_timings() : _cpu_used(), _msg_count() {}
1047 #if defined FIX8_SIZEOF_UNSIGNED_LONG && FIX8_SIZEOF_UNSIGNED_LONG == 8
1049 constexpr
unsigned long COLLAPSE_INT64(
unsigned long x)
1050 {
return x + (x >> 8) + (x >> 16) + (x >> 24) + (x >> 32) + (x >> 40) + (x >> 48) + (x >> 56); }
1052 #define COLLAPSE_INT64(x) (x + (x >> 8) + (x >> 16) + (x >> 24) + (x >> 32) + (x >> 40) + (x >> 48) + (x >> 56))
1060 #if defined FIX8_CODECTIMING
1061 static codec_timings _encode_timings, _decode_timings;
1068 #if defined FIX8_RAW_MSG_SUPPORT
1070 mutable int _begin_payload = -1;
1071 mutable unsigned _payload_len = 0;
1073 #if defined FIX8_PREENCODE_MSG_SUPPORT
1074 mutable std::array<char, FIX8_MAX_MSG_LENGTH> _preencode;
1075 mutable size_t _preencode_len = 0;
1086 template<
typename InputIterator>
1089 :
MessageBase(ctx, msgType, begin, cnt, ftha),_header(ctx._mk_hdr(true)),
1090 _trailer(ctx._mk_trl(true)), _custom_seqnum(), _no_increment(), _end_of_batch(true)
1118 unsigned decode(
const f8String& from,
unsigned offset=0,
unsigned ignore=0,
bool permissive_mode=
false)
1120 const unsigned hlen(_header->
decode(from, offset, 0, permissive_mode));
1122 #if defined FIX8_RAW_MSG_SUPPORT
1123 _begin_payload = hlen;
1124 _payload_len = blen;
1127 return _trailer->
decode(from, blen, ignore, permissive_mode);
1158 _header->
clear(reuse);
1160 _trailer->
clear(reuse);
1170 static unsigned calc_chksum(
const char *from,
const size_t sz,
const unsigned offset=0,
const int len=-1)
1172 #if defined FIX8_SIZEOF_UNSIGNED_LONG && FIX8_SIZEOF_UNSIGNED_LONG == 8
1189 const unsigned long OVERFLOW_MASK (1UL << 8 | 1UL << 16 | 1UL << 24 | 1UL << 32 | 1UL << 40 | 1UL << 48 | 1UL << 56);
1190 unsigned long ret{}, overflow{};
1192 const unsigned long elen (len != -1 ? len : sz);
1194 for (; ii < (elen - elen % 8); ii += 8)
1196 unsigned long expected_overflow((ret & OVERFLOW_MASK) ^ (OVERFLOW_MASK & *reinterpret_cast<const unsigned long*>(from + ii)));
1197 ret += *
reinterpret_cast<const unsigned long*
>(from + ii);
1198 overflow += (expected_overflow ^ ret) & OVERFLOW_MASK;
1200 ret = COLLAPSE_INT64(ret);
1201 overflow = COLLAPSE_INT64(overflow);
1202 for (; ii < elen; ret += from[ii++]);
1203 return (ret - overflow) & 0xff;
1207 const char *eptr(from + (len != -1 ? len + offset : sz - offset));
1208 for (
const char *ptr(from + offset); ptr < eptr; val += *ptr++);
1219 {
return calc_chksum(from.c_str(), from.size(), offset, len); }
1226 char buf[4] {
'0',
'0',
'0', 0 };
1227 itoa<unsigned>(val, buf + (val > 99 ? 0 : val > 9 ? 1 : 2), 10);
1241 return factory(ctx, to, no_chksum, permissive_mode);
1306 auto itr (
_fields.find(fnum));
1307 return itr !=
_fields.end() ? itr->second
1308 : (itr = _header->
_fields.find(fnum)) != _header->
_fields.end() ? itr->second
1309 : (itr = _trailer->
_fields.find(fnum)) != _trailer->
_fields.end() ? itr->second :
nullptr;
1320 #if defined FIX8_RAW_MSG_SUPPORT
1323 const f8String& get_rawmsg()
const {
return _rawmsg; }
1327 f8String::const_iterator begin_payload()
const {
return f8String::const_iterator(_rawmsg.data() + _begin_payload); }
1331 f8String::const_iterator end_payload()
const {
return f8String::const_iterator(_rawmsg.data() + _begin_payload + _payload_len); }
1335 unsigned get_payload_len()
const {
return _payload_len; }
1339 unsigned get_payload_begin()
const {
return _begin_payload; }
1341 #if defined FIX8_PREENCODE_MSG_SUPPORT
1344 const char *get_preencode_msg()
const {
return _preencode_len ? _preencode.data() :
nullptr; }
1348 size_t get_preencode_len()
const {
return _preencode_len; }
1358 F8API virtual void print(std::ostream& os,
int depth=0)
const;
1366 #if defined FIX8_CODECTIMING
1367 F8API static void format_codec_timings(
const f8String& md, std::ostream& ostr, codec_timings& tobj);
1368 F8API static void report_codec_timings(
const f8String& tag);
1375 for (
const auto *pp : what.
_msgs)
1382 #endif // FIX8_MESSAGE_HPP_
F8API unsigned move_legal(MessageBase *to, bool force=false)
bool have(const unsigned short fnum) const
void add_trait(const InputIterator begin, const size_t cnt)
F8API unsigned decode(const f8String &from, unsigned offset, unsigned ignore=0, bool permissive_mode=false)
MessageBase & operator<<(GroupBase *what)
void add(MessageBase *what)
const unsigned short Common_CheckSum(10)
BaseField *(&) _do(const char *from, const RealmBase *db, const int)
static unsigned extract_trailer(const f8String &from, f8String &chksum)
void operator+=(GroupBase *what)
Binary comparitor functor.
virtual void clear(bool reuse=true)
void push_unknown(MessageBase *to) const
virtual body_length * get_body_length()
F8API MessageBase & operator=(const MessageBase &that)
Assignment operator.
BaseField * get_field_flattened(const unsigned short fnum) const
F8API BaseField * remove(const unsigned short fnum, Presence::const_iterator itr)
const_iterator begin() const
virtual F8API void print_field(const unsigned short fnum, std::ostream &os) const
Base class for inbound message routing.
Message instantiation table entry.
Pair abstraction for use with GeneratedTable.
unsigned decode(const f8String &from, unsigned offset=0, unsigned ignore=0, bool permissive_mode=false)
GroupBase * find_group() const
unsigned short getPos(const unsigned short field, Presence::const_iterator &itr) const
virtual bool operator()(const Message *msg)
virtual F8API void print(std::ostream &os, int depth=0) const
void add_field_decoder(const unsigned short fnum, const unsigned pos, BaseField *what)
friend std::ostream & operator<<(std::ostream &os, const MessageBase &what)
static Message * _make(bool deepctor)
bool has(const unsigned short field, Presence::const_iterator &itr) const
static f8String fmt_chksum(const unsigned val)
F8API size_t encode(f8String &to) const
static unsigned calc_chksum(const char *from, const size_t sz, const unsigned offset=0, const int len=-1)
virtual void set_custom_seqnum(unsigned seqnum)
F8API unsigned copy_legal(MessageBase *to, bool force=false) const
static Message * _make(bool deepctor)
unsigned decode_group(GroupBase *grpbase, const unsigned short fnum, const f8String &from, unsigned s_offset, unsigned ignore)
std::vector< MessageBase * > GroupElement
std::function< Message *(bool)> _do
BaseField * get_field_by_name(const char *tag) const
virtual begin_string * get_begin_string()
virtual bool is_admin() const
const Presence & get_presence() const
virtual bool operator()(const Message *msg) const
std::ostream & operator<<(std::ostream &os, const GroupBase &what)
std::function< bool(const char *, const char *)> c_str_compare
Field and Message metadata structures.
void push_unknown(Message *to) const
virtual GroupBase * create_nested_group(unsigned short fnum) const
F8API unsigned check_positions()
virtual F8API void print_group(const unsigned short fnum, std::ostream &os, int depth=0) const
virtual check_sum * get_check_sum()
Abstract base class for all repeating groups.
MessageBase(const struct F8MetaCntx &ctx, const f8String &msgType, const InputIterator begin, const size_t cnt, const FieldTrait_Hash_Array *ftha)
bool operator()(T &to) const
virtual ~MessageBase()
Dtor.
static unsigned extract_header(const f8String &from, char *len, char *mtype)
virtual MessageBase * create_group(bool deepctor=true) const =0
Used for static trait interrogation.
static bool has_group_count(const BaseField *bf)
Fields::const_iterator find_field(const unsigned short fnum) const
void add_field(const unsigned short fnum, Fields::iterator fitr, const unsigned pos, BaseField *what, bool check=true)
const F8MetaCntx & ctx()
Compiler generated metadata object, accessed through this function.
MessageBase * Trailer() const
const f8String & get_msgtype() const
void set(const unsigned short field, FieldTrait::TraitTypes type=FieldTrait::present)
void clear_flag(FieldTrait::TraitTypes type=FieldTrait::present)
std::map< unsigned short, GroupBase * > Groups
MessageBase * Header() const
F8API Message * clone() const
bool get_end_of_batch() const
Type2Type idiom. Variadic template version. Kudos to Andrei Alexandrescu.
unsigned short _fnum
field number
void clear_positions()
empty the positions map
static unsigned extract_element(const char *from, const unsigned sz, f8String &tag, f8String &val)
static unsigned extract_element(const char *from, const unsigned sz, char *tag, char *val)
BaseField * get_field(const unsigned short fnum) const
virtual GroupBase * create_nested_group(unsigned short fnum) const
const T * operator()() const
void clear(bool reuse=true)
GroupBase * find_add_group(const unsigned short fnum, GroupBase *grpbase=nullptr)
F8API BaseField * replace(const unsigned short fnum, Presence::const_iterator itr, BaseField *with)
virtual bool process(Router &rt) const
F8API size_t encode_group(const unsigned short fnum, std::ostream &to) const
MessageBase * get_element(const unsigned idx) const
Structures for framework generated message creation and static trait interrogation.
Minst(Type2Type< T, args...>)
virtual void clear(bool reuse=true)
const unsigned short Common_MsgSeqNum(34)
const unsigned char default_assignment_separator('=')
default FIX assignment separator (=)
const unsigned short Common_BodyLength(9)
void set_end_of_batch(bool is_end_of_batch)
void add_field(const unsigned short fnum, const unsigned pos, BaseField *what, bool check=true)
A complete Fix message with header, body and trailer.
static Message * factory(const F8MetaCntx &ctx, const char *from, bool no_chksum=false, bool permissive_mode=false)
bool get(const unsigned short field, FieldTrait::TraitTypes type=FieldTrait::present) const
std::multimap< unsigned short, BaseField * > Positions
T get_value(const std::string &source)
virtual bool get_no_increment() const
Fields::const_iterator fields_end() const
static unsigned calc_chksum(const f8String &from, const unsigned offset=0, const int len=-1)
MessageBase & operator<<(T *what)
static void set_tabsize(unsigned tabsize)
BaseField * get_field_by_name_flattened(const char *tag) const
Field template. There will ONLY be partial template specialisations of this template.
virtual msg_type * get_msg_type()
void operator+=(MessageBase *what)
void check_set_rlm(BaseField *where) const
GroupBase(const unsigned short fnum)
An invalid field was requested or added.
GroupBase * find_group(const unsigned short fnum) const
const f8String & get_unknown() const
const unsigned short _fnum
GroupBase * find_add_group(GroupBase *grpbase=nullptr)
std::map< const char *const, const BaseMsgEntry *, c_str_compare > ReverseMsgTable
const unsigned char default_field_separator(0x1)
default FIX field separator (^A)
const unsigned short Common_BeginString(8)
const FieldTraits & get_fp() const
unsigned get_custom_seqnum() const
void add_field(const unsigned short fnum, Presence::const_iterator itr, const unsigned pos, BaseField *what, bool check)
void print_fp(std::ostream &os)
The base field class (ABC) for all fields.
bool add(const FieldTrait &what)
friend std::ostream & operator<<(std::ostream &os, const Message &what)
static F8API unsigned _tabsize
A collection of FieldTraits for a message. Which fields are required, which are present.
GroupBase & operator<<(MessageBase *what)
void add_group(GroupBase *what)
virtual F8API void print(std::ostream &os, int depth=0) const
F8API size_t encode(std::ostream &to) const
const_iterator at(const size_t idx) const
const f8String & _msgType
std::map< unsigned short, BaseField * > Fields
std::function< Message *(bool)> msg_create
static unsigned get_tabsize()
bool is_legal(unsigned short fnum) const
GroupElement _msgs
vector of repeating messagebase groups
Message(const F8MetaCntx &ctx, const f8String &msgType, const InputIterator begin, const size_t cnt, const FieldTrait_Hash_Array *ftha)
Base class for all fix messages.
unsigned short getPos(const unsigned short field) const
const Val * find_ptr(const Key &key) const
f8String _unknown
pass through for permissive mode
Fields::const_iterator fields_begin() const
Fast map for statically generated data types. Assumes table is sorted. Complexity is O(logN)...
const_iterator end() const
bool add_field(BaseField *what)
void set(const unsigned short field, Presence::const_iterator &itr, FieldTrait::TraitTypes type)
static unsigned extract_element_fixed_width(const char *from, const unsigned sz, const unsigned val_sz, char *tag, char *val)
virtual void set_no_increment(bool flag=true)
std::map< const char *const, const BaseEntry *, c_str_compare > ReverseFieldTable
bool add_trait(const FieldTrait &what)
void append_group(T *what)
Fast index lookup for FieldTrait.
MessageBase * operator[](const unsigned idx) const