root/isimud/exchanges/FIX/common/messages_impl.hpp

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. length
  2. find
  3. find
  4. type
  5. set_header
  6. set_sequence_num
  7. size
  8. search
  9. generate_checksum
  10. is_checksum_valid
  11. is_valid
  12. add_field_tag
  13. to_string
  14. finalise_msg

   1 /******************************************************************************
   2 ** $Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/isimud/exchanges/FIX/common/messages_impl.hpp 2330 2018-09-26 03:49:30Z jmmcg $
   3 **
   4 ** Copyright (c) 2015 by J.M.McGuiness, isimud@hussar.me.uk
   5 **
   6 ** This library is free software; you can redistribute it and/or
   7 ** modify it under the terms of the GNU Lesser General Public
   8 ** License as published by the Free Software Foundation; either
   9 ** version 2.1 of the License, or (at your option) any later version.
  10 **
  11 ** This library is distributed in the hope that it will be useful,
  12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 ** Lesser General Public License for more details.
  15 **
  16 ** You should have received a copy of the GNU Lesser General Public
  17 ** License along with this library; if not, write to the Free Software
  18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 */
  20 
  21 namespace isimud { namespace exchanges { namespace FIX { namespace common {
  22 
  23 template<class MsgVer> inline constexpr __stdcall
  24 Header<MsgVer>::Header() noexcept(true) {
  25         using fix_template_to_msg_type_t=underlying_fix_data_buffer::value_type[MsgVer::fix_template_msg_type_offset];
  26         jmmcg::memcpy_opt(
  27                 MsgVer::fix_template_to_msg_type,
  28                 reinterpret_cast<fix_template_to_msg_type_t &>(*begin_string)
  29         );
  30 }
  31 
  32 template<class MsgVer> inline constexpr typename Header<MsgVer>::size_type
  33 Header<MsgVer>::length() const noexcept(true) {
  34         const size_type body_size=jmmcg::fromstring<size_type>(body_length_value, sizeof(body_length_value));
  35         return msg_type_tag-begin_string+body_size+jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size+CheckSumLength+sizeof(Separator);
  36 }
  37 
  38 template<class MsgVer>
  39 template<FieldsFast field> inline
  40 constexpr field_str_range_t __fastcall
  41 Header<MsgVer>::find() noexcept(true) {
  42         using body_type=char const [max_size_of_fix_message];
  43         [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
  44         const_pointer field_ptr=this->body_length_tag;
  45         const constexpr std::size_t field_len=jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::size;
  46         field_ptr=jmmcg::strstr_opt(reinterpret_cast<body_type &>(*field_ptr), jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value);
  47         assert(field_ptr);
  48         field_ptr+=field_len;
  49         const_pointer end=field_ptr;
  50         end=jmmcg::strchr_opt<Separator>(reinterpret_cast<body_type &>(*end))+1;
  51         assert((end-field_ptr)>0);
  52         assert(static_cast<size_type>(end-field_ptr)<this->length());
  53         assert(static_cast<size_type>(field_ptr-start)<this->length());
  54         assert(static_cast<size_type>(end-start)<this->length());
  55         return field_str_range_t(field_ptr, end-1);
  56 }
  57 
  58 template<class MsgVer>
  59 template<FieldsFast field> inline
  60 constexpr field_str_range_t const __fastcall
  61 Header<MsgVer>::find() const noexcept(true) {
  62         using body_type=char const [max_size_of_fix_message];
  63         [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
  64         const_pointer field_ptr=this->body_length_tag;
  65         const constexpr std::size_t field_len=jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::size;
  66         field_ptr=jmmcg::strstr_opt(reinterpret_cast<body_type &>(*field_ptr), jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value);
  67         assert(field_ptr);
  68         field_ptr+=field_len;
  69         const_pointer end=field_ptr;
  70         end=jmmcg::strchr_opt<Separator>(reinterpret_cast<body_type &>(*end))+1;
  71         assert((end-field_ptr)>0);
  72         assert(static_cast<size_type>(end-field_ptr)<this->length());
  73         assert(static_cast<size_type>(field_ptr-start)<this->length());
  74         assert(static_cast<size_type>(end-start)<this->length());
  75         return field_str_range_t(field_ptr, end-1);
  76 }
  77 
  78 template<class MsgVer> inline MsgTypes
  79 Header<MsgVer>::type() const noexcept(true) {
  80         field_str_range_t const &type_str=find<FieldsFast::MsgType>();
  81         if ((type_str.second-type_str.first)==1) {
  82                 const auto type_int=static_cast<MsgTypes>(*type_str.first);
  83                 return static_cast<MsgTypes>(type_int);
  84         } else {
  85                 union {
  86                         char c[2];
  87                         MsgTypes_t type_int;
  88                 } conv;
  89                 conv.c[0]=type_str.first[0];
  90                 conv.c[1]=type_str.first[1];
  91                 return static_cast<MsgTypes>(conv.type_int);
  92         }
  93 }
  94 
  95 template<class MsgVer>
  96 template<MsgTypes MsgType> inline constexpr underlying_fix_data_buffer::iterator
  97 Header<MsgVer>::set_header() noexcept(true) {
  98         using JMMCG_FIX_MSG_SEQ_NUM_TAG_t=jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::element_type;
  99         pointer data=begin_string+MsgVer::fix_template_msg_type_offset;
 100         jmmcg::memcpy_opt(
 101                 jmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::value,
 102                 reinterpret_cast<typename jmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::element_type &>(*data)
 103         );
 104         data+=jmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::size;
 105         jmmcg::memcpy_opt(
 106                 jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::value,
 107                 reinterpret_cast<JMMCG_FIX_MSG_SEQ_NUM_TAG_t &>(*data)
 108         );
 109         data+=jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::size;
 110         return data;
 111 }
 112 
 113 template<class MsgVer>
 114 template<MsgTypes MsgType, class SrcMsg> inline constexpr underlying_fix_data_buffer::iterator
 115 Header<MsgVer>::set_sequence_num(SrcMsg const &msg) noexcept(true) {
 116         pointer data=set_header<MsgType>();
 117         const int i=jmmcg::tostring(
 118                 msg.sequenceNumber,
 119                 data,
 120                 data_.size()-MsgVer::fix_template_msg_type_offset-jmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::size-jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::size+1
 121         );
 122         assert(i>0);
 123         data+=i;
 124         return data;
 125 }
 126 
 127 template<class MsgVer> constexpr inline __stdcall
 128 Message<MsgVer>::Message() noexcept(true)
 129 : Header_t() {
 130 }
 131 
 132 template<class MsgVer> constexpr inline __stdcall
 133 Message<MsgVer>::Message(logon_args_t const &) noexcept(true)
 134 : Header_t() {
 135 }
 136 
 137 template<class MsgVer> constexpr inline __stdcall
 138 Message<MsgVer>::Message(logoff_args_t const &) noexcept(true)
 139 : Header_t() {
 140 }
 141 
 142 template<class MsgVer> constexpr inline __stdcall
 143 Message<MsgVer>::Message(RejectCode_t const &) noexcept(true)
 144 : Header_t() {
 145 // TODO: need to construct this!
 146 }
 147 
 148 template<class MsgVer> constexpr inline typename Message<MsgVer>::size_type __fastcall
 149 Message<MsgVer>::size() const noexcept(true) {
 150         const size_type body_size=jmmcg::fromstring<size_type>(this->body_length_value);
 151         assert(body_size<this->length());
 152         return body_size;
 153 }
 154 
 155 template<class MsgVer>
 156 template<FieldsFast field>
 157 constexpr inline bool __fastcall
 158 Message<MsgVer>::search() const noexcept(true) {
 159         using body_type=char const [max_size_of_fix_message];
 160         const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
 161         const_pointer field_ptr=this->body_length_tag;
 162         field_ptr=jmmcg::strstr_opt(reinterpret_cast<body_type &>(*field_ptr), jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value);
 163         assert(field_ptr>=start);
 164         return static_cast<size_type>(field_ptr-start)<=this->length();
 165 }
 166 
 167 template<class MsgVer> inline checksum_t
 168 Message<MsgVer>::generate_checksum(size_type body_len) const noexcept(true) {
 169         checksum_t fix_chk_sum{};
 170         const std::size_t checksum=std::accumulate(this->begin_string, std::next(this->begin_string, body_len+(this->body_length_value-this->begin_string)), 0UL);
 171         const std::size_t checksum_mod=(checksum%256UL);
 172         BOOST_MPL_ASSERT_RELATION(CheckSumLength, ==, 3);
 173         [[maybe_unused]] const int i=jmmcg::tostring_zero_pad_right_justify<10, CheckSumLength>(checksum_mod, reinterpret_cast<char (&)[CheckSumLength]>(*fix_chk_sum.data()));
 174         assert(i==CheckSumLength);
 175         return fix_chk_sum;
 176 }
 177 
 178 template<class MsgVer> constexpr inline bool
 179 Message<MsgVer>::is_checksum_valid(size_type body_len, const_pointer start_of_checksum_value) const noexcept(true) {
 180         auto const &computed_chksum=generate_checksum(body_len);
 181         return std::equal(computed_chksum.begin(), computed_chksum.end()-1, start_of_checksum_value);
 182 }
 183 
 184 template<class MsgVer> constexpr inline bool
 185 Message<MsgVer>::is_valid() const noexcept(true) {
 186         const bool has_msg_ver=std::equal(this->begin_string, this->body_length_tag, msg_version_t::MsgVer);
 187         if (has_msg_ver) {
 188                 auto const &msg_str=jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::BodyLength>::value;
 189                 const bool has_msg_size=std::equal(this->body_length_tag, this->body_length_value, msg_str);
 190                 if (has_msg_size) {
 191                         const_pointer next_field=this->body_length_value;
 192                         const size_type body_size=jmmcg::fromstring<size_type>(next_field, sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1);
 193                         underlying_fix_data_buffer::const_iterator end_of_body_size=this->msg_type_tag;
 194                         if (
 195                                 body_size>0
 196                                 && (body_size<(max_size_of_fix_message-sizeof(msg_version_t::MsgVer)-msg_version_t::fix_template_body_length_offset-sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1))
 197                                 && ((end_of_body_size-this->begin_string)>0)
 198                         ) {
 199                                 auto const &checksum_str=jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::value;
 200                                 underlying_fix_data_buffer::const_iterator start_of_checksum=end_of_body_size+body_size;
 201                                 const bool has_checksum=std::equal(start_of_checksum, start_of_checksum+jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size, checksum_str);
 202                                 if (has_checksum) {
 203                                         const bool has_terminal_separator=(*(end_of_body_size+body_size+jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size+CheckSumLength)==Separator);
 204                                         if (has_terminal_separator) {
 205                                                 const_pointer start_of_checksum_value=end_of_body_size+body_size+jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size;
 206                                                 return is_checksum_valid(body_size, start_of_checksum_value) && msg_version_t::is_valid(*this);
 207                                         }
 208                                 }
 209                         }
 210                 }
 211         }
 212         return false;
 213 }
 214 
 215 template<class MsgVer>
 216 template<FieldsFast field>
 217 constexpr inline underlying_fix_data_buffer::iterator
 218 Message<MsgVer>::add_field_tag(underlying_fix_data_buffer::iterator data) noexcept(true) {
 219         jmmcg::memcpy_opt(
 220                 jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value,
 221                 reinterpret_cast<typename jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::element_type &>(*data)
 222         );
 223         return data+jmmcg::enum_tags::mpl::to_array<FieldsFast, field>::size;
 224 }
 225 
 226 template<class MsgVer> inline std::string
 227 Message<MsgVer>::to_string() const noexcept(false) {
 228         std::stringstream ss;
 229         ss
 230                 <<this->begin_string
 231                 <<this->body_length_tag
 232                 <<this->body_length_value
 233                 <<this->msg_type_tag
 234                 <<this->data_;
 235         return ss.str();
 236 }
 237 
 238 template<class MsgVer> constexpr inline void
 239 Message<MsgVer>::finalise_msg(underlying_fix_data_buffer::iterator data) noexcept(true) {
 240         const std::size_t length=data-this->begin_string-MsgVer::fix_template_body_length_offset-sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)+1;
 241         BOOST_MPL_ASSERT_RELATION(sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1, ==, 3);
 242         [[maybe_unused]] const int i=jmmcg::tostring_zero_pad_right_justify<10, sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1>(
 243                 length,
 244                 reinterpret_cast<char (&)[sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1]>(*(this->body_length_value))
 245         );
 246         assert(i>0 && static_cast<std::size_t>(i)<sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL));
 247         underlying_fix_data_buffer::iterator ptr=data;
 248         using JMMCG_FIX_MSG_CHECKSUM_TAG_t=jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::element_type;
 249         jmmcg::memcpy_opt(jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::value, reinterpret_cast<JMMCG_FIX_MSG_CHECKSUM_TAG_t &>(*ptr));
 250         ptr+=jmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size;
 251         checksum_t const &checksum=generate_checksum(length);
 252         jmmcg::memcpy_opt(checksum, reinterpret_cast<checksum_t &>(*ptr));
 253         ptr+=CheckSumLength;
 254         *ptr=Separator;
 255         assert(this->is_valid());
 256         assert((ptr-this->begin_string)>0);
 257         assert(static_cast<size_type>(ptr-this->begin_string)<this->data_.size());
 258 }
 259 
 260 template<class MsgVer> inline std::ostream &
 261 operator<<(std::ostream &os, Message<MsgVer> const &m) {
 262         os<<m.to_string();
 263         return os;
 264 }
 265 
 266 } } } }

/* [<][>][^][v][top][bottom][index][help] */