libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
messages_impl.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2015 by J.M.McGuiness, isimud@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 namespace isimud { namespace ISIMUD_VER_NAMESPACE { namespace exchanges { namespace FIX { namespace common {
20 
21 template<class MsgVer> inline constexpr __stdcall
22 Header<MsgVer>::Header() noexcept(true) {
23  using fix_template_to_msg_type_t=underlying_fix_data_buffer::value_type[MsgVer::fix_template_msg_type_offset];
24  libjmmcg::memcpy_opt(
25  MsgVer::fix_template_to_msg_type,
26  reinterpret_cast<fix_template_to_msg_type_t &>(*begin_string)
27  );
28 }
29 
30 template<class MsgVer> inline constexpr typename Header<MsgVer>::size_type
31 Header<MsgVer>::length() const noexcept(true) {
32  const size_type body_size=libjmmcg::fromstring<size_type>(body_length_value, sizeof(body_length_value));
33  return msg_type_tag-begin_string+body_size+libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size+CheckSumLength+sizeof(Separator);
34 }
35 
36 template<class MsgVer>
37 template<FieldsFast field> inline
38 constexpr field_str_range_t __fastcall
39 Header<MsgVer>::find() noexcept(true) {
40  using body_type=char [max_size_of_fix_message];
41  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
42  pointer field_ptr=this->body_length_tag;
43  const constexpr size_type field_len=libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::size;
44  field_ptr=const_cast<pointer>(libjmmcg::strstr_opt(reinterpret_cast<body_type &>(*field_ptr), libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value));
45  assert(field_ptr);
46  assert(static_cast<size_type>(field_ptr-start)<this->length());
47  field_ptr+=field_len;
48  assert(static_cast<size_type>(field_ptr-start)<this->length());
49  pointer end=field_ptr;
50  end=const_cast<pointer>(libjmmcg::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>(end-start)<this->length());
54  return field_str_range_t(field_ptr, end-1);
55 }
56 
57 template<class MsgVer>
58 template<FieldsFast field> inline
59 constexpr field_str_const_range_t __fastcall
60 Header<MsgVer>::find() const noexcept(true) {
61  using body_type=char const [max_size_of_fix_message];
62  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
63  const_pointer field_ptr=this->body_length_tag;
64  const constexpr size_type field_len=libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::size;
65  field_ptr=libjmmcg::strstr_opt(reinterpret_cast<body_type &>(*field_ptr), libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value);
66  assert(field_ptr);
67  assert(static_cast<size_type>(field_ptr-start)<this->length());
68  field_ptr+=field_len;
69  assert(static_cast<size_type>(field_ptr-start)<this->length());
70  const_pointer end=field_ptr;
71  end=libjmmcg::strchr_opt<Separator>(reinterpret_cast<body_type &>(*end));
72  assert((end-field_ptr)>0);
73  assert(static_cast<size_type>(end-field_ptr)<this->length());
74  assert(static_cast<size_type>(end-start)<this->length());
75  return field_str_const_range_t(field_ptr, end);
76 }
77 
78 template<class MsgVer>
79 constexpr inline field_str_const_range_t
80 Header<MsgVer>::find_ExDestination() const noexcept(true) {
81  switch (type()) {
83  case MsgTypes::ExecutionReport:
84  case MsgTypes::MultilegOrderCancelReplace:
85  case MsgTypes::NewOrderCross:
86  case MsgTypes::NewOrderMultileg:
87  case MsgTypes::NewOrderSingle:
88  case MsgTypes::OrderCancelReject:
89  case MsgTypes::OrderCancelReplaceRequest:
90  case MsgTypes::OrderCancelRequest:
91  case MsgTypes::Quote:
92  case MsgTypes::QuoteResponse:
93  case MsgTypes::QuoteStatusReport:
94  return find<FieldsFast::ExDestination>();
95  default:
96  return field_str_const_range_t{};
97  }
98 }
99 
100 template<class MsgVer>
101 constexpr inline ExDestination_t
102 Header<MsgVer>::find_MIC() const noexcept(true) {
103  auto const &exdest=find_ExDestination();
104  if (exdest!=field_str_const_range_t{}) {
105  return libjmmcg::enum_tags::convert<ExDestination_t>(reinterpret_cast<std::array<char, sizeof(ExDestination_t)> const &>(*exdest.first));
106  } else {
107  return static_cast<ExDestination_t>(std::numeric_limits<std::underlying_type<ExDestination_t>::type>::max());
108  }
109 }
110 
111 template<class MsgVer> inline MsgTypes
112 Header<MsgVer>::type() const noexcept(true) {
113  field_str_const_range_t const &type_str=find<FieldsFast::MsgType>();
114  if ((type_str.second-type_str.first)==1) {
115  const auto type_int=static_cast<MsgTypes>(*type_str.first);
116  return static_cast<MsgTypes>(type_int);
117  } else {
118  union {
119  char c[2];
120  MsgTypes_t type_int;
121  } conv;
122  conv.c[0]=type_str.first[0];
123  conv.c[1]=type_str.first[1];
124  return static_cast<MsgTypes>(conv.type_int);
125  }
126 }
127 
128 template<class MsgVer> inline checksum_t
129 Header<MsgVer>::generate_checksum(size_type body_len) const noexcept(true) {
130  checksum_t fix_chk_sum{};
131  const std::size_t checksum=std::accumulate(this->begin_string, std::next(this->begin_string, body_len+1), 0UL);
132  const std::size_t checksum_mod=(checksum%256UL);
133  BOOST_MPL_ASSERT_RELATION(CheckSumLength, ==, 3);
134  [[maybe_unused]] const int i=libjmmcg::tostring_zero_pad_right_justify<10, CheckSumLength>(checksum_mod, reinterpret_cast<char (&)[CheckSumLength]>(*fix_chk_sum.data()));
135  assert(i==CheckSumLength);
136  return fix_chk_sum;
137 }
138 
139 template<class MsgVer> constexpr inline bool
140 Header<MsgVer>::is_checksum_valid(size_type body_len, const_pointer start_of_checksum_value) const noexcept(true) {
141  auto const &computed_chksum=generate_checksum(body_len+sizeof(begin_string)+sizeof(body_length_tag)+sizeof(body_length_value));
142  return std::equal(computed_chksum.begin(), computed_chksum.end()-1, start_of_checksum_value);
143 }
144 
145 template<class MsgVer> constexpr inline bool
146 Header<MsgVer>::is_valid() const noexcept(true) {
147  const bool has_msg_ver=std::equal(this->begin_string, this->body_length_tag, msg_version_t::MsgVer);
148  if (has_msg_ver) {
149  auto constexpr const &msg_str=libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::BodyLength>::value;
150  const bool has_msg_size=std::equal(this->body_length_tag, this->body_length_value, msg_str);
151  if (has_msg_size) {
152  const_pointer next_field=this->body_length_value;
153  const size_type body_size=libjmmcg::fromstring<size_type>(next_field, sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1);
154  underlying_fix_data_buffer::const_iterator end_of_body_size=this->msg_type_tag;
155  if (
156  body_size>0
157  && (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))
158  && ((end_of_body_size-this->begin_string)>0)
159  ) {
160  auto const &checksum_str=libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::value;
161  underlying_fix_data_buffer::const_iterator start_of_checksum=end_of_body_size+body_size;
162  const bool has_checksum=std::equal(start_of_checksum, start_of_checksum+libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size, checksum_str);
163  if (has_checksum) {
164  const bool has_terminal_separator=(*(end_of_body_size+body_size+libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size+CheckSumLength)==Separator);
165  if (has_terminal_separator) {
166  const_pointer start_of_checksum_value=end_of_body_size+body_size+libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size;
167  return is_checksum_valid(body_size, start_of_checksum_value);
168  }
169  }
170  }
171  }
172  }
173  return false;
174 }
175 
176 template<class MsgVer>
177 template<MsgTypes MsgType> inline constexpr underlying_fix_data_buffer::iterator
178 Header<MsgVer>::set_header() noexcept(true) {
179  using JMMCG_FIX_MSG_SEQ_NUM_TAG_t=libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::element_type;
180  pointer data=static_cast<pointer>(begin_string)+MsgVer::fix_template_msg_type_offset;
181  libjmmcg::memcpy_opt(
182  libjmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::value,
183  reinterpret_cast<typename libjmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::element_type &>(*data)
184  );
185  data+=libjmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::size;
186  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
187  assert(static_cast<size_type>(data-start)<this->length());
188  libjmmcg::memcpy_opt(
189  libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::value,
190  reinterpret_cast<JMMCG_FIX_MSG_SEQ_NUM_TAG_t &>(*data)
191  );
192  data+=libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::size;
193  assert(static_cast<size_type>(data-start)<this->length());
194  return data;
195 }
196 
197 template<class MsgVer>
198 template<MsgTypes MsgType> inline constexpr underlying_fix_data_buffer::iterator
199 Header<MsgVer>::set_sequence_num_int(SeqNum_t seq_num) noexcept(true) {
200  pointer data=set_header<MsgType>();
201  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
202  assert(static_cast<size_type>(data-start)<this->length());
203  const int i=libjmmcg::tostring(
204  seq_num,
205  data,
206  data_.size()-MsgVer::fix_template_msg_type_offset-libjmmcg::enum_tags::mpl::to_array<MsgTypes, MsgType>::size-libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::MsgSeqNum>::size+1
207  );
208  assert(i>0);
209  data+=i;
210  assert(static_cast<size_type>(data-start)<this->length());
211  return data;
212 }
213 
214 template<class MsgVer>
215 template<MsgTypes MsgType, class SrcMsg, class Ret> inline constexpr Ret
216 Header<MsgVer>::set_sequence_num(SrcMsg const &msg) noexcept(true) {
217  return this->set_sequence_num_int<MsgType>(msg.sequenceNumber);
218 }
219 
220 template<class MsgVer> constexpr inline __stdcall
221 Message<MsgVer>::Message() noexcept(true)
222 : Header_t() {
223 }
224 
225 template<class MsgVer> constexpr inline __stdcall
226 Message<MsgVer>::Message(logon_args_t const &) noexcept(true)
227 : Header_t() {
228 }
229 
230 template<class MsgVer> constexpr inline __stdcall
231 Message<MsgVer>::Message(logoff_args_t const &) noexcept(true)
232 : Header_t() {
233 }
234 
235 template<class MsgVer> constexpr inline __stdcall
236 Message<MsgVer>::Message(RejectCode_t const &) noexcept(true)
237 : Header_t() {
238 // TODO: need to construct this!
239 }
240 
241 template<class MsgVer> constexpr inline typename Message<MsgVer>::size_type __fastcall
242 Message<MsgVer>::size() const noexcept(true) {
243  const size_type body_size=libjmmcg::fromstring<size_type>(this->body_length_value);
244  assert(body_size<this->length());
245  return body_size;
246 }
247 
248 template<class MsgVer>
249 template<FieldsFast field>
250 constexpr inline bool __fastcall
251 Message<MsgVer>::search() const noexcept(true) {
252  using body_type=char const [max_size_of_fix_message];
253  const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
254  const_pointer field_ptr=this->body_length_tag;
255  field_ptr=libjmmcg::strstr_opt(reinterpret_cast<body_type &>(*field_ptr), libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value);
256  assert(field_ptr>=start);
257  return static_cast<size_type>(field_ptr-start)<=this->length();
258 }
259 
260 template<class MsgVer> constexpr inline bool
261 Message<MsgVer>::is_valid() const noexcept(true) {
262  return Header_t::is_valid() && msg_version_t::is_valid(*this);
263 }
264 
265 template<class MsgVer> constexpr common::ClientOrderID_t
266 Message<MsgVer>::clientOrderID() const noexcept(true) {
267  field_str_const_range_t const &type_str=this->template find<FieldsFast::ClOrdID>();
268  assert((type_str.second-type_str.first)>0);
269  common::ClientOrderID_t ret{};
270  assert(static_cast<size_type>(type_str.second-type_str.first)<=ret.max_size());
271  std::copy(type_str.first, type_str.second, ret.begin());
272  return ret;
273 }
274 
275 template<class MsgVer> constexpr inline common::Side
276 Message<MsgVer>::side() const noexcept(true) {
277  field_str_const_range_t const &type_str=this->template find<FieldsFast::Side>();
278  assert((type_str.second-type_str.first)==1);
279  return static_cast<common::Side>(*type_str.first);
280 }
281 
282 template<class MsgVer> constexpr inline Price_t
283 Message<MsgVer>::limitPrice() const noexcept(true) {
284  field_str_const_range_t const &type_str=this->template find<FieldsFast::Price>();
285  assert((type_str.second-type_str.first)>0);
286  const auto price=libjmmcg::fromstring<Price_t>(type_str.first, type_str.second-type_str.first);
287  return price*implied_decimal_places;
288 }
289 
290 template<class MsgVer> constexpr inline Quantity_t
291 Message<MsgVer>::orderQty() const noexcept(true) {
292  field_str_const_range_t const &type_str=this->template find<FieldsFast::OrderQty>();
293  assert((type_str.second-type_str.first)>0);
294  const auto qty=libjmmcg::fromstring<Quantity_t>(type_str.first, type_str.second-type_str.first-1);
295  return qty;
296 }
297 
298 template<class MsgVer> constexpr inline void
299 Message<MsgVer>::orderQty(Quantity_t q) noexcept(true) {
300  field_str_range_t type_str=this->template find<FieldsFast::OrderQty>();
301  assert((type_str.second-type_str.first)>0);
302  [[maybe_unused]] auto const i=libjmmcg::tostring(q, type_str.first, type_str.second-type_str.first);
303  assert(i>0);
304 }
305 
306 template<class MsgVer> constexpr inline SecurityID_t
307 Message<MsgVer>::instrumentID() const noexcept(true) {
308  field_str_const_range_t const &type_str=this->template find<FieldsFast::SecurityID>();
309  assert((type_str.second-type_str.first)>0);
310  SecurityID_t ret{};
311  assert(static_cast<size_type>(type_str.second-type_str.first)<=ret.max_size());
312  std::copy(type_str.first, type_str.second, ret.begin());
313  return ret;
314 }
315 
316 template<class MsgVer>
317 template<class OutIter>
318 inline OutIter
319 Message<MsgVer>::write_ClOrdID(ClientOrderID_t const &clID, OutIter data) noexcept(true) {
320  data=add_field_tag<FieldsFast::ClOrdID>(data);
321  libjmmcg::memcpy_opt(clID, reinterpret_cast<ClientOrderID_t &>(*data));
322  data+=clID.size()-1;
323  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
324  assert(static_cast<size_type>(data-start)<this->data_.size());
325  return data;
326 }
327 
328 template<class MsgVer>
329 template<class OutIter> inline OutIter
330 Message<MsgVer>::write_TransactTime(OutIter data) noexcept(true) {
331  data=add_field_tag<FieldsFast::TransactTime>(data);
332  boost::posix_time::ptime const timeUTC=boost::posix_time::microsec_clock::universal_time();
333  auto const &as_ISO_str=boost::posix_time::to_iso_extended_string(timeUTC);
334  auto const end=std::copy(as_ISO_str.begin(), as_ISO_str.end(), data);
335  assert(end>data);
336  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
337  assert(static_cast<size_type>(end-start)<this->data_.size());
338  return end;
339 }
340 
341 template<class MsgVer>
342 template<class OutIter> inline OutIter
343 Message<MsgVer>::write_ExDest(ExDestination_t mic, OutIter data) noexcept(true) {
344  data=add_field_tag<FieldsFast::ExDestinationIDSource>(data);
345  *data=static_cast<std::underlying_type<ExDestinationIDSource>::type>(ExDestinationIDSource::MIC);
346  ++data;
347  [[maybe_unused]] const_pointer const start=this->body_length_tag; // Convert from an offset in the class to a pointer-to-char in memory.
348  assert(static_cast<size_type>(data-start)<this->data_.size());
349  data=add_field_tag<FieldsFast::ExDestination>(data);
350  assert(static_cast<size_type>(data-start)<this->data_.size());
351  libjmmcg::memcpy_opt(
352  reinterpret_cast<std::array<char, sizeof(ExDestination_t)> const &>(mic),
353  reinterpret_cast<std::array<char, sizeof(ExDestination_t)> &>(*data)
354  );
355  data+=sizeof(ExDestination_t);
356  assert(static_cast<size_type>(data-start)<this->data_.size());
357  return data;
358 }
359 
360 template<class MsgVer>
361 template<FieldsFast field>
362 constexpr inline underlying_fix_data_buffer::iterator
364  [[maybe_unused]] const_pointer const start=this->body_length_value+sizeof(this->body_length_value); // Convert from an offset in the class to a pointer-to-char in memory.
365  assert(static_cast<size_type>(data-start)<(this->data_.size()));
366  libjmmcg::memcpy_opt(
367  libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::value,
368  reinterpret_cast<typename libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::element_type &>(*data)
369  );
370  data+=libjmmcg::enum_tags::mpl::to_array<FieldsFast, field>::size;
371  assert(static_cast<size_type>(data-start)<(this->data_.size()));
372  return data;
373 }
374 
375 template<class MsgVer> inline std::string
376 Message<MsgVer>::to_string() const noexcept(false) {
377  std::stringstream ss;
378  ss
379  <<this->begin_string
380  <<this->body_length_tag
381  <<this->body_length_value
382  <<this->msg_type_tag
383  <<this->data_;
384  return ss.str();
385 }
386 
387 template<class MsgVer> constexpr inline void
388 Message<MsgVer>::finalise_msg(underlying_fix_data_buffer::iterator data) noexcept(true) {
389  const size_type length=data-this->begin_string-MsgVer::fix_template_body_length_offset-sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)+1;
390  BOOST_MPL_ASSERT_RELATION(sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1, ==, 3);
391  [[maybe_unused]] const int i=libjmmcg::tostring_zero_pad_right_justify<10, sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1>(
392  length,
393  reinterpret_cast<char (&)[sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL)-1]>(*(this->body_length_value))
394  );
395  assert(i>0 && static_cast<size_type>(i)<sizeof(JMMCG_FIX_MSG_BODY_LENGTH_NULL));
396  underlying_fix_data_buffer::iterator ptr=data;
397  using JMMCG_FIX_MSG_CHECKSUM_TAG_t=libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::element_type;
398  libjmmcg::memcpy_opt(libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::value, reinterpret_cast<JMMCG_FIX_MSG_CHECKSUM_TAG_t &>(*ptr));
399  ptr+=libjmmcg::enum_tags::mpl::to_array<FieldsFast, FieldsFast::CheckSum>::size;
400  checksum_t const &checksum=this->generate_checksum(data-this->begin_string);
401  libjmmcg::memcpy_opt(checksum, reinterpret_cast<checksum_t &>(*ptr));
402  ptr+=CheckSumLength;
403  *ptr=Separator;
404  assert(this->is_valid());
405  assert((ptr-this->begin_string)>0);
406  assert(static_cast<size_type>(ptr-this->begin_string)<this->data_.size());
407  assert(this->is_valid());
408 }
409 
410 template<class MsgVer> inline std::ostream &
411 operator<<(std::ostream &os, Message<MsgVer> const &m) {
412  os<<m.to_string();
413  return os;
414 }
415 
416 } } } } }