High Frequency FIX Parser
C++ library for high frequency messaging with the Financial Information Exchange (FIX) protocol.
hffix.hpp
Go to the documentation of this file.
1/*******************************************************************************************
2Copyright 2011, T3 IP, LLC. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without modification, are
5permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice, this list of
8 conditions and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 of conditions and the following disclaimer in the documentation and/or other materials
12 provided with the distribution.
13
14THIS SOFTWARE IS PROVIDED BY T3 IP, LLC ``AS IS'' AND ANY EXPRESS OR IMPLIED
15WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL T3 IP, LLC OR
17CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24The views and conclusions contained in the software and documentation are those of the
25authors and should not be interpreted as representing official policies, either expressed
26or implied, of T3 IP, LLC.
27*******************************************************************************************/
28
35#ifndef HFFIX_HPP
36#define HFFIX_HPP
37
38#include "hffix_fields.hpp" // for field and message tag names and properties. Needed for length_fields[].
39#include <cstring> // for memcpy
40#include <string> //
41#include <algorithm> // for is_tag_a_data_length
42#include <numeric> // for accumulate
43#include <iostream> // for operator<<()
44#include <limits> // for numeric_limits<>::is_signed
45#include <stdexcept> // for exceptions
46#if __cplusplus >= 201703L
47#include <string_view> // for push_back_string()
48#endif
49#if __cplusplus >= 201103L
50#include <cstdint> // for std::uint8_t
51#include <chrono>
52#endif
53
54#ifndef HFFIX_NO_BOOST_DATETIME
55#ifdef DATE_TIME_TIME_HPP___ // The header include guard from boost/date_time/time.hpp
56#ifdef DATE_TIME_DATE_HPP___ // The header include guard from boost/date_time/date.hpp
57#define HFFIX_BOOST_DATETIME
58#endif
59#endif
60#endif
61
65namespace hffix {
66
67/* @cond EXCLUDE */
68
69namespace details {
70
71inline void throw_range_error() {
72 throw std::out_of_range("hffix message_writer buffer full");
73}
74
75template <std::size_t N>
76std::ptrdiff_t len(char const (&)[N]) { return std::ptrdiff_t(N - 1); }
77
78/*
79\brief Internal ascii-to-integer conversion.
80
81Parses ascii and returns a (possibly negative) integer.
82
83\tparam Int_type The type of integer to be returned.
84\param begin Pointer to the beginning of the ascii string.
85\param end Pointer to past-the-end of the ascii string.
86\return The ascii string represented as an integer of type Int_type.
87*/
88template<typename Int_type> Int_type atoi(char const* begin, char const* end)
89{
90 Int_type val(0);
91 bool isnegative(false);
92
93 if (begin < end && *begin == '-') {
94 isnegative = true;
95 ++begin;
96 }
97
98 for(; begin<end; ++begin) {
99 val *= 10;
100 val += (Int_type)(*begin - '0');
101 }
102
103 return isnegative ? -val : val;
104}
105
106
107/*
108\brief Internal ascii-to-unsigned-integer conversion.
109
110Parses ascii and returns an unsigned integer.
111
112\tparam Uint_type The type of unsigned integer to be returned.
113\param begin Pointer to the beginning of the ascii string.
114\param end Pointer to past-the-end of the ascii string.
115\return The ascii string represented as an unsigned integer of type Uint_type.
116*/
117template<typename Uint_type> Uint_type atou(char const* begin, char const* end)
118{
119 Uint_type val(0);
120
121 for(; begin<end; ++begin) {
122 val *= 10u;
123 val += (Uint_type)(*begin - '0');
124 }
125
126 return val;
127}
128
129
130/*
131\brief Internal integer-to-ascii conversion.
132
133Writes an integer out as ascii.
134
135\tparam Int_type Type of integer to be converted.
136\param number Value of the integer to be converted.
137\param buffer Pointer to location for the ascii to be written.
138\param end Past-the-end of the buffer, to check for overflow.
139\return Pointer to past-the-end of the ascii that was written.
140*/
141template<typename Int_type> char* itoa(Int_type number, char* buffer, char* end)
142{
143 // Write out the digits in reverse order.
144 bool isnegative(false);
145 if (number < 0) {
146 isnegative = true;
147 number = -number;
148 }
149
150 char*b = buffer;
151 do {
152 if (b >= end) details::throw_range_error();
153 *b++ = '0' + (number % 10);
154 number /= 10;
155 } while(number);
156
157 if (isnegative) {
158 if (b >= end) details::throw_range_error();
159 *b++ = '-';
160 }
161
162 // Reverse the digits in-place.
163 std::reverse(buffer, b);
164
165 return b;
166}
167
168
169/*
170\brief Internal unsigned-integer-to-ascii conversion.
171
172Writes an unsigned integer out as ascii.
173
174\tparam Int_type Type of integer to be converted.
175\param number Value of the integer to be converted.
176\param buffer Pointer to location for the ascii to be written.
177\param end Past-the-end of the buffer, to check for overflow.
178\return Pointer to past-the-end of the ascii that was written.
179*/
180template<typename Uint_type> char* utoa(Uint_type number, char* buffer, char* end)
181{
182 // Write out the digits in reverse order.
183 char*b = buffer;
184 do {
185 if (b >= end) details::throw_range_error();
186 *b++ = '0' + (number % 10);
187 number /= 10;
188 } while(number);
189
190 // Reverse the digits in-place.
191 std::reverse(buffer, b);
192
193 return b;
194}
195
196/*
197\brief Internal ascii-to-decimal conversion.
198
199Converts an ascii string to a decimal float, of the form \htmlonly mantissa&times;10<sup>exponent</sup>\endhtmlonly.
200
201Non-normalized. The exponent will always be less than or equal to zero.
202If the decimal float is an integer, the exponent will be zero.
203
204\tparam Int_type Signed integer type for the mantissa and exponent.
205\param begin Pointer to the beginning of the ascii string.
206\param end Pointer to past-the-end of the ascii string.
207\param mantissa Reference to storage for the mantissa of the decimal float to be returned.
208\param exponent Reference to storage for the exponent of the decimal float to be returned.
209*/
210template<typename Int_type> void atod(char const* begin, char const* end, Int_type& mantissa, Int_type& exponent)
211{
212 Int_type mantissa_ = 0;
213 Int_type exponent_ = 0;
214 bool isdecimal(false);
215 bool isnegative(false);
216
217 if (begin < end && *begin == '-') {
218 isnegative = true;
219 ++begin;
220 }
221
222 for(; begin < end; ++begin) {
223 if (*begin == '.') {
224 isdecimal = true;
225 } else {
226 mantissa_ *= 10;
227 mantissa_ += (*begin - '0');
228 if (isdecimal) --exponent_;
229 }
230 }
231
232 if (isnegative) mantissa_ = -mantissa_;
233 mantissa = mantissa_;
234 exponent = exponent_;
235}
236
237/*
238\brief Internal decimal-to-ascii conversion.
239
240Converts a decimal float of the form \htmlonly mantissa&times;10<sup>exponent</sup>\endhtmlonly to ascii.
241
242Non-normalized. The exponent parameter must be less than or equal to zero.
243
244\tparam Int_type Integer type for the mantissa and exponent.
245\param mantissa The mantissa of the decimal float.
246\param exponent The exponent of the decimal float. Must be less than or equal to zero.
247\param buffer Pointer to location for the ascii to be written.
248\param end Past-the-end of the buffer, to check for overflow.
249\return Pointer to past-the-end of the ascii that was written.
250*/
251template<typename Int_type> char* dtoa(Int_type mantissa, Int_type exponent, char* buffer, char* end)
252{
253 // Write out the digits in reverse order.
254 bool isnegative(false);
255 if (mantissa < 0) {
256 isnegative = true;
257 mantissa = -mantissa;
258 }
259
260 char*b = buffer;
261 do {
262 if (b >= end) details::throw_range_error();
263 *b++ = '0' + (mantissa % 10);
264 mantissa /= 10;
265 if (++exponent == 0) {
266 if (b >= end) details::throw_range_error();
267 *b++ = '.';
268 }
269 } while(mantissa > 0 || exponent < 1);
270
271 if (isnegative) {
272 if (b >= end) details::throw_range_error();
273 *b++ = '-';
274 }
275
276 // Reverse the digits in-place.
277 std::reverse(buffer, b);
278
279 return b;
280}
281
282
283/*
284\brief Internal ascii-to-date conversion.
285
286Parses ascii and returns a LocalMktDate or UTCDate.
287
288\param begin Pointer to the beginning of the ascii string.
289\param end Pointer to past-the-end of the ascii string.
290\param[out] year Year.
291\param[out] month Month.
292\param[out] day Day.
293\return True if successful and the out arguments were set.
294*/
295inline bool atodate(
296 char const* begin,
297 char const* end,
298 int& year,
299 int& month,
300 int& day
301)
302{
303 if (end - begin != 8) return false;
304
305 year = details::atoi<int>(begin, begin + 4);
306 month = details::atoi<int>(begin + 4, begin + 6);
307 day = details::atoi<int>(begin + 6, begin + 8);
308
309 return true;
310}
311
312
313/*
314\brief Internal ascii-to-time conversion with millisecond precision.
315
316Parses ascii and returns a time with millisecond precision.
317
318\param begin Pointer to the beginning of the ascii string.
319\param end Pointer to past-the-end of the ascii string.
320\param[out] hour Hour.
321\param[out] minute Minute.
322\param[out] second Second.
323\param[out] millisecond Millisecond.
324\return True if successful and the out arguments were set.
325*/
326inline bool atotime(
327 char const* begin,
328 char const* end,
329 int& hour,
330 int& minute,
331 int& second,
332 int& millisecond
333)
334{
335 if (end - begin != 8 && end - begin != 12) return false;
336
337 hour = details::atoi<int>(begin, begin + 2);
338 minute = details::atoi<int>(begin + 3, begin + 5);
339 second = details::atoi<int>(begin + 6, begin + 8);
340
341 if (end - begin == 12)
342 millisecond = details::atoi<int>(begin + 9, begin + 12);
343 else
344 millisecond = 0;
345 return true;
346}
347
348/*
349\brief Internal ascii-to-time conversion with nanosecond precision.
350
351Parses ascii and returns a time with nanosecond precision.
352
353\param begin Pointer to the beginning of the ascii string.
354\param end Pointer to past-the-end of the ascii string.
355\param[out] hour Hour.
356\param[out] minute Minute.
357\param[out] second Second.
358\param[out] nanosecond Nanosecond.
359\return True if successful and the out arguments were set.
360*/
361inline bool atotime_nano(
362 char const* begin,
363 char const* end,
364 int& hour,
365 int& minute,
366 int& second,
367 int& nanosecond
368)
369{
370 if (end - begin < 8)
371 return false;
372
373 hour = details::atoi<int>(begin, begin + 2);
374 minute = details::atoi<int>(begin + 3, begin + 5);
375 second = details::atoi<int>(begin + 6, begin + 8);
376
377 switch (end - begin) {
378 case 12: nanosecond = details::atoi<int>(begin + 9, begin + 12) * 1000000L; break;
379 case 15: nanosecond = details::atoi<int>(begin + 9, begin + 15) * 1000L; break;
380 case 18: nanosecond = details::atoi<int>(begin + 9, begin + 18); break;
381 default: nanosecond = 0;
382 }
383 return true;
384}
385
386#if __cplusplus >= 201103L
387/*
388\brief SFINAE to check if type is std::chrono::time_point
389
390\tparam Clock the clock on which this time point is measured
391\tparam Duration a std::chrono::duration type used to measure the time since epoch
392*/
393template<typename T>
394struct is_time_point : std::false_type {};
395
396template<typename Clock, typename Duration>
397struct is_time_point<std::chrono::time_point<Clock, Duration>> : std::true_type {};
398
399/*
400\brief Internal ascii-to-timepoint conversion with millisecond precision.
401
402Parses ascii and returns a std::chrono::time_point.
403
404\param begin Pointer to the beginning of the ascii string.
405\param end Pointer to past-the-end of the ascii string.
406\param[out] tp time_point.
407\return True if successful and the out arguments were set.
408*/
409template <typename TimePoint>
410inline typename std::enable_if<details::is_time_point<TimePoint>::value, bool>::type
411atotimepoint(
412 char const* begin,
413 char const* end,
414 TimePoint& tp
415)
416{
417 // TODO: after c++20 this simplifies to
418 // std::chrono::parse("%Y%m%d-%T", tp);
419 int year, month, day, hour, minute, second, millisecond;
420 if (!atotime(begin + 9, end, hour, minute, second, millisecond))
421 return false;
422 if (!atodate(begin, begin + 8, year, month, day))
423 return false;
424
425 // from http://howardhinnant.github.io/date_algorithms.html
426 year -= month <= 2;
427 const unsigned era = (year >= 0 ? year : year - 399) / 400;
428 const unsigned yoe = static_cast<unsigned>(year - era * 400);
429 const unsigned doy = (153 * (month + (month > 2 ? -3 : 9)) + 2) / 5 + day - 1;
430 const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
431 const unsigned long days_since_epoch = era * 146097 + static_cast<unsigned>(doe) - 719468;
432
433 tp = TimePoint(std::chrono::seconds(days_since_epoch * 24 * 3600) +
434 std::chrono::hours(hour) +
435 std::chrono::minutes(minute) +
436 std::chrono::seconds(second) +
437 std::chrono::milliseconds(millisecond));
438
439 return true;
440}
441
442/*
443\brief Internal ascii-to-timepoint conversion with nanosecond precision.
444
445Parses ascii and returns a std::chrono::time_point.
446
447\param begin Pointer to the beginning of the ascii string.
448\param end Pointer to past-the-end of the ascii string.
449\param[out] tp time_point.
450\return True if successful and the out arguments were set.
451*/
452template <typename TimePoint>
453inline typename std::enable_if<details::is_time_point<TimePoint>::value, bool>::type
454atotimepoint_nano(
455 char const* begin,
456 char const* end,
457 TimePoint& tp
458)
459{
460 // TODO: after c++20 this simplifies to
461 // std::chrono::parse("%Y%m%d-%T", tp);
462 int year, month, day, hour, minute, second, nanosecond;
463 if (!atotime_nano(begin + 9, end, hour, minute, second, nanosecond))
464 return false;
465 if (!atodate(begin, begin + 8, year, month, day))
466 return false;
467
468 // from http://howardhinnant.github.io/date_algorithms.html
469 year -= month <= 2;
470 const unsigned era = (year >= 0 ? year : year - 399) / 400;
471 const unsigned yoe = static_cast<unsigned>(year - era * 400);
472 const unsigned doy = (153 * (month + (month > 2 ? -3 : 9)) + 2) / 5 + day - 1;
473 const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
474 const unsigned long days_since_epoch = era * 146097 + static_cast<unsigned>(doe) - 719468;
475
476 tp = TimePoint(std::chrono::seconds(days_since_epoch * 24 * 3600) +
477 std::chrono::hours(hour) +
478 std::chrono::minutes(minute) +
479 std::chrono::seconds(second) +
480 std::chrono::nanoseconds(nanosecond));
481
482 return true;
483}
484
485/*
486\brief Internal ascii-to-timepoint conversion with millisecond precision.
487
488Parses ascii and returns a std::chrono::time_point.
489
490\param tp TimePoint to parse.
491\param[out] year Year.
492\param[out] month Month.
493\param[out] day Day.
494\param[out] hour Hour.
495\param[out] minute Minute.
496\param[out] second Second.
497\param[out] millisecond Millisecond.
498*/
499template <typename TimePoint>
500inline typename std::enable_if<details::is_time_point<TimePoint>::value, void>::type
501timepointtoparts(TimePoint tp, int& year, int& month, int& day,
502 int& hour, int& minute, int& second, int& millisecond) noexcept
503{
504 auto epoch_sec = std::chrono::time_point_cast<
505 std::chrono::seconds>(tp).time_since_epoch().count();
506 auto day_sec = epoch_sec - (epoch_sec % 86400);
507 auto days_since_epoch = day_sec / 86400;
508
509 // see http://howardhinnant.github.io/date_algorithms.html
510 days_since_epoch += 719468;
511 const unsigned era = (days_since_epoch >= 0 ? days_since_epoch : days_since_epoch - 146096) / 146097;
512 const unsigned doe = static_cast<unsigned>(days_since_epoch - era * 146097);
513 const unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
514 year = static_cast<unsigned>(yoe) + era * 400;
515 const unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
516 const unsigned mp = (5 * doy + 2) / 153;
517 day = doy - (153 * mp + 2) / 5 + 1;
518 month = mp + (mp < 10 ? 3 : -9);
519 year += month <= 2;
520
521 auto in_day = tp - std::chrono::seconds(day_sec);
522 millisecond = std::chrono::time_point_cast<std::chrono::milliseconds>(
523 in_day).time_since_epoch().count();
524 hour = millisecond / (60 * 60 * 1000);
525 millisecond -= hour * 60 * 60 * 1000;
526 minute = millisecond / (60 * 1000);
527 millisecond -= minute * 60 * 1000;
528 second = millisecond / 1000;
529 millisecond -= second * 1000;
530}
531
532/*
533\brief Internal ascii-to-timepoint conversion with nanosecond precision.
534
535Parses ascii and returns a std::chrono::time_point.
536
537\param tp TimePoint to parse.
538\param[out] year Year.
539\param[out] month Month.
540\param[out] day Day.
541\param[out] hour Hour.
542\param[out] minute Minute.
543\param[out] second Second.
544\param[out] nanosecond Nanosecond.
545*/
546template <typename TimePoint>
547inline typename std::enable_if<details::is_time_point<TimePoint>::value, void>::type
548timepointtoparts_nano(TimePoint tp, int& year, int& month, int& day,
549 int& hour, int& minute, int& second, int& nanosecond) noexcept
550{
551 auto epoch_sec = std::chrono::time_point_cast<
552 std::chrono::seconds>(tp).time_since_epoch().count();
553 auto day_sec = epoch_sec - (epoch_sec % 86400);
554 auto days_since_epoch = day_sec / 86400;
555
556 // see http://howardhinnant.github.io/date_algorithms.html
557 days_since_epoch += 719468;
558 const unsigned era = (days_since_epoch >= 0 ? days_since_epoch : days_since_epoch - 146096) / 146097;
559 const unsigned doe = static_cast<unsigned>(days_since_epoch - era * 146097);
560 const unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
561 year = static_cast<unsigned>(yoe) + era * 400;
562 const unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
563 const unsigned mp = (5 * doy + 2) / 153;
564 day = doy - (153 * mp + 2) / 5 + 1;
565 month = mp + (mp < 10 ? 3 : -9);
566 year += month <= 2;
567
568 // the math here must be in higher precision, but at the end it fits in an int
569 auto in_day = tp - std::chrono::seconds(day_sec);
570 long lnanosecond = std::chrono::time_point_cast<std::chrono::nanoseconds>(
571 in_day).time_since_epoch().count();
572 hour = lnanosecond / (60 * 60 * 1000000000L);
573 lnanosecond -= hour * 60 * 60 * 1000000000L;
574 minute = lnanosecond / (60 * 1000000000L);
575 lnanosecond -= minute * 60 * 1000000000L;
576 second = lnanosecond / 1000000000L;
577 lnanosecond -= second * 1000000000L;
578 nanosecond = static_cast<int>(lnanosecond);
579}
580#endif
581
582} // namespace details
583
584/* @endcond*/
585
623public:
624
630 message_writer(char* buffer, size_t size):
631 buffer_(buffer),
632 buffer_end_(buffer + size),
633 next_(buffer),
634 body_length_(NULL) {
635 }
636
642 message_writer(char* begin, char* end) :
643 buffer_(begin),
644 buffer_end_(end),
645 next_(begin),
646 body_length_(NULL) {
647 }
648
654 template<size_t N>
655 message_writer(char(&buffer)[N]) :
656 buffer_(buffer),
657 buffer_end_(&(buffer[N])),
658 next_(buffer),
659 body_length_(NULL) {
660 }
661
662
667
670
676 size_t message_size() const {
677 return next_ - buffer_;
678 }
679
685 char* message_begin() const {
686 return buffer_;
687 }
693 char* message_end() const {
694 return next_;
695 }
696
700 size_t buffer_size() const {
701 return buffer_end_ - buffer_;
702 }
703
707 size_t buffer_size_remaining() const {
708 return buffer_end_ - next_;
709 }
710
712
715
727 void push_back_header(char const* begin_string_version) {
728 if (body_length_) throw std::logic_error("hffix message_writer.push_back_header called twice");
729 if (buffer_end_ - next_ < 2 + std::ptrdiff_t(strlen(begin_string_version)) + 3 + 7) {
730 details::throw_range_error();
731 }
732 memcpy(next_, "8=", 2);
733 next_ += 2;
734 memcpy(next_, begin_string_version, std::strlen(begin_string_version));
735 next_ += std::strlen(begin_string_version);
736 *(next_++) = '\x01';
737 memcpy(next_, "9=", 2);
738 next_ += 2;
739 body_length_ = next_;
740 next_ += 6; // 6 characters reserved for BodyLength.
741 *next_++ = '\x01';
742 }
743
744#if __cplusplus >= 201703L
756 void push_back_header(std::string_view begin_string_version) {
757 if (body_length_) throw std::logic_error("hffix message_writer.push_back_header called twice");
758 if (buffer_end_ - next_ < 2 + std::ptrdiff_t(begin_string_version.size()) + 3 + 7) {
759 details::throw_range_error();
760 }
761 memcpy(next_, "8=", 2);
762 next_ += 2;
763 memcpy(next_, begin_string_version.data(), begin_string_version.size());
764 next_ += begin_string_version.size();
765 *(next_++) = '\x01';
766 memcpy(next_, "9=", 2);
767 next_ += 2;
768 body_length_ = next_;
769 next_ += 6; // 6 characters reserved for BodyLength.
770 *next_++ = '\x01';
771 }
772#endif
773
790 void push_back_trailer(bool calculate_checksum = true) {
791 // Calculate and write out the BodyLength.
792 // BodyLength does not include the SOH character after the BodyLength field.
793 // BodyLength does not include the SOH character before the CheckSum field.
794 if (!body_length_) {
795 throw std::logic_error("hffix message_writer.push_back_trailer called before message_writer.push_back_header");
796 }
797
798 size_t const len = next_ - (body_length_ + 7);
799 body_length_[0] = '0' + (len / 100000) % 10;
800 body_length_[1] = '0' + (len / 10000) % 10;
801 body_length_[2] = '0' + (len / 1000) % 10;
802 body_length_[3] = '0' + (len / 100) % 10;
803 body_length_[4] = '0' + (len / 10) % 10;
804 body_length_[5] = '0' + len % 10;
805
806 if (buffer_end_ - next_ < 7) {
807 details::throw_range_error();
808 }
809
810 // write out the CheckSum after optionally calculating it
811 if (calculate_checksum) {
812#if __cplusplus >= 201103L
813 using std::uint8_t;
814#else
815 typedef unsigned char uint8_t;
816#endif
817 uint8_t const checksum = std::accumulate(buffer_, next_, uint8_t(0));
818
819 memcpy(next_, "10=", 3);
820 next_ += 3;
821 next_[0] = '0' + ((checksum / 100) % 10);
822 next_[1] = '0' + ((checksum / 10) % 10);
823 next_[2] = '0' + (checksum % 10);
824
825 next_ += 3;
826 *next_++ = '\x01';
827 } else {
828 memcpy(next_, "10=000\x01", 7);
829 next_ += 7;
830 }
831
832 }
833
835
838
848 void push_back_string(int tag, char const* begin, char const* end) {
849 next_ = details::itoa(tag, next_, buffer_end_);
850 if (buffer_end_ - next_ < (end - begin) + 2) {
851 details::throw_range_error();
852 }
853 *next_++ = '=';
854 memcpy(next_, begin, end - begin);
855 next_ += (end - begin);
856 *next_++ = '\x01';
857 }
858
867 void push_back_string(int tag, char const* cstring) {
868 // Find the end of the cstring, like strlen, but throw if the cstring
869 // is longer than the remaining buffer.
870 char const* cstring_end = (char const*)memchr(cstring, 0, buffer_end_ - next_);
871 if (cstring_end) push_back_string(tag, cstring, cstring_end);
872 else details::throw_range_error();
873 }
874
886 void push_back_string(int tag, std::string const& s) {
887 push_back_string(tag, s.data(), s.data() + s.size());
888 }
889
890
891#if __cplusplus >= 201703L
902 void push_back_string(int tag, std::string_view s) {
903 push_back_string(tag, s.data(), s.data() + s.length());
904 }
905#endif
906
915 void push_back_char(int tag, char character) {
916 next_ = details::itoa(tag, next_, buffer_end_);
917 if (buffer_end_ - next_ < 3) {
918 details::throw_range_error();
919 }
920 *next_++ = '=';
921 *next_++ = character;
922 *next_++ = '\x01';
923 }
925
937 template<typename Int_type> void push_back_int(int tag, Int_type number) {
938 next_ = details::itoa(tag, next_, buffer_end_);
939 if (next_ >= buffer_end_) details::throw_range_error();
940 *next_++ = '=';
941 next_ = details::itoa(number, next_, buffer_end_);
942 if (next_ >= buffer_end_) details::throw_range_error();
943 *next_++ = '\x01';
944 }
945
947
950
966 template<typename Int_type> void push_back_decimal(int tag, Int_type mantissa, Int_type exponent) {
967 next_ = details::itoa(tag, next_, buffer_end_);
968 if (next_ >= buffer_end_) details::throw_range_error();
969 *next_++ = '=';
970 next_ = details::dtoa(mantissa, exponent, next_, buffer_end_);
971 if (next_ >= buffer_end_) details::throw_range_error();
972 *next_++ = '\x01';
973 }
975
976
979
990 void push_back_date(int tag, int year, int month, int day) {
991 next_ = details::itoa(tag, next_, buffer_end_);
992 if (buffer_end_ - next_ < details::len("=YYYYMMDD|")) {
993 details::throw_range_error();
994 }
995 *next_++ = '=';
996 itoa_padded(year, next_, next_ + 4);
997 next_ += 4;
998 itoa_padded(month, next_, next_ + 2);
999 next_ += 2;
1000 itoa_padded(day, next_, next_ + 2);
1001 next_ += 2;
1002 *next_++ = '\x01';
1003 }
1013 void push_back_monthyear(int tag, int year, int month) {
1014 next_ = details::itoa(tag, next_, buffer_end_);
1015 if (buffer_end_ - next_ < details::len("=YYYYMM|")) {
1016 details::throw_range_error();
1017 }
1018 *next_++ = '=';
1019 itoa_padded(year, next_, next_ + 4);
1020 next_ += 4;
1021 itoa_padded(month, next_, next_ + 2);
1022 next_ += 2;
1023 *next_++ = '\x01';
1024 }
1025
1040 void push_back_timeonly(int tag, int hour, int minute, int second) {
1041 next_ = details::itoa(tag, next_, buffer_end_);
1042 if (buffer_end_ - next_ < details::len("=HH:MM:SS|")) {
1043 details::throw_range_error();
1044 }
1045 *next_++ = '=';
1046 itoa_padded(hour, next_, next_ + 2);
1047 next_ += 2;
1048 *next_++ = ':';
1049 itoa_padded(minute, next_, next_ + 2);
1050 next_ += 2;
1051 *next_++ = ':';
1052 itoa_padded(second, next_, next_ + 2);
1053 next_ += 2;
1054 *next_++ = '\x01';
1055 }
1056
1070 void push_back_timeonly(int tag, int hour, int minute, int second, int millisecond) {
1071 next_ = details::itoa(tag, next_, buffer_end_);
1072 if (buffer_end_ - next_ < details::len("=HH:MM:SS.sss|")) {
1073 details::throw_range_error();
1074 }
1075 *next_++ = '=';
1076 itoa_padded(hour, next_, next_ + 2);
1077 next_ += 2;
1078 *next_++ = ':';
1079 itoa_padded(minute, next_, next_ + 2);
1080 next_ += 2;
1081 *next_++ = ':';
1082 itoa_padded(second, next_, next_ + 2);
1083 next_ += 2;
1084 *next_++ = '.';
1085 itoa_padded(millisecond, next_, next_ + 3);
1086 next_ += 3;
1087 *next_++ = '\x01';
1088 }
1089
1103 void push_back_timeonly_nano(int tag, int hour, int minute, int second, int nanosecond) {
1104 next_ = details::itoa(tag, next_, buffer_end_);
1105 if (buffer_end_ - next_ < details::len("=HH:MM:SS.sssssssss|")) {
1106 details::throw_range_error();
1107 }
1108 *next_++ = '=';
1109 itoa_padded(hour, next_, next_ + 2);
1110 next_ += 2;
1111 *next_++ = ':';
1112 itoa_padded(minute, next_, next_ + 2);
1113 next_ += 2;
1114 *next_++ = ':';
1115 itoa_padded(second, next_, next_ + 2);
1116 next_ += 2;
1117 *next_++ = '.';
1118 itoa_padded(nanosecond, next_, next_ + 9);
1119 next_ += 9;
1120 *next_++ = '\x01';
1121 }
1122
1140 void push_back_timestamp(int tag, int year, int month, int day, int hour, int minute, int second) {
1141 next_ = details::itoa(tag, next_, buffer_end_);
1142
1143 if (buffer_end_ - next_ < details::len("=YYYYMMDD-HH:MM:SS|")) {
1144 details::throw_range_error();
1145 }
1146 *next_++ = '=';
1147 itoa_padded(year, next_, next_ + 4);
1148 next_ += 4;
1149 itoa_padded(month, next_, next_ + 2);
1150 next_ += 2;
1151 itoa_padded(day, next_, next_ + 2);
1152 next_ += 2;
1153 *next_++ = '-';
1154 itoa_padded(hour, next_, next_ + 2);
1155 next_ += 2;
1156 *next_++ = ':';
1157 itoa_padded(minute, next_, next_ + 2);
1158 next_ += 2;
1159 *next_++ = ':';
1160 itoa_padded(second, next_, next_ + 2);
1161 next_ += 2;
1162 *next_++ = '\x01';
1163 }
1164
1181 void push_back_timestamp(int tag, int year, int month, int day, int hour, int minute, int second, int millisecond) {
1182 next_ = details::itoa(tag, next_, buffer_end_);
1183 if (buffer_end_ - next_ < details::len("=YYYYMMDD-HH:MM:SS.sss|")) {
1184 details::throw_range_error();
1185 }
1186 *next_++ = '=';
1187 itoa_padded(year, next_, next_ + 4);
1188 next_ += 4;
1189 itoa_padded(month, next_, next_ + 2);
1190 next_ += 2;
1191 itoa_padded(day, next_, next_ + 2);
1192 next_ += 2;
1193 *next_++ = '-';
1194 itoa_padded(hour, next_, next_ + 2);
1195 next_ += 2;
1196 *next_++ = ':';
1197 itoa_padded(minute, next_, next_ + 2);
1198 next_ += 2;
1199 *next_++ = ':';
1200 itoa_padded(second, next_, next_ + 2);
1201 next_ += 2;
1202 *next_++ = '.';
1203 itoa_padded(millisecond, next_, next_ + 3);
1204 next_ += 3;
1205 *next_++ = '\x01';
1206 }
1207
1224 void push_back_timestamp_nano(int tag, int year, int month, int day, int hour, int minute, int second, int nanosecond) {
1225 next_ = details::itoa(tag, next_, buffer_end_);
1226 if (buffer_end_ - next_ < details::len("=YYYYMMDD-HH:MM:SS.sssssssss|")) {
1227 details::throw_range_error();
1228 }
1229 *next_++ = '=';
1230 itoa_padded(year, next_, next_ + 4);
1231 next_ += 4;
1232 itoa_padded(month, next_, next_ + 2);
1233 next_ += 2;
1234 itoa_padded(day, next_, next_ + 2);
1235 next_ += 2;
1236 *next_++ = '-';
1237 itoa_padded(hour, next_, next_ + 2);
1238 next_ += 2;
1239 *next_++ = ':';
1240 itoa_padded(minute, next_, next_ + 2);
1241 next_ += 2;
1242 *next_++ = ':';
1243 itoa_padded(second, next_, next_ + 2);
1244 next_ += 2;
1245 *next_++ = '.';
1246 itoa_padded(nanosecond, next_, next_ + 9);
1247 next_ += 9;
1248 *next_++ = '\x01';
1249 }
1251
1252#ifdef HFFIX_BOOST_DATETIME
1253
1256
1267 void push_back_date(int tag, boost::gregorian::date date) {
1268 if (!date.is_not_a_date())
1269 push_back_date(tag, date.year(), date.month(), date.day());
1270 }
1271
1286 void push_back_timeonly(int tag, boost::posix_time::time_duration timeonly) {
1287 if (!timeonly.is_not_a_date_time())
1289 tag,
1290 timeonly.hours(),
1291 timeonly.minutes(),
1292 timeonly.seconds(),
1293 static_cast<int>(timeonly.fractional_seconds() * 1000 / boost::posix_time::time_duration::ticks_per_second())
1294 );
1295 }
1296
1311 void push_back_timeonly_nano(int tag, boost::posix_time::time_duration timeonly) {
1312 if (!timeonly.is_not_a_date_time())
1314 tag,
1315 timeonly.hours(),
1316 timeonly.minutes(),
1317 timeonly.seconds(),
1318 static_cast<int>(timeonly.fractional_seconds() * 1000000000L / boost::posix_time::time_duration::ticks_per_second())
1319 );
1320 }
1321
1336 void push_back_timestamp(int tag, boost::posix_time::ptime timestamp) {
1337 if (!timestamp.is_not_a_date_time())
1339 tag,
1340 timestamp.date().year(),
1341 timestamp.date().month(),
1342 timestamp.date().day(),
1343 timestamp.time_of_day().hours(),
1344 timestamp.time_of_day().minutes(),
1345 timestamp.time_of_day().seconds(),
1346 static_cast<int>(timestamp.time_of_day().fractional_seconds() * 1000 / boost::posix_time::time_duration::ticks_per_second())
1347 );
1348 else
1349 throw std::logic_error("push_back_timestamp called with not_a_date_time.");
1350 }
1351
1366 void push_back_timestamp_nano(int tag, boost::posix_time::ptime timestamp) {
1367 if (!timestamp.is_not_a_date_time())
1369 tag,
1370 timestamp.date().year(),
1371 timestamp.date().month(),
1372 timestamp.date().day(),
1373 timestamp.time_of_day().hours(),
1374 timestamp.time_of_day().minutes(),
1375 timestamp.time_of_day().seconds(),
1376 static_cast<int>(timestamp.time_of_day().fractional_seconds() * 1000000000L / boost::posix_time::time_duration::ticks_per_second())
1377 );
1378 else
1379 throw std::logic_error("push_back_timestamp_nano called with not_a_date_time.");
1380 }
1382#endif // HFFIX_BOOST_DATETIME
1383
1384#if __cplusplus >= 201103L
1387
1402 template<typename Clock, typename Duration>
1403 void push_back_timestamp(int tag, std::chrono::time_point<Clock,Duration> tp) {
1404 // TODO: with c++20, we can use std::chrono::format
1405 int year, month, day, hour, minute, second, millisecond;
1406 details::timepointtoparts(tp, year, month, day, hour, minute, second, millisecond);
1407 push_back_timestamp(tag, year, month, day, hour, minute, second, millisecond);
1408 }
1409
1424 template<typename Clock, typename Duration>
1425 void push_back_timestamp_nano(int tag, std::chrono::time_point<Clock,Duration> tp) {
1426 // TODO: with c++20, we can use std::chrono::format
1427 int year, month, day, hour, minute, second, nanosecond;
1428 details::timepointtoparts_nano(tp, year, month, day, hour, minute, second, nanosecond);
1429 push_back_timestamp_nano(tag, year, month, day, hour, minute, second, nanosecond);
1430 }
1431
1444 template<typename Rep, typename Period>
1445 void push_back_timeonly(int tag, std::chrono::duration<Rep,Period> timeonly) {
1446 using namespace std::chrono;
1447
1449 tag,
1450 duration_cast<hours> (timeonly).count(),
1451 duration_cast<minutes> (timeonly % hours(1)).count(),
1452 duration_cast<seconds> (timeonly % minutes(1)).count(),
1453 duration_cast<milliseconds>(timeonly % seconds(1)).count()
1454 );
1455 }
1456
1469 template<typename Rep, typename Period>
1470 void push_back_timeonly_nano(int tag, std::chrono::duration<Rep,Period> timeonly) {
1471 using namespace std::chrono;
1472
1474 tag,
1475 duration_cast<hours> (timeonly).count(),
1476 duration_cast<minutes> (timeonly % hours(1)).count(),
1477 duration_cast<seconds> (timeonly % minutes(1)).count(),
1478 duration_cast<nanoseconds>(timeonly % seconds(1)).count()
1479 );
1480 }
1482#endif
1483
1484
1487
1513 void push_back_data(int tag_data_length, int tag_data, char const* begin, char const* end) {
1514 next_ = details::itoa(tag_data_length, next_, buffer_end_);
1515 if (next_ == buffer_end_) details::throw_range_error();
1516 *next_++ = '=';
1517 next_ = details::itoa(end - begin, next_, buffer_end_);
1518 if (next_ == buffer_end_) details::throw_range_error();
1519 *next_++ = '\x01';
1520 next_ = details::itoa(tag_data, next_, buffer_end_);
1521
1522 if (buffer_end_ - next_ < (end - begin) + 2) {
1523 details::throw_range_error();
1524 }
1525 *next_++ = '=';
1526 memcpy(next_, begin, end - begin);
1527 next_ += end - begin;
1528 *next_++ = '\x01';
1529 }
1530
1531
1533private:
1534 static void itoa_padded(int x, char* b, char* e) {
1535 while (e > b) {
1536 *--e = '0' + (x % 10);
1537 x /= 10;
1538 }
1539 }
1540
1541 char* buffer_;
1542 char* buffer_end_;
1543 char* next_;
1544 char* body_length_; // Pointer to the location at which the BodyLength should be written, once the length of the message is known. 6 chars, which allows for messagelength up to 999,999.
1545};
1546
1547class message_reader;
1548class message_reader_const_iterator;
1549
1576public:
1577
1579 char const* begin() const {
1580 return begin_;
1581 }
1582
1584 char const* end() const {
1585 return end_;
1586 }
1587
1589 size_t size() const {
1590 return end_ - begin_;
1591 }
1592
1593
1597 inline friend bool operator==(field_value const& that, char const* cstring) {
1598 return !strncmp(that.begin(), cstring, that.size()) && !cstring[that.size()];
1599 // TODO Is this correct? Maybe getting too fancy here trying to avoid call to strlen.
1600 }
1601
1605 inline friend bool operator==(char const* cstring, field_value const& that) {
1606 return that == cstring;
1607 }
1608
1612 inline friend bool operator!=(field_value const& that, char const* cstring) {
1613 return !(that == cstring);
1614 }
1615
1619 inline friend bool operator!=(char const* cstring, field_value const& that) {
1620 return !(that == cstring);
1621 }
1622
1626 inline friend bool operator==(field_value const& that, std::string const& s) {
1627 return that.size() == s.size() && !strncmp(that.begin(), s.data(), that.size());
1628 }
1629
1633 inline friend bool operator==(std::string const& s, field_value const& that) {
1634 return that == s;
1635 }
1636
1640 inline friend bool operator!=(field_value const& that, std::string const& s) {
1641 return !(that == s);
1642 }
1643
1647 inline friend bool operator!=(std::string const& s, field_value const& that) {
1648 return !(that == s);
1649 }
1650
1651#if __cplusplus >= 201703L
1655 inline friend bool operator==(field_value const& that, std::string_view s) {
1656 return std::equal(that.begin(), that.end(), s.begin(), s.end());
1657 }
1658
1662 inline friend bool operator==(std::string_view s, field_value const& that) {
1663 return that == s;
1664 }
1665
1669 inline friend bool operator!=(field_value const& that, std::string_view s) {
1670 return !(that == s);
1671 }
1672
1676 inline friend bool operator!=(std::string_view s, field_value const& that) {
1677 return !(that == s);
1678 }
1679#endif
1680
1684 friend std::ostream& operator<<(std::ostream& os, field_value const& that) {
1685 return os.write(that.begin(), that.size());
1686 }
1687
1690
1699 std::string as_string() const {
1700 return std::string(begin(), end());
1701 }
1702
1703#if __cplusplus >= 201703L
1709 std::string_view as_string_view() const {
1710 return std::string_view(begin(), size());
1711 }
1712#endif
1713
1719 char as_char() const {
1720 return *begin();
1721 }
1722
1724
1725
1728
1741 template<typename Int_type> void as_decimal(Int_type& mantissa, Int_type& exponent) const {
1742 details::atod<Int_type>(begin(), end(), mantissa, exponent);
1743 }
1745
1746private:
1747 template <typename Int_type, bool Is_signed_integer>
1748 struct as_int_selector {
1749 };
1750
1751 template <typename Int_type>
1752 struct as_int_selector<Int_type, true> {
1753 static Int_type call_as_int(char const* begin, char const* end) {
1754 return details::atoi<Int_type>(begin, end);
1755 }
1756 };
1757
1758 template <typename Int_type>
1759 struct as_int_selector<Int_type, false> {
1760 static Int_type call_as_int(char const* begin, char const* end) {
1761 return details::atou<Int_type>(begin, end);
1762 }
1763 };
1764
1765public:
1766
1769
1778 template<typename Int_type> Int_type as_int() const {
1779 return as_int_selector<Int_type, std::numeric_limits<Int_type>::is_signed>::call_as_int(begin(), end());
1780 }
1782
1785
1786
1798 int& year,
1799 int& month,
1800 int& day
1801 ) const {
1802 return details::atodate(begin(), end(), year, month, day);
1803 }
1804
1805
1816 int& year,
1817 int& month
1818 ) const {
1819 if (end() - begin() != 6) return false;
1820
1821 year = details::atoi<int>(begin(), begin() + 4);
1822 month = details::atoi<int>(begin() + 4, begin() + 6);
1823
1824 return true;
1825 }
1826
1827
1840 int& hour,
1841 int& minute,
1842 int& second,
1843 int& millisecond
1844 ) const {
1845 return details::atotime(begin(), end(), hour, minute, second, millisecond);
1846 }
1847
1860 int& hour,
1861 int& minute,
1862 int& second,
1863 int& nanosecond
1864 ) const {
1865 return details::atotime_nano(begin(), end(), hour, minute, second, nanosecond);
1866 }
1867
1883 int& year,
1884 int& month,
1885 int& day,
1886 int& hour,
1887 int& minute,
1888 int& second,
1889 int& millisecond
1890 ) const {
1891 return
1892 details::atotime(begin() + 9, end(), hour, minute, second, millisecond)
1893 && details::atodate(begin(), begin() + 8, year, month, day); // take advantage of short-circuit && to check field length
1894 }
1895
1911 int& year,
1912 int& month,
1913 int& day,
1914 int& hour,
1915 int& minute,
1916 int& second,
1917 int& nanosecond
1918 ) const {
1919 return
1920 details::atotime_nano(begin() + 9, end(), hour, minute, second, nanosecond)
1921 && details::atodate(begin(), begin() + 8, year, month, day); // take advantage of short-circuit && to check field length
1922 }
1923
1925
1926#ifdef HFFIX_BOOST_DATETIME
1927
1930
1938 boost::gregorian::date as_date() const {
1939 int year, month, day;
1940 if (as_date(year, month, day)) {
1941 try {
1942 return boost::gregorian::date(year, month, day);
1943 } catch(std::exception& ex) {
1944 return boost::gregorian::date(boost::posix_time::not_a_date_time);
1945 }
1946 } else
1947 return boost::gregorian::date(boost::posix_time::not_a_date_time);
1948 }
1949
1957 boost::posix_time::time_duration as_timeonly() const {
1958 int hour, minute, second, millisecond;
1959 if (as_timeonly(hour, minute, second, millisecond)) {
1960 try {
1961 return boost::posix_time::time_duration(hour, minute, second, boost::posix_time::time_duration::ticks_per_second() * millisecond / 1000);
1962 } catch(std::exception& ex) {
1963 return boost::posix_time::time_duration(boost::posix_time::not_a_date_time);
1964 }
1965 } else
1966 return boost::posix_time::time_duration(boost::posix_time::not_a_date_time);
1967 }
1968
1976 boost::posix_time::time_duration as_timeonly_nano() const {
1977 int hour, minute, second, nanosecond;
1978 if (as_timeonly_nano(hour, minute, second, nanosecond)) {
1979 try {
1980 return boost::posix_time::time_duration(hour, minute, second, boost::posix_time::time_duration::ticks_per_second() * nanosecond / 1000000000L);
1981 } catch(std::exception& ex) {
1982 return boost::posix_time::time_duration(boost::posix_time::not_a_date_time);
1983 }
1984 } else
1985 return boost::posix_time::time_duration(boost::posix_time::not_a_date_time);
1986 }
1987
1995 boost::posix_time::ptime as_timestamp() const {
1996 int year, month, day, hour, minute, second, millisecond;
1997
1998 if (details::atotime(begin() + 9, end(), hour, minute, second, millisecond)
1999 && details::atodate(begin(), begin() + 8, year, month, day)) {
2000 try {
2001 return boost::posix_time::ptime(
2002 boost::gregorian::date(year, month, day),
2003 boost::posix_time::time_duration(hour, minute, second, boost::posix_time::time_duration::ticks_per_second() * millisecond / 1000)
2004 );
2005 } catch(std::exception& ex) {
2006 return boost::posix_time::not_a_date_time;
2007 }
2008 } else
2009 return boost::posix_time::not_a_date_time;
2010 }
2011
2019 boost::posix_time::ptime as_timestamp_nano() const {
2020 int year, month, day, hour, minute, second, nanosecond;
2021
2022 if (details::atotime_nano(begin() + 9, end(), hour, minute, second, nanosecond)
2023 && details::atodate(begin(), begin() + 8, year, month, day)) {
2024 try {
2025 return boost::posix_time::ptime(
2026 boost::gregorian::date(year, month, day),
2027 boost::posix_time::time_duration(hour, minute, second, boost::posix_time::time_duration::ticks_per_second() * nanosecond / 1000000000L)
2028 );
2029 } catch(std::exception& ex) {
2030 return boost::posix_time::not_a_date_time;
2031 }
2032 } else
2033 return boost::posix_time::not_a_date_time;
2034 }
2036
2037
2038#endif // HFFIX_BOOST_DATETIME
2039
2040#if __cplusplus >= 201103L
2043
2057 template<typename Clock, typename Duration>
2058 bool as_timestamp(std::chrono::time_point<Clock,Duration>& tp) const {
2059 if (details::atotimepoint(begin(), end(), tp))
2060 return true;
2061 else
2062 return false;
2063 }
2064
2078 template<typename Clock, typename Duration>
2079 bool as_timestamp_nano(std::chrono::time_point<Clock,Duration>& tp) const {
2080 if (details::atotimepoint_nano(begin(), end(), tp))
2081 return true;
2082 else
2083 return false;
2084 }
2085
2096 template<typename Rep, typename Period>
2097 bool as_timeonly(std::chrono::duration<Rep,Period>& dur) const {
2098 int hour, minute, second, millisecond;
2099 if (as_timeonly(hour, minute, second, millisecond)) {
2100 dur = std::chrono::hours(hour) +
2101 std::chrono::minutes(minute) +
2102 std::chrono::seconds(second) +
2103 std::chrono::milliseconds(millisecond);
2104 return true;
2105 }
2106 else
2107 return false;
2108 }
2109
2120 template<typename Rep, typename Period>
2121 bool as_timeonly_nano(std::chrono::duration<Rep,Period>& dur) const {
2122 int hour, minute, second, nanosecond;
2123 if (as_timeonly_nano(hour, minute, second, nanosecond)) {
2124 dur = std::chrono::hours(hour) +
2125 std::chrono::minutes(minute) +
2126 std::chrono::seconds(second) +
2127 std::chrono::nanoseconds(nanosecond);
2128 return true;
2129 }
2130 else
2131 return false;
2132 }
2134#endif
2135
2136
2137private:
2138 friend class field;
2139 friend class message_reader_const_iterator;
2140 friend class message_reader;
2141 char const* begin_;
2142 char const* end_;
2143};
2144
2150class field {
2151public:
2152
2154 int tag() const {
2155 return tag_;
2156 }
2157
2159 field_value const& value() const {
2160 return value_;
2161 }
2162
2164 friend std::ostream& operator<<(std::ostream& os, field const& that) {
2165 os << that.tag_ << "=";
2166 return os.write(that.value_.begin(), that.value_.size());
2167 }
2168
2169private:
2170 friend class message_reader_const_iterator;
2171 friend class message_reader;
2172 int tag_;
2173 field_value value_;
2174};
2175
2182
2183public:
2184
2190private:
2191
2192 message_reader_const_iterator(message_reader const& container, char const* buffer) :
2193 message_reader_(&container),
2194 buffer_(buffer),
2195 current_() {
2196 }
2197
2198public:
2199
2201 typedef ::std::input_iterator_tag iterator_category;
2205 typedef std::ptrdiff_t difference_type;
2207 typedef field* pointer;
2210
2211
2215 field const& operator*() const {
2216 return current_;
2217 }
2218
2222 field const* operator->() const {
2223 return &current_;
2224 }
2225
2226
2229 return a.buffer_ == b.buffer_;
2230 }
2231
2234 return a.buffer_ != b.buffer_;
2235 }
2236
2239 return a.buffer_ < b.buffer_;
2240 }
2241
2244 return a.buffer_ > b.buffer_;
2245 }
2246
2249 return a.buffer_ <= b.buffer_;
2250 }
2251
2254 return a.buffer_ >= b.buffer_;
2255 }
2256
2260 ++(*this);
2261 return i;
2262 }
2263
2266 increment();
2267 return *this;
2268 }
2269
2279 if (addend < 0) throw std::logic_error("message_reader::const_iterator is a Forward Iterator, so only positive addends are allowed.");
2280 for (int i = 0; i < addend; ++i)
2281 ++a;
2282
2283 return a;
2284 }
2285
2286
2289 return a + addend;
2290 }
2291
2292private:
2293 friend class message_reader;
2294 message_reader const* message_reader_; // pointer to the message_reader for this iterator
2295 char const* buffer_; // pointer to the first character of the ascii tag number for the current_ field
2296 field current_;
2297
2298 void increment();
2299};
2300
2301
2306 tag_equal(int tag) : tag(tag) {}
2307 int tag;
2308 bool operator()(field const& v) const {
2309 return v.tag() == tag;
2310 }
2311};
2312
2313
2351template <typename ForwardIterator, typename UnaryPredicate>
2352inline bool find_with_hint(ForwardIterator begin, ForwardIterator end, UnaryPredicate predicate, ForwardIterator & i) {
2353 ForwardIterator j = std::find_if(i, end, predicate);
2354 if (j != end) {
2355 i = j;
2356 return true;
2357 }
2358 j = std::find_if(begin, i, predicate);
2359 if (j != i) {
2360 i = j;
2361 return true;
2362 }
2363 return false;
2364}
2365
2366
2397
2398public:
2399
2400 typedef field value_type;
2401 typedef field const& const_reference;
2403 typedef field const* const_pointer;
2404 typedef size_t size_type;
2405
2411 message_reader(char const* buffer, size_t size) :
2412 buffer_(buffer),
2413 buffer_end_(buffer + size),
2414 begin_(*this, 0),
2415 end_(*this, 0),
2416 is_complete_(false),
2417 is_valid_(true) {
2418 init();
2419 }
2420
2426 message_reader(char const* begin, char const* end) :
2427 buffer_(begin),
2428 buffer_end_(end),
2429 begin_(*this, 0),
2430 end_(*this, 0),
2431 is_complete_(false),
2432 is_valid_(true) {
2433 init();
2434 }
2435
2440 buffer_(that.buffer_),
2441 buffer_end_(that.buffer_end_),
2442 begin_(*this, 0),
2443 end_(*this, 0),
2444 is_complete_(that.is_complete_),
2445 is_valid_(that.is_valid_) {
2446 init();
2447 }
2448
2453 {
2454 buffer_= that.buffer_;
2455 buffer_end_ = that.buffer_end_;
2456 // This can't be the default assignment operator because begin_ and end_ are const_iterators which
2457 // point back to 'this'. If we copy them as is they will point back to the previous 'that'.
2458 begin_ = const_iterator(*this, 0);
2459 end_ = const_iterator(*this, 0);
2460 is_complete_ = that.is_complete_;
2461 is_valid_ = that.is_valid_;
2462 init();
2463 return *this;
2464 }
2465
2474 buffer_(that.message_begin()),
2475 buffer_end_(that.message_end()),
2476 begin_(*this, 0),
2477 end_(*this, 0),
2478 is_complete_(false),
2479 is_valid_(true) {
2480 init();
2481 }
2482
2488 template<size_t N>
2489 message_reader(const char(&buffer)[N]) :
2490 buffer_(buffer),
2491 buffer_end_(&(buffer[N])),
2492 begin_(*this, 0),
2493 end_(*this, 0),
2494 is_complete_(false),
2495 is_valid_(true) {
2496 init();
2497 }
2498
2503 }
2504
2508 bool is_complete() const {
2509 return is_complete_;
2510 }
2526 bool is_valid() const {
2527 return is_valid_;
2528 }
2529
2530
2544 if (!is_complete_) {
2545 throw std::logic_error("Can't call next_message_reader on an incomplete message.");
2546 }
2547
2548 if (!is_valid_) { // this message isn't valid, so we have to try to search for the beginning of the next message.
2549 char const* b = buffer_ + 1;
2550 while(b < buffer_end_ - 10) {
2551 if (!std::memcmp(b, "8=FIX", 5))
2552 break;
2553 ++b;
2554 }
2555 return message_reader(b, buffer_end_);
2556 }
2557
2558 return message_reader(end_.current_.value_.end_ + 1, buffer_end_);
2559 }
2560
2581 unsigned char calculate_check_sum() {
2582 // return iterator for beginning of nonmutable sequence
2583 if (!is_valid_) throw std::logic_error("hffix Cannot calculate checksum for an invalid message.");
2584 return std::accumulate(buffer_, end_.buffer_, (unsigned char)(0));
2585 }
2586
2594 // return iterator for beginning of nonmutable sequence
2595 if (!is_valid_) throw std::logic_error("hffix Cannot return iterator for an invalid message.");
2596 return begin_;
2597 }
2598
2604 // return iterator for end of nonmutable sequence
2605 if (!is_valid_) throw std::logic_error("hffix Cannot return iterator for an invalid message.");
2606 return end_;
2607 }
2608
2614 // return iterator for beginning of nonmutable sequence
2615 if (!is_valid_) throw std::logic_error("hffix Cannot return iterator for an invalid message.");
2616 return begin_;
2617 }
2618
2624 // return iterator for end of nonmutable sequence
2625 if (!is_valid_) throw std::logic_error("hffix Cannot return iterator for an invalid message.");
2626 return end_;
2627 }
2628
2632 char const* prefix_begin() const {
2633 return buffer_ + 2;
2634 }
2635
2639 char const* prefix_end() const {
2640 return prefix_end_;
2641 }
2642
2646 size_t prefix_size() const {
2647 return prefix_end_ - buffer_ - 2;
2648 }
2649
2670 bool find_with_hint(int tag, const_iterator& i) const {
2671 return hffix::find_with_hint(begin(), end(), tag_equal(tag), i);
2672 }
2673
2675
2676
2684 char const* buffer_begin() const {
2685 return buffer_;
2686 }
2690 char const* buffer_end() const {
2691 return buffer_end_;
2692 }
2693
2697 size_t buffer_size() const {
2698 return buffer_end_ - buffer_;
2699 }
2700
2708 char const* message_begin() const {
2709 return buffer_;
2710 }
2715 char const* message_end() const {
2716 if (!is_valid_) throw std::logic_error("hffix Cannot determine size of an invalid message.");
2717 return end_.current_.value_.end_ + 1;
2718 }
2719
2724 size_t message_size() const {
2725 if (!is_valid_) throw std::logic_error("hffix Cannot determine size of an invalid message.");
2726 return end_.current_.value_.end_ - buffer_ + 1;
2727 }
2728
2730
2731private:
2732 friend class message_reader_const_iterator;
2733
2734 void init() {
2735
2736 // Skip the version prefix string "8=FIX.4.2" or "8=FIXT.1.1", et cetera.
2737 char const* b = buffer_ + 9; // look for the first '\x01'
2738
2739 while(true) {
2740 if (b >= buffer_end_) {
2741 is_complete_ = false;
2742 return;
2743 }
2744 if (*b == '\x01') {
2745 prefix_end_ = b;
2746 break;
2747 }
2748 if (b - buffer_ > 11) {
2749 invalid();
2750 return;
2751 }
2752 ++b;
2753 }
2754
2755 if (b + 1 >= buffer_end_) {
2756 is_complete_ = false;
2757 return;
2758 }
2759 if (b[1] != '9') { // next field must be tag 9 BodyLength
2760 invalid();
2761 return;
2762 }
2763 b += 3; // skip the " 9=" for tag 9 BodyLength
2764
2765 size_t bodylength(0); // the value of tag 9 BodyLength
2766
2767 while(true) {
2768 if (b >= buffer_end_) {
2769 is_complete_ = false;
2770 return;
2771 }
2772 if (*b == '\x01') break;
2773 if (*b < '0' || *b > '9') { // this is the only time we need to check for numeric ascii.
2774 invalid();
2775 return;
2776 }
2777 bodylength *= 10;
2778 bodylength += *b++ - '0'; // we know that 0 <= (*b - '0') <= 9, so rvalue will be positive.
2779 }
2780
2781 ++b;
2782 if (b + 3 >= buffer_end_) {
2783 is_complete_ = false;
2784 return;
2785 }
2786
2787 if (*b != '3' || b[1] != '5') { // next field must be tag 35 MsgType
2788 invalid();
2789 return;
2790 }
2791
2792 char const* checksum = b + bodylength;
2793
2794 if (checksum + 7 > buffer_end_) {
2795 is_complete_ = false;
2796 return;
2797 }
2798
2799 if (*(checksum - 1) != '\x01') { // check for SOH before the checksum.
2800 // this guarantees that at least
2801 // there is one SOH in the message
2802 // which will prevent us from
2803 // falling off of the end of
2804 // a malformed message while
2805 // iterating.
2806 invalid();
2807 return;
2808 }
2809
2810 if (*(checksum + 6) != '\x01') { // check for trailing SOH
2811 invalid();
2812 return;
2813 }
2814
2815 begin_.buffer_ = b;
2816 begin_.current_.tag_ = 35; // MsgType
2817 b += 3;
2818 begin_.current_.value_.begin_ = b;
2819 while(*++b != '\x01') {
2820 if (b >= checksum) {
2821 invalid();
2822 return;
2823 }
2824 }
2825 begin_.current_.value_.end_ = b;
2826
2827 end_.buffer_ = checksum;
2828 end_.current_.tag_ = 10; //CheckSum
2829 end_.current_.value_.begin_ = checksum + 3;
2830 end_.current_.value_.end_ = checksum + 6;
2831
2832 is_complete_ = true;
2833 }
2834
2835 char const* buffer_;
2836 char const* buffer_end_;
2837 const_iterator begin_;
2838 const_iterator end_;
2839 bool is_complete_;
2840 bool is_valid_;
2841 char const* prefix_end_; // Points after the 8=FIX... Prefix field.
2842
2843 void invalid() {
2844 is_complete_ = true; // invalid messages are considered complete, for use of the message_reader::operator++()
2845 is_valid_ = false;
2846 }
2847};
2848
2849
2851namespace details {
2852bool is_tag_a_data_length(int tag);
2853}
2857inline void message_reader_const_iterator::increment()
2858{
2859 buffer_ = current_.value_.end_ + 1;
2860 current_.value_.begin_ = buffer_;
2861 current_.tag_ = 0;
2862
2863 while(*current_.value_.begin_ != '=' && *current_.value_.begin_ != '\x01') {
2864 current_.tag_ *= 10;
2865 current_.tag_ += (*current_.value_.begin_ - '0');
2866 ++current_.value_.begin_;
2867 }
2868
2869 // we expect to see a '='. if we see a '\x01' at this point then this field
2870 // has no value and the message is invalid, so we're doomed. it's too
2871 // late to set is_invalid, though, so let's just say that this field
2872 // has a null value.
2873 if (*current_.value_.begin_ == '\x01') {
2874 current_.value_.end_ = current_.value_.begin_;
2875 return;
2876 }
2877
2878 // move past the '='.
2879 ++current_.value_.begin_;
2880
2881 // find the end of the field value
2882 current_.value_.end_ = std::find(current_.value_.begin_, message_reader_->message_end(), '\x01');
2883 if (details::is_tag_a_data_length(current_.tag_)) {
2884 size_t data_len = details::atou<size_t>(current_.value_.begin_, current_.value_.end_);
2885
2886 buffer_ = current_.value_.end_ + 1;
2887 current_.value_.begin_ = buffer_;
2888 current_.tag_ = 0;
2889
2890 while(*current_.value_.begin_ != '=') {
2891 current_.tag_ *= 10;
2892 current_.tag_ += (*current_.value_.begin_ - '0');
2893 ++current_.value_.begin_;
2894 }
2895
2896 current_.value_.end_ = ++current_.value_.begin_ + data_len;
2897 }
2898}
2899
2900/* @cond EXCLUDE */
2901
2902namespace details {
2903
2904
2905// A predicate constructed with an int which returns true if the int passed to
2906// the predicate is greater than or equal to the int passed to the constructor.
2907struct int_gte {
2908 int_gte(int tag) : tag(tag) {}
2909 int tag;
2910 bool operator()(int that) const {
2911 return that >= tag;
2912 }
2913};
2914
2915// Returns true if the argument exists in the length_fields array.
2916//
2917// We have to call this function every time a message_reader iterator
2918// is incremented, so we want it to be fast.
2919//
2920// Instead of doing std::binary_search on the sorted range of length_fields,
2921// we'll take advantage of an assumption that most tags are low-numbered
2922// tags, and search from the beginning of length_fields, hoping that
2923// our search will usually end quickly.
2924//
2925// TODO: This has not yet been benchmarked against any alternatives.
2926// The benchmark results would depend on the distrubution of tags
2927// in the FIX data set.
2928inline bool is_tag_a_data_length(int tag)
2929{
2930 int* length_fields_end = length_fields + (sizeof(length_fields)/sizeof(length_fields[0]));
2931 int* i = std::find_if(length_fields, length_fields_end, int_gte(tag));
2932 if (i == length_fields_end) return false;
2933 return (*i == tag);
2934}
2935
2936// \brief std::ostream-able type returned by hffix::field_name function.
2937template <typename AssociativeContainer> struct field_name_streamer {
2938 int tag;
2939 AssociativeContainer const& field_dictionary;
2940 bool number_alternative;
2941
2942 field_name_streamer(int tag, AssociativeContainer const& field_dictionary, bool number_alternative) : tag(tag), field_dictionary(field_dictionary), number_alternative(number_alternative) {}
2943
2944 friend std::ostream& operator<<(std::ostream& os, field_name_streamer that) {
2945 typename AssociativeContainer::const_iterator i = that.field_dictionary.find(that.tag);
2946 if (i != that.field_dictionary.end())
2947 os << i->second;
2948 else if (that.number_alternative)
2949 os << that.tag;
2950 return os;
2951 }
2952};
2953
2954}
2955/* @endcond */
2956
2974template <typename AssociativeContainer> details::field_name_streamer<AssociativeContainer> field_name(int tag, AssociativeContainer const& field_dictionary, bool or_number = true)
2975{
2976 return details::field_name_streamer<AssociativeContainer>(tag, field_dictionary, or_number);
2977}
2978
2979} // namespace hffix
2980
2981#endif
FIX field value for hffix::message_reader.
Definition hffix.hpp:1575
friend bool operator==(std::string_view s, field_value const &that)
True if the value of the field is equal to the string_view argument.
Definition hffix.hpp:1662
char const * begin() const
Pointer to the beginning of the field value in the buffer.
Definition hffix.hpp:1579
std::string_view as_string_view() const
Ascii value as std::string_view.
Definition hffix.hpp:1709
friend bool operator==(char const *cstring, field_value const &that)
True if the value of the field is equal to the C-string argument.
Definition hffix.hpp:1605
boost::posix_time::time_duration as_timeonly_nano() const
Ascii-to-time conversion with nanosecond precision.
Definition hffix.hpp:1976
bool as_timeonly(int &hour, int &minute, int &second, int &millisecond) const
Ascii-to-time conversion with millisecond precision.
Definition hffix.hpp:1839
friend bool operator!=(field_value const &that, std::string const &s)
True if the value of the field is not equal to the string argument.
Definition hffix.hpp:1640
friend bool operator==(field_value const &that, std::string_view s)
True if the value of the field is equal to the string_view argument.
Definition hffix.hpp:1655
bool as_timeonly_nano(std::chrono::duration< Rep, Period > &dur) const
Ascii-to-time conversion with nanosecond precision.
Definition hffix.hpp:2121
bool as_monthyear(int &year, int &month) const
Ascii-to-month-year conversion.
Definition hffix.hpp:1815
boost::posix_time::time_duration as_timeonly() const
Ascii-to-time conversion with millisecond precision.
Definition hffix.hpp:1957
bool as_date(int &year, int &month, int &day) const
Ascii-to-date conversion.
Definition hffix.hpp:1797
bool as_timestamp_nano(std::chrono::time_point< Clock, Duration > &tp) const
Ascii-to-time-point conversion with nanosecond precision.
Definition hffix.hpp:2079
std::string as_string() const
Ascii value as std::string.
Definition hffix.hpp:1699
friend bool operator!=(std::string const &s, field_value const &that)
True if the value of the field is not equal to the string argument.
Definition hffix.hpp:1647
char as_char() const
Ascii value as char.
Definition hffix.hpp:1719
bool as_timestamp(std::chrono::time_point< Clock, Duration > &tp) const
Ascii-to-time-point conversion with millisecond precision.
Definition hffix.hpp:2058
bool as_timeonly_nano(int &hour, int &minute, int &second, int &nanosecond) const
Ascii-to-time conversion with nanosecond precision.
Definition hffix.hpp:1859
friend bool operator==(std::string const &s, field_value const &that)
True if the value of the field is equal to the string argument.
Definition hffix.hpp:1633
boost::posix_time::ptime as_timestamp() const
Ascii-to-timestamp conversion with millisecond precision.
Definition hffix.hpp:1995
bool as_timestamp(int &year, int &month, int &day, int &hour, int &minute, int &second, int &millisecond) const
Ascii-to-timestamp conversion with millisecond precision.
Definition hffix.hpp:1882
boost::gregorian::date as_date() const
Ascii-to-date conversion.
Definition hffix.hpp:1938
void as_decimal(Int_type &mantissa, Int_type &exponent) const
Ascii-to-decimal conversion.
Definition hffix.hpp:1741
Int_type as_int() const
Ascii-to-integer conversion.
Definition hffix.hpp:1778
size_t size() const
Size of the field value, in bytes.
Definition hffix.hpp:1589
friend bool operator!=(char const *cstring, field_value const &that)
True if the value of the field is not equal to the C-string argument.
Definition hffix.hpp:1619
friend bool operator!=(field_value const &that, char const *cstring)
True if the value of the field is not equal to the C-string argument.
Definition hffix.hpp:1612
friend std::ostream & operator<<(std::ostream &os, field_value const &that)
Stream out the raw text value of the field.
Definition hffix.hpp:1684
friend bool operator!=(std::string_view s, field_value const &that)
True if the value of the field is not equal to the string_view argument.
Definition hffix.hpp:1676
boost::posix_time::ptime as_timestamp_nano() const
Ascii-to-timestamp conversion with nanosecond precision.
Definition hffix.hpp:2019
friend bool operator!=(field_value const &that, std::string_view s)
True if the value of the field is not equal to the string_view argument.
Definition hffix.hpp:1669
friend bool operator==(field_value const &that, std::string const &s)
True if the value of the field is equal to the string argument.
Definition hffix.hpp:1626
bool as_timeonly(std::chrono::duration< Rep, Period > &dur) const
Ascii-to-time conversion.
Definition hffix.hpp:2097
bool as_timestamp_nano(int &year, int &month, int &day, int &hour, int &minute, int &second, int &nanosecond) const
Ascii-to-timestamp conversion with nanosecond precision.
Definition hffix.hpp:1910
char const * end() const
Pointer to past-the-end of the field value in the buffer.
Definition hffix.hpp:1584
friend bool operator==(field_value const &that, char const *cstring)
True if the value of the field is equal to the C-string argument.
Definition hffix.hpp:1597
A FIX field for hffix::message_reader, with tag and hffix::field_value.
Definition hffix.hpp:2150
friend std::ostream & operator<<(std::ostream &os, field const &that)
Output stream operator. Output format is "[tag number]=[value]".
Definition hffix.hpp:2164
int tag() const
Tag of the field.
Definition hffix.hpp:2154
field_value const & value() const
Weakly-typed value of the field.
Definition hffix.hpp:2159
The iterator type for hffix::message_reader. Typedef'd as hffix::message_reader::const_iterator.
Definition hffix.hpp:2181
friend bool operator==(message_reader_const_iterator const &a, message_reader_const_iterator const &b)
Equal.
Definition hffix.hpp:2228
field const & operator*() const
Returns a hffix::message_reader::const_reference to a field.
Definition hffix.hpp:2215
field & reference
For std::iterator_traits.
Definition hffix.hpp:2209
field * pointer
For std::iterator_traits.
Definition hffix.hpp:2207
field value_type
For std::iterator_traits.
Definition hffix.hpp:2203
friend bool operator>=(message_reader_const_iterator const &a, message_reader_const_iterator const &b)
Greater-than or equal.
Definition hffix.hpp:2253
friend bool operator<(message_reader_const_iterator const &a, message_reader_const_iterator const &b)
Less-than.
Definition hffix.hpp:2238
std::ptrdiff_t difference_type
For std::iterator_traits.
Definition hffix.hpp:2205
field const * operator->() const
Returns a hffix::message_reader::const_pointer to a field.
Definition hffix.hpp:2222
friend bool operator<=(message_reader_const_iterator const &a, message_reader_const_iterator const &b)
Less-than or equal.
Definition hffix.hpp:2248
friend message_reader_const_iterator operator+(int addend, message_reader_const_iterator a)
Addition.
Definition hffix.hpp:2288
message_reader_const_iterator operator++(int)
Postfix increment.
Definition hffix.hpp:2258
friend message_reader_const_iterator operator+(message_reader_const_iterator a, int addend)
Addition.
Definition hffix.hpp:2278
message_reader_const_iterator & operator++()
Prefix increment.
Definition hffix.hpp:2265
::std::input_iterator_tag iterator_category
For std::iterator_traits.
Definition hffix.hpp:2201
friend bool operator>(message_reader_const_iterator const &a, message_reader_const_iterator const &b)
Greater-than.
Definition hffix.hpp:2243
friend bool operator!=(message_reader_const_iterator const &a, message_reader_const_iterator const &b)
Not equal.
Definition hffix.hpp:2233
One FIX message for reading.
Definition hffix.hpp:2396
size_t message_size() const
The entire size of the FIX message in bytes.
Definition hffix.hpp:2724
message_reader(message_reader const &that)
Copy constructor. The hffix::message_reader is immutable, so copying it is fine.
Definition hffix.hpp:2439
~message_reader()
Owns no resources, so destruction is no-op.
Definition hffix.hpp:2502
char const * message_begin() const
A pointer to the beginning of the FIX message in the buffer.
Definition hffix.hpp:2708
message_reader & operator=(const message_reader &that)
Copy assignment operator. The hffix::message_reader is immutable, so copying it is fine.
Definition hffix.hpp:2452
char const * message_end() const
A pointer to past-the-end of the FIX message in the buffer.
Definition hffix.hpp:2715
bool find_with_hint(int tag, const_iterator &i) const
Convenient synonym for hffix::find_with_hint(reader.begin(), reader.end(), hffix::tag_equal(tag),...
Definition hffix.hpp:2670
size_t buffer_size() const
The size of the buffer in bytes.
Definition hffix.hpp:2697
char const * buffer_end() const
A pointer to past-the-end of the buffer.
Definition hffix.hpp:2690
size_t prefix_size() const
Returns the FIX version prefix BeginString field value size. (Example: returns 7 for "FIX....
Definition hffix.hpp:2646
message_reader next_message_reader() const
Returns a new message_reader for the next FIX message in the buffer.
Definition hffix.hpp:2543
const_iterator end() const
An iterator to the CheckSum field in the FIX message. Same as hffix::message_reader::check_sum().
Definition hffix.hpp:2603
message_reader(char const *buffer, size_t size)
Construct by buffer size.
Definition hffix.hpp:2411
const_iterator message_type() const
An iterator to the MsgType field in the FIX message. Same as hffix::message_reader::begin().
Definition hffix.hpp:2613
message_reader(const char(&buffer)[N])
Construct on an array reference to a buffer.
Definition hffix.hpp:2489
char const * prefix_end() const
Returns the FIX version prefix BeginString field value end pointer.
Definition hffix.hpp:2639
bool is_valid() const
True if the message is valid.
Definition hffix.hpp:2526
message_reader(char const *begin, char const *end)
Construct by buffer begin and end.
Definition hffix.hpp:2426
char const * prefix_begin() const
Returns the FIX version prefix BeginString field value begin pointer. (Example: "FIX....
Definition hffix.hpp:2632
bool is_complete() const
True if the buffer contains a complete FIX message.
Definition hffix.hpp:2508
char const * buffer_begin() const
A pointer to the begining of the buffer.
Definition hffix.hpp:2684
message_reader(message_writer const &that)
Construct a message_reader from a message_writer. Equivalent to.
Definition hffix.hpp:2473
unsigned char calculate_check_sum()
Calulate the checksum for this message.
Definition hffix.hpp:2581
const_iterator begin() const
An iterator to the MsgType field in the FIX message. Same as hffix::message_reader::message_type().
Definition hffix.hpp:2593
const_iterator check_sum() const
An iterator to the CheckSum field in the FIX message. Same as hffix::message_reader::end().
Definition hffix.hpp:2623
One FIX message for writing.
Definition hffix.hpp:622
void push_back_date(int tag, boost::gregorian::date date)
Append a LocalMktDate or UTCDate field to the message.
Definition hffix.hpp:1267
void push_back_timeonly(int tag, int hour, int minute, int second)
Append a UTCTimeOnly field to the message.
Definition hffix.hpp:1040
void push_back_timestamp(int tag, int year, int month, int day, int hour, int minute, int second)
Append a UTCTimestamp field to the message.
Definition hffix.hpp:1140
void push_back_timeonly(int tag, boost::posix_time::time_duration timeonly)
Append a UTCTimeOnly field to the message with millisecond precision.
Definition hffix.hpp:1286
void push_back_data(int tag_data_length, int tag_data, char const *begin, char const *end)
Append a data length field and a data field to the message.
Definition hffix.hpp:1513
void push_back_timeonly_nano(int tag, std::chrono::duration< Rep, Period > timeonly)
Append a UTCTimeOnly field to the message with nanosecond precision.
Definition hffix.hpp:1470
void push_back_header(char const *begin_string_version)
Write the BeginString and BodyLength fields to the buffer.
Definition hffix.hpp:727
size_t buffer_size() const
Total available buffer size, including buffer already written to by this message.
Definition hffix.hpp:700
size_t buffer_size_remaining() const
Remaining available buffer size. Excludes buffer already written to by this message.
Definition hffix.hpp:707
void push_back_string(int tag, std::string const &s)
Append a string field to the message.
Definition hffix.hpp:886
void push_back_header(std::string_view begin_string_version)
Write the BeginString and BodyLength fields to the buffer.
Definition hffix.hpp:756
void push_back_trailer(bool calculate_checksum=true)
Write the CheckSum field to the buffer.
Definition hffix.hpp:790
void push_back_timestamp_nano(int tag, boost::posix_time::ptime timestamp)
Append a UTCTimestamp field to the message with nanosecond precision.
Definition hffix.hpp:1366
void push_back_timeonly(int tag, std::chrono::duration< Rep, Period > timeonly)
Append a UTCTimeOnly field to the message with millisecond precision.
Definition hffix.hpp:1445
void push_back_timestamp_nano(int tag, int year, int month, int day, int hour, int minute, int second, int nanosecond)
Append a UTCTimestamp field to the message with nanosecond precision.
Definition hffix.hpp:1224
void push_back_timeonly_nano(int tag, int hour, int minute, int second, int nanosecond)
Append a UTCTimeOnly field to the message with up to nanosecond precision.
Definition hffix.hpp:1103
void push_back_timestamp_nano(int tag, std::chrono::time_point< Clock, Duration > tp)
Append a std::chrono::time_point field to the message with nanosecond precision.
Definition hffix.hpp:1425
void push_back_timeonly_nano(int tag, boost::posix_time::time_duration timeonly)
Append a UTCTimeOnly field to the message with nanosecond precision.
Definition hffix.hpp:1311
message_writer(char *begin, char *end)
Construct by buffer begin and end.
Definition hffix.hpp:642
void push_back_int(int tag, Int_type number)
Append an integer field to the message.
Definition hffix.hpp:937
void push_back_monthyear(int tag, int year, int month)
Append a month-year field to the message.
Definition hffix.hpp:1013
void push_back_timeonly(int tag, int hour, int minute, int second, int millisecond)
Append a UTCTimeOnly field to the message with millisecond precision.
Definition hffix.hpp:1070
message_writer(char(&buffer)[N])
Construct on an array reference to a buffer.
Definition hffix.hpp:655
void push_back_date(int tag, int year, int month, int day)
Append a LocalMktDate or UTCDate field to the message.
Definition hffix.hpp:990
void push_back_string(int tag, char const *cstring)
Append a string field to the message.
Definition hffix.hpp:867
void push_back_timestamp(int tag, int year, int month, int day, int hour, int minute, int second, int millisecond)
Append a UTCTimestamp field to the message with millisecond precision.
Definition hffix.hpp:1181
~message_writer()
Owns no resources, so destruction is no-op.
Definition hffix.hpp:666
char * message_end() const
Pointer to past-the-end of the message.
Definition hffix.hpp:693
void push_back_string(int tag, std::string_view s)
Append a string field to the message.
Definition hffix.hpp:902
void push_back_string(int tag, char const *begin, char const *end)
Append a string field to the message.
Definition hffix.hpp:848
void push_back_decimal(int tag, Int_type mantissa, Int_type exponent)
Append a decimal float field to the message.
Definition hffix.hpp:966
char * message_begin() const
Pointer to beginning of the message.
Definition hffix.hpp:685
size_t message_size() const
Size of the message in bytes.
Definition hffix.hpp:676
void push_back_char(int tag, char character)
Append a char field to the message.
Definition hffix.hpp:915
void push_back_timestamp(int tag, std::chrono::time_point< Clock, Duration > tp)
Append a std::chrono::time_point field to the message with millisecond precision.
Definition hffix.hpp:1403
void push_back_timestamp(int tag, boost::posix_time::ptime timestamp)
Append a UTCTimestamp field to the message with millisecond precision.
Definition hffix.hpp:1336
message_writer(char *buffer, size_t size)
Construct by buffer size.
Definition hffix.hpp:630
The hffix_fields.hpp file is generated by the fixspec/spec-parse-fields Haskell program from the FIX ...
int length_fields[]
Sorted list of all field tags which are of type Length.
Namespace for all types and functions of High Frequency FIX Parser.
Definition hffix.hpp:65
details::field_name_streamer< AssociativeContainer > field_name(int tag, AssociativeContainer const &field_dictionary, bool or_number=true)
Given a field tag number and a field name dictionary, returns a type which provides operator<< to wri...
Definition hffix.hpp:2974
bool find_with_hint(ForwardIterator begin, ForwardIterator end, UnaryPredicate predicate, ForwardIterator &i)
An algorithm similar to std::find_if for forward-searching over a range and finding items which match...
Definition hffix.hpp:2352
A predicate constructed with a FIX tag which returns true if the tag of the hffix::field passed to th...
Definition hffix.hpp:2305