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);
378 for(std::size_t i =0; i < m_header_pointer; i++)
380 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]));
381 body_length +=
static_cast<int>((2 + m_header_vector[i].tag_str_length + m_header_vector[i].value->length()));
385 for(std::size_t i =0; i < m_body_pointer; i++)
387 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]));
388 body_length +=
static_cast<int>((2 + m_body_vector[i].tag_str_length + m_body_vector[i].value->length()));
392 for(std::size_t i =0; i < m_trailer_pointer; i++)
394 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]));
395 body_length +=
static_cast<int>((2 + m_trailer_vector[i].tag_str_length + m_trailer_vector[i].value->length()));
399 for(
const auto & additional_header_tag : m_additional_static_header_tags)
401 body_length +=
static_cast<int>((2 + additional_header_tag.tag_str_length + additional_header_tag.value.length()));
404 auto fix_str_body_len_length = Converters::unsigned_int_to_chars<uint32_t>(body_length, m_fix_string_body_length.data());
405 m_fix_string_body_length.set_length(
static_cast<uint32_t
>(fix_str_body_len_length));
410 auto write_to_buffer = [&target_buffer, &encoded_length](
const char* buffer, std::size_t buffer_len)
413 llfix_builtin_memcpy(target_buffer + encoded_length, buffer, buffer_len);
414 encoded_length += buffer_len;
418 write_to_buffer(
"8=", 2);
419 write_to_buffer(m_session_settings->begin_string.c_str(), m_session_settings->begin_string.length());
420 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
423 write_to_buffer(
"9=", 2);
424 write_to_buffer(m_fix_string_body_length.c_str(), m_fix_string_body_length.length());
425 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
428 write_to_buffer(
"35=", 3);
429 write_to_buffer(&m_msg_type[0], m_msg_type_len);
430 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
433 write_to_buffer(
"34=", 3);
434 write_to_buffer(m_fix_string_seq_no.c_str(), m_fix_string_seq_no.length());
435 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
438 write_to_buffer(
"49=", 3);
439 write_to_buffer(m_session_settings->sender_comp_id.c_str(), m_session_settings->sender_comp_id.length());
440 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
443 write_to_buffer(
"52=", 3);
444 write_to_buffer(m_fix_string_send_time.data(), m_fix_string_send_time.length());
445 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
448 write_to_buffer(
"56=", 3);
449 write_to_buffer(m_session_settings->target_comp_id.c_str(), m_session_settings->target_comp_id.length());
450 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
452 if(m_session_settings->include_last_processed_seqnum_in_header)
455 write_to_buffer(
"369=", 4);
456 write_to_buffer(m_last_processed_seq_num.c_str(), m_last_processed_seq_num.length());
457 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
462 for(
const auto & additional_header_tag : m_additional_static_header_tags)
464 write_to_buffer(&additional_header_tag.tag_str[0], additional_header_tag.tag_str_length);
466 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
468 write_to_buffer(additional_header_tag.value.c_str(), additional_header_tag.value.length());
470 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
475 for(std::size_t i=0; i<m_header_pointer;i++)
477 write_to_buffer(&m_header_vector[i].tag_str[0], m_header_vector[i].tag_str_length);
479 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
481 write_to_buffer(m_header_vector[i].value->c_str(), m_header_vector[i].value->length());
483 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
488 for(std::size_t i=0; i<m_body_pointer;i++)
490 write_to_buffer(&m_body_vector[i].tag_str[0], m_body_vector[i].tag_str_length);
492 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
494 write_to_buffer(m_body_vector[i].value->c_str(), m_body_vector[i].value->length());
496 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
501 for(std::size_t i=0; i<m_trailer_pointer;i++)
503 write_to_buffer(&m_trailer_vector[i].tag_str[0], m_trailer_vector[i].tag_str_length);
505 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
507 write_to_buffer(m_trailer_vector[i].value->c_str(), m_trailer_vector[i].value->length());
509 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
514 write_to_buffer(
"10=", 3);
516 if(llfix_likely(m_session_settings->enable_simd_avx2))
518 FixUtilities::encode_checksum_simd_avx2(target_buffer, encoded_length-3, target_buffer + encoded_length);
522 FixUtilities::encode_checksum_no_simd(target_buffer, encoded_length-3, target_buffer + encoded_length);
524 encoded_length += FixConstants::FIX_CHECKSUM_LENGTH;
526 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
530 m_header_pointer = 0;
532 m_trailer_pointer = 0;
533 m_fix_string_cache.reset_pointer();
534 m_fix_string_send_time_set =
false;
537 std::string to_string()
541 for(std::size_t i=0; i< m_header_pointer; i++)
545 ret += std::to_string(m_header_vector[i].tag) +
"=" + m_header_vector[i].value->to_string() +
'|';
549 return "An error occurred during OutgoingFixMessage::to_string call";
553 for(std::size_t i=0; i< m_body_pointer; i++)
557 ret += std::to_string(m_body_vector[i].tag) +
"=" + m_body_vector[i].value->to_string() +
'|';
561 return "An error occurred during OutgoingFixMessage::to_string call";
565 for(std::size_t i=0; i< m_trailer_pointer; i++)
569 ret += std::to_string(m_trailer_vector[i].tag) +
"=" + m_trailer_vector[i].value->to_string() +
'|';
573 return "An error occurred during OutgoingFixMessage::to_string call";
581 void load_from_buffer(
char* buffer, std::size_t buffer_size)
584 assert(buffer_size > 0);
586 std::size_t buffer_read{ 0 };
587 bool looking_for_equals{
true };
589 std::size_t current_tag_start{ 0 };
590 std::size_t current_tag_length{ 0 };
592 std::size_t current_value_start{ 0 };
593 std::size_t current_value_length{ 0 };
595 bool is_replacing_a_non_retransmittable_admin_message {
false};
599 if (looking_for_equals)
601 if (buffer[buffer_read] == FixConstants::FIX_EQUALS)
603 looking_for_equals =
false;
605 current_value_start = buffer_read + 1;
606 current_value_length = 0;
610 current_tag_length++;
615 if (buffer[buffer_read] == FixConstants::FIX_DELIMITER)
617 uint32_t tag = Converters::chars_to_unsigned_int<uint32_t>(buffer + current_tag_start, current_tag_length);
619 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)
621 bool is_one_of_static_header_tags = is_static_header_tag(tag);
623 if (is_one_of_static_header_tags ==
false)
625 auto str_val = m_fix_string_cache.allocate();
626 str_val->copy_from(buffer + current_value_start, current_value_length);
628 if (tag == FixConstants::TAG_MSG_TYPE)
630 is_replacing_a_non_retransmittable_admin_message = FixUtilities::is_a_non_retransmittable_admin_message_type(str_val);
632 if(is_replacing_a_non_retransmittable_admin_message)
638 if (str_val->length() == 1)
648 else if (tag == FixConstants::TAG_SENDING_TIME)
650 set_tag<FixMessageComponent::HEADER>(FixConstants::TAG_ORIG_SENDING_TIME, str_val);
652 else if(tag == FixConstants::TAG_MSG_SEQ_NUM)
654 if(is_replacing_a_non_retransmittable_admin_message)
656 uint32_t sequence_no = Converters::chars_to_unsigned_int<uint32_t>(buffer + current_value_start, current_value_length);
658 set_tag(FixConstants::TAG_NEW_SEQ_NO, sequence_no);
664 if(is_replacing_a_non_retransmittable_admin_message ==
false)
672 looking_for_equals =
true;
674 current_tag_start = buffer_read + 1;
675 current_tag_length = 0;
679 current_value_length++;
685 if (buffer_read == buffer_size)
696 return m_body_vector.begin();
701 return m_body_vector.begin() + m_body_pointer;
705 #ifdef LLFIX_UNIT_TEST
706 std::size_t get_msg_type_length()
const {
return m_msg_type_len; }
711 char m_msg_type[FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH];
712 std::size_t m_msg_type_len = 1;
714 FixString m_fix_string_send_time;
715 bool m_fix_string_send_time_set =
false;
716 FixString m_fix_string_seq_no;
717 FixString m_fix_string_body_length;
718 FixString m_last_processed_seq_num;
720 std::vector<OutgoingStaticValue> m_additional_static_header_tags;
721 std::vector<OutgoingValue> m_header_vector;
722 std::size_t m_header_pointer = 0;
724 void add_placeholder_to_header_vector()
726 OutgoingValue placeholder;
727 m_header_vector.push_back(placeholder);
731 std::vector<OutgoingValue> m_body_vector;
732 std::size_t m_body_pointer = 0;
733 static inline constexpr std::size_t INITIAL_BODY_TAG_PLACEHOLDER_COUNT = 256;
735 void add_placeholder_to_body_vector()
737 OutgoingValue placeholder;
738 m_body_vector.push_back(placeholder);
742 std::vector<OutgoingValue> m_trailer_vector;
743 std::size_t m_trailer_pointer = 0;
745 void add_placeholder_to_trailer_vector()
747 OutgoingValue placeholder;
748 m_trailer_vector.push_back(placeholder);
752 ObjectCache<FixString> m_fix_string_cache;
755 SequenceStore* m_session_sequence_store =
nullptr;
756 FixSessionSettings* m_session_settings =
nullptr;
758 bool is_static_header_tag(uint32_t tag)
const
760 for (
const auto& item : m_additional_static_header_tags)
770 template<FixMessageComponent component = FixMessageComponent::BODY>
771 void set_tag_internal(uint32_t tag, FixString* value)
777 if constexpr (component == FixMessageComponent::BODY)
779 if (llfix_unlikely(m_body_pointer + 1 == m_body_vector.size()))
781 add_placeholder_to_body_vector();
784 m_body_vector[m_body_pointer] = node;
787 else if constexpr (component == FixMessageComponent::HEADER)
789 if (llfix_unlikely(m_header_pointer + 1 == m_header_vector.size()))
791 add_placeholder_to_header_vector();
794 m_header_vector[m_header_pointer] = node;
797 else if constexpr (component == FixMessageComponent::TRAILER)
799 if (llfix_unlikely(m_trailer_pointer + 1 == m_trailer_vector.size()))
801 add_placeholder_to_trailer_vector();
804 m_trailer_vector[m_trailer_pointer] = node;
810 static constexpr
bool always_false_v =
false;
812 OutgoingFixMessage(
const OutgoingFixMessage& other) =
delete;
813 OutgoingFixMessage& operator= (
const OutgoingFixMessage& other) =
delete;
814 OutgoingFixMessage(OutgoingFixMessage&& other) =
delete;
815 OutgoingFixMessage& operator=(OutgoingFixMessage&& other) =
delete;