32 #include <string_view>
35 #include "core/compiler/builtin_functions.h"
36 #include "core/compiler/unused.h"
37 #include "core/compiler/hints_branch_predictor.h"
38 #include "core/compiler/hints_hot_code.h"
40 #include "core/os/assert_msg.h"
42 #include "core/utilities/converters.h"
43 #include "core/utilities/object_cache.h"
45 #include "electronic_trading/common/fixed_point.h"
46 #include "electronic_trading/session/sequence_store.h"
48 #include "fix_constants.h"
49 #include "fix_string.h"
50 #include "fix_session_settings.h"
51 #include "fix_utilities.h"
71 enum class FixMessageComponent
81 FixString* value =
nullptr;
83 std::size_t tag_str_length=0;
86 struct OutgoingStaticValue
90 std::size_t tag_str_length=0;
106 bool initialise(FixSessionSettings* session_settings_instance,
SequenceStore* session_sequence_store_instance)
108 m_session_settings = session_settings_instance;
109 m_session_sequence_store = session_sequence_store_instance;
111 m_body_vector.reserve(INITIAL_BODY_TAG_PLACEHOLDER_COUNT);
113 for (std::size_t i = 0; i < INITIAL_BODY_TAG_PLACEHOLDER_COUNT; i++)
115 add_placeholder_to_body_vector();
118 m_header_vector.reserve(INITIAL_BODY_TAG_PLACEHOLDER_COUNT);
120 for (std::size_t i = 0; i < INITIAL_BODY_TAG_PLACEHOLDER_COUNT; i++)
122 add_placeholder_to_header_vector();
125 m_trailer_vector.reserve(INITIAL_BODY_TAG_PLACEHOLDER_COUNT);
127 for (std::size_t i = 0; i < INITIAL_BODY_TAG_PLACEHOLDER_COUNT; i++)
129 add_placeholder_to_trailer_vector();
132 return m_fix_string_cache.create(256);
161 m_msg_type_len = buffer.length();
162 assert(m_msg_type_len <= FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH);
163 llfix_builtin_memcpy(m_msg_type, buffer.data(), m_msg_type_len);
191 template<FixMessageComponent component = FixMessageComponent::BODY,
typename T>
192 void set_tag(uint32_t tag, T val, std::size_t decimal_points = 0)
194 FixString* str_value = m_fix_string_cache.allocate();
196 if constexpr (std::is_same_v<T, const char*>)
198 LLFIX_UNUSED(decimal_points);
199 str_value->copy_from(val);
201 else if constexpr (std::is_same_v<T, std::string>)
203 LLFIX_UNUSED(decimal_points);
204 str_value->copy_from(val.c_str());
206 else if constexpr (std::is_same_v<T, char>)
208 LLFIX_UNUSED(decimal_points);
209 str_value->copy_from(val);
211 else if constexpr (std::is_same_v<T, std::string_view>)
213 LLFIX_UNUSED(decimal_points);
214 str_value->copy_from(val);
216 else if constexpr (std::is_same_v<T, FixString*>)
218 LLFIX_UNUSED(decimal_points);
219 str_value->copy_from(val->to_string_view());
221 else if constexpr (std::is_same_v<T, bool>)
223 LLFIX_UNUSED(decimal_points);
224 str_value->data()[0] = val ==
true ? FixConstants::FIX_BOOLEAN_TRUE : FixConstants::FIX_BOOLEAN_FALSE;
225 str_value->set_length(1);
227 else if constexpr (std::is_same_v<T, FixedPoint>)
229 LLFIX_UNUSED(decimal_points);
230 auto len = val.to_chars(str_value->data());
231 str_value->set_length(
static_cast<uint32_t
>(len));
233 else if constexpr (std::is_floating_point<T>::value)
235 llfix_assert_msg(decimal_points > 0,
"When you pass double/float to set_tag, you should also specify decimal points");
236 auto length = Converters::double_to_chars(val, str_value->data(), str_value->capacity(), decimal_points);
237 str_value->set_length(
static_cast<uint32_t
>(length));
239 else if constexpr (std::is_integral<T>::value && std::is_signed<T>::value)
241 LLFIX_UNUSED(decimal_points);
242 auto length = Converters::int_to_chars(val, str_value->data());
243 str_value->set_length(
static_cast<uint32_t
>(length));
245 else if constexpr (std::is_integral<T>::value &&
sizeof(T) ==
sizeof(uint64_t))
247 LLFIX_UNUSED(decimal_points);
248 auto length = Converters::unsigned_int_to_chars<uint64_t>(val, str_value->data());
249 str_value->set_length(
static_cast<uint32_t
>(length));
251 else if constexpr (std::is_integral<T>::value &&
sizeof(T) ==
sizeof(uint32_t))
253 LLFIX_UNUSED(decimal_points);
254 auto length = Converters::unsigned_int_to_chars<uint32_t>(val, str_value->data());
255 str_value->set_length(
static_cast<uint32_t
>(length));
259 static_assert(always_false_v<T>,
"set_tag unsupported type");
262 set_tag_internal<component>(tag, str_value);
276 template<FixMessageComponent component = FixMessageComponent::BODY>
279 FixString* str_value = m_fix_string_cache.allocate();
280 str_value->copy_from(buffer, data_length);
281 set_tag_internal<component>(tag, str_value);
297 template<FixMessageComponent component = FixMessageComponent::BODY>
300 if (m_fix_string_send_time_set ==
false)
302 FixUtilities::encode_current_time(&m_fix_string_send_time, m_session_settings->timestamp_subseconds_precision);
303 m_fix_string_send_time_set =
true;
306 set_tag_internal<component>(tag, &m_fix_string_send_time);
309 void set_additional_static_header_tag(uint32_t tag,
const std::string& val)
311 OutgoingStaticValue node;
315 node.tag_str_length = Converters::unsigned_int_to_chars<uint32_t>(node.tag, &(node.tag_str[0]));
317 m_additional_static_header_tags.push_back(node);
327 if(m_fix_string_send_time_set ==
false)
329 FixUtilities::encode_current_time(&m_fix_string_send_time, m_session_settings->timestamp_subseconds_precision);
330 m_fix_string_send_time_set =
true;
333 return m_fix_string_send_time.to_string();
336 LLFIX_HOT
void encode(
char* target_buffer, std::size_t target_buffer_length,
const uint32_t sequence_no, std::size_t& encoded_length)
338 assert(target_buffer !=
nullptr && target_buffer_length > 0);
342 auto fix_str_seq_no_length = Converters::unsigned_int_to_chars<uint32_t>(sequence_no, m_fix_string_seq_no.data());
343 m_fix_string_seq_no.set_length(
static_cast<uint32_t
>(fix_str_seq_no_length));
355 int body_length = 20;
357 if (m_fix_string_send_time_set ==
false)
359 FixUtilities::encode_current_time(&m_fix_string_send_time, m_session_settings->timestamp_subseconds_precision);
360 m_fix_string_send_time_set =
true;
363 body_length +=
static_cast<int>(m_fix_string_send_time.length());
365 body_length +=
static_cast<int>(m_msg_type_len);
366 body_length +=
static_cast<int>(m_fix_string_seq_no.length());
367 body_length +=
static_cast<int>(m_session_settings->sender_comp_id.length());
368 body_length +=
static_cast<int>(m_session_settings->target_comp_id.length());
370 if(m_session_settings->include_last_processed_seqnum_in_header)
372 auto last_processed_seq_num_str_len = Converters::unsigned_int_to_chars<uint32_t>(m_session_sequence_store->
get_incoming_seq_no(), m_last_processed_seq_num.data());
373 m_last_processed_seq_num.set_length(
static_cast<uint32_t
>(last_processed_seq_num_str_len));
374 body_length +=
static_cast<int>(5+ last_processed_seq_num_str_len);
377 for(std::size_t i =0; i < m_header_pointer; i++)
379 m_header_vector[i].tag_str_length = Converters::unsigned_int_to_chars<uint32_t>(m_header_vector[i].tag, &(m_header_vector[i].tag_str[0]));
380 body_length +=
static_cast<int>((2 + m_header_vector[i].tag_str_length + m_header_vector[i].value->length()));
383 for(std::size_t i =0; i < m_body_pointer; i++)
385 m_body_vector[i].tag_str_length = Converters::unsigned_int_to_chars<uint32_t>(m_body_vector[i].tag, &(m_body_vector[i].tag_str[0]));
386 body_length +=
static_cast<int>((2 + m_body_vector[i].tag_str_length + m_body_vector[i].value->length()));
389 for(std::size_t i =0; i < m_trailer_pointer; i++)
391 m_trailer_vector[i].tag_str_length = Converters::unsigned_int_to_chars<uint32_t>(m_trailer_vector[i].tag, &(m_trailer_vector[i].tag_str[0]));
392 body_length +=
static_cast<int>((2 + m_trailer_vector[i].tag_str_length + m_trailer_vector[i].value->length()));
395 for(
const auto & additional_header_tag : m_additional_static_header_tags)
397 body_length +=
static_cast<int>((2 + additional_header_tag.tag_str_length + additional_header_tag.value.length()));
400 auto fix_str_body_len_length = Converters::unsigned_int_to_chars<uint32_t>(body_length, m_fix_string_body_length.data());
401 m_fix_string_body_length.set_length(
static_cast<uint32_t
>(fix_str_body_len_length));
406 auto write_to_buffer = [&target_buffer, &encoded_length](
const char* buffer, std::size_t buffer_len)
409 llfix_builtin_memcpy(target_buffer + encoded_length, buffer, buffer_len);
410 encoded_length += buffer_len;
414 write_to_buffer(
"8=", 2);
415 write_to_buffer(m_session_settings->begin_string.c_str(), m_session_settings->begin_string.length());
416 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
419 write_to_buffer(
"9=", 2);
420 write_to_buffer(m_fix_string_body_length.c_str(), m_fix_string_body_length.length());
421 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
424 write_to_buffer(
"35=", 3);
425 write_to_buffer(&m_msg_type[0], m_msg_type_len);
426 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
429 write_to_buffer(
"34=", 3);
430 write_to_buffer(m_fix_string_seq_no.c_str(), m_fix_string_seq_no.length());
431 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
434 write_to_buffer(
"49=", 3);
435 write_to_buffer(m_session_settings->sender_comp_id.c_str(), m_session_settings->sender_comp_id.length());
436 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
439 write_to_buffer(
"52=", 3);
440 write_to_buffer(m_fix_string_send_time.data(), m_fix_string_send_time.length());
441 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
444 write_to_buffer(
"56=", 3);
445 write_to_buffer(m_session_settings->target_comp_id.c_str(), m_session_settings->target_comp_id.length());
446 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
448 if(m_session_settings->include_last_processed_seqnum_in_header)
451 write_to_buffer(
"369=", 4);
452 write_to_buffer(m_last_processed_seq_num.c_str(), m_last_processed_seq_num.length());
453 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
457 for(
const auto & additional_header_tag : m_additional_static_header_tags)
459 write_to_buffer(&additional_header_tag.tag_str[0], additional_header_tag.tag_str_length);
461 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
463 write_to_buffer(additional_header_tag.value.c_str(), additional_header_tag.value.length());
465 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
469 for(std::size_t i=0; i<m_header_pointer;i++)
471 write_to_buffer(&m_header_vector[i].tag_str[0], m_header_vector[i].tag_str_length);
473 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
475 write_to_buffer(m_header_vector[i].value->c_str(), m_header_vector[i].value->length());
477 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
481 for(std::size_t i=0; i<m_body_pointer;i++)
483 write_to_buffer(&m_body_vector[i].tag_str[0], m_body_vector[i].tag_str_length);
485 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
487 write_to_buffer(m_body_vector[i].value->c_str(), m_body_vector[i].value->length());
489 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
493 for(std::size_t i=0; i<m_trailer_pointer;i++)
495 write_to_buffer(&m_trailer_vector[i].tag_str[0], m_trailer_vector[i].tag_str_length);
497 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
499 write_to_buffer(m_trailer_vector[i].value->c_str(), m_trailer_vector[i].value->length());
501 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
506 write_to_buffer(
"10=", 3);
508 if(llfix_likely(m_session_settings->enable_simd_avx2))
510 FixUtilities::encode_checksum_simd_avx2(target_buffer, encoded_length-3, target_buffer + encoded_length);
514 FixUtilities::encode_checksum_no_simd(target_buffer, encoded_length-3, target_buffer + encoded_length);
516 encoded_length += FixConstants::FIX_CHECKSUM_LENGTH;
518 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
522 m_header_pointer = 0;
524 m_trailer_pointer = 0;
525 m_fix_string_cache.reset_pointer();
526 m_fix_string_send_time_set =
false;
529 std::string to_string()
533 for(std::size_t i=0; i< m_header_pointer; i++)
537 ret += std::to_string(m_header_vector[i].tag) +
"=" + m_header_vector[i].value->to_string() +
'|';
541 return "An error occurred during OutgoingFixMessage::to_string call";
545 for(std::size_t i=0; i< m_body_pointer; i++)
549 ret += std::to_string(m_body_vector[i].tag) +
"=" + m_body_vector[i].value->to_string() +
'|';
553 return "An error occurred during OutgoingFixMessage::to_string call";
557 for(std::size_t i=0; i< m_trailer_pointer; i++)
561 ret += std::to_string(m_trailer_vector[i].tag) +
"=" + m_trailer_vector[i].value->to_string() +
'|';
565 return "An error occurred during OutgoingFixMessage::to_string call";
573 void load_from_buffer(
char* buffer, std::size_t buffer_size)
576 assert(buffer_size > 0);
578 std::size_t buffer_read{ 0 };
579 bool looking_for_equals{
true };
581 std::size_t current_tag_start{ 0 };
582 std::size_t current_tag_length{ 0 };
584 std::size_t current_value_start{ 0 };
585 std::size_t current_value_length{ 0 };
587 bool is_replacing_a_non_retransmittable_admin_message {
false};
591 if (looking_for_equals)
593 if (buffer[buffer_read] == FixConstants::FIX_EQUALS)
595 looking_for_equals =
false;
597 current_value_start = buffer_read + 1;
598 current_value_length = 0;
602 current_tag_length++;
607 if (buffer[buffer_read] == FixConstants::FIX_DELIMITER)
609 uint32_t tag = Converters::chars_to_unsigned_int<uint32_t>(buffer + current_tag_start, current_tag_length);
611 if (tag != FixConstants::TAG_BEGIN_STRING && tag != FixConstants::TAG_BODY_LENGTH && tag != FixConstants::TAG_SENDER_COMP_ID && tag != FixConstants::TAG_TARGET_COMP_ID && tag != FixConstants::TAG_CHECKSUM)
613 bool is_one_of_static_header_tags = is_static_header_tag(tag);
615 if (is_one_of_static_header_tags ==
false)
617 auto str_val = m_fix_string_cache.allocate();
618 str_val->copy_from(buffer + current_value_start, current_value_length);
620 if (tag == FixConstants::TAG_MSG_TYPE)
622 is_replacing_a_non_retransmittable_admin_message = FixUtilities::is_a_non_retransmittable_admin_message_type(str_val);
624 if(is_replacing_a_non_retransmittable_admin_message)
630 if (str_val->length() == 1)
640 else if (tag == FixConstants::TAG_SENDING_TIME)
642 set_tag<FixMessageComponent::HEADER>(FixConstants::TAG_ORIG_SENDING_TIME, str_val);
644 else if(tag == FixConstants::TAG_MSG_SEQ_NUM)
646 if(is_replacing_a_non_retransmittable_admin_message)
648 uint32_t sequence_no = Converters::chars_to_unsigned_int<uint32_t>(buffer + current_value_start, current_value_length);
650 set_tag(FixConstants::TAG_NEW_SEQ_NO, sequence_no);
656 if(is_replacing_a_non_retransmittable_admin_message ==
false)
664 looking_for_equals =
true;
666 current_tag_start = buffer_read + 1;
667 current_tag_length = 0;
671 current_value_length++;
677 if (buffer_read == buffer_size)
688 return m_body_vector.begin();
693 return m_body_vector.begin() + m_body_pointer;
697 #ifdef LLFIX_UNIT_TEST
698 std::size_t get_msg_type_length()
const {
return m_msg_type_len; }
703 char m_msg_type[FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH];
704 std::size_t m_msg_type_len = 1;
706 FixString m_fix_string_send_time;
707 bool m_fix_string_send_time_set =
false;
708 FixString m_fix_string_seq_no;
709 FixString m_fix_string_body_length;
710 FixString m_last_processed_seq_num;
712 std::vector<OutgoingStaticValue> m_additional_static_header_tags;
713 std::vector<OutgoingValue> m_header_vector;
714 std::size_t m_header_pointer = 0;
716 void add_placeholder_to_header_vector()
718 OutgoingValue placeholder;
719 m_header_vector.push_back(placeholder);
723 std::vector<OutgoingValue> m_body_vector;
724 std::size_t m_body_pointer = 0;
725 static inline constexpr std::size_t INITIAL_BODY_TAG_PLACEHOLDER_COUNT = 256;
727 void add_placeholder_to_body_vector()
729 OutgoingValue placeholder;
730 m_body_vector.push_back(placeholder);
734 std::vector<OutgoingValue> m_trailer_vector;
735 std::size_t m_trailer_pointer = 0;
737 void add_placeholder_to_trailer_vector()
739 OutgoingValue placeholder;
740 m_trailer_vector.push_back(placeholder);
744 ObjectCache<FixString> m_fix_string_cache;
747 SequenceStore* m_session_sequence_store =
nullptr;
748 FixSessionSettings* m_session_settings =
nullptr;
750 bool is_static_header_tag(uint32_t tag)
const
752 for (
const auto& item : m_additional_static_header_tags)
762 template<FixMessageComponent component = FixMessageComponent::BODY>
763 void set_tag_internal(uint32_t tag, FixString* value)
769 if constexpr (component == FixMessageComponent::BODY)
771 if (llfix_unlikely(m_body_pointer + 1 == m_body_vector.size()))
773 add_placeholder_to_body_vector();
776 m_body_vector[m_body_pointer] = node;
779 else if constexpr (component == FixMessageComponent::HEADER)
781 if (llfix_unlikely(m_header_pointer + 1 == m_header_vector.size()))
783 add_placeholder_to_header_vector();
786 m_header_vector[m_header_pointer] = node;
789 else if constexpr (component == FixMessageComponent::TRAILER)
791 if (llfix_unlikely(m_trailer_pointer + 1 == m_trailer_vector.size()))
793 add_placeholder_to_trailer_vector();
796 m_trailer_vector[m_trailer_pointer] = node;
802 static constexpr
bool always_false_v =
false;
804 OutgoingFixMessage(
const OutgoingFixMessage& other) =
delete;
805 OutgoingFixMessage& operator= (
const OutgoingFixMessage& other) =
delete;
806 OutgoingFixMessage(OutgoingFixMessage&& other) =
delete;
807 OutgoingFixMessage& operator=(OutgoingFixMessage&& other) =
delete;