10 #include <string_view>
13 #include "core/compiler/builtin_functions.h"
14 #include "core/compiler/unused.h"
15 #include "core/compiler/hints_branch_predictor.h"
16 #include "core/compiler/hints_hot_code.h"
18 #include "core/os/assert_msg.h"
20 #include "core/utilities/converters.h"
21 #include "core/utilities/object_cache.h"
23 #include "electronic_trading/common/fixed_point.h"
24 #include "electronic_trading/session/sequence_store.h"
26 #include "fix_constants.h"
27 #include "fix_string.h"
28 #include "fix_session_settings.h"
29 #include "fix_utilities.h"
49 enum class FixMessageComponent
59 FixString* value =
nullptr;
61 std::size_t tag_str_length=0;
64 struct OutgoingStaticValue
68 std::size_t tag_str_length=0;
84 bool initialise(FixSessionSettings* session_settings_instance,
SequenceStore* session_sequence_store_instance)
86 m_session_settings = session_settings_instance;
87 m_session_sequence_store = session_sequence_store_instance;
89 m_body_vector.reserve(INITIAL_BODY_TAG_PLACEHOLDER_COUNT);
91 for (std::size_t i = 0; i < INITIAL_BODY_TAG_PLACEHOLDER_COUNT; i++)
93 add_placeholder_to_body_vector();
96 m_header_vector.reserve(INITIAL_BODY_TAG_PLACEHOLDER_COUNT);
98 for (std::size_t i = 0; i < INITIAL_BODY_TAG_PLACEHOLDER_COUNT; i++)
100 add_placeholder_to_header_vector();
103 m_trailer_vector.reserve(INITIAL_BODY_TAG_PLACEHOLDER_COUNT);
105 for (std::size_t i = 0; i < INITIAL_BODY_TAG_PLACEHOLDER_COUNT; i++)
107 add_placeholder_to_trailer_vector();
110 return m_fix_string_cache.create(256);
139 m_msg_type_len = buffer.length();
140 assert(m_msg_type_len <= FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH);
141 llfix_builtin_memcpy(m_msg_type, buffer.data(), m_msg_type_len);
169 template<FixMessageComponent component = FixMessageComponent::BODY,
typename T>
170 void set_tag(uint32_t tag, T val, std::size_t decimal_points = 0)
172 FixString* str_value = m_fix_string_cache.allocate();
174 if constexpr (std::is_same_v<T, const char*>)
176 LLFIX_UNUSED(decimal_points);
177 str_value->copy_from(val);
179 else if constexpr (std::is_same_v<T, std::string>)
181 LLFIX_UNUSED(decimal_points);
182 str_value->copy_from(val.c_str());
184 else if constexpr (std::is_same_v<T, char>)
186 LLFIX_UNUSED(decimal_points);
187 str_value->copy_from(val);
189 else if constexpr (std::is_same_v<T, std::string_view>)
191 LLFIX_UNUSED(decimal_points);
192 str_value->copy_from(val);
194 else if constexpr (std::is_same_v<T, FixString*>)
196 LLFIX_UNUSED(decimal_points);
197 str_value->copy_from(val->to_string_view());
199 else if constexpr (std::is_same_v<T, bool>)
201 LLFIX_UNUSED(decimal_points);
202 str_value->data()[0] = val ==
true ? FixConstants::FIX_BOOLEAN_TRUE : FixConstants::FIX_BOOLEAN_FALSE;
203 str_value->set_length(1);
205 else if constexpr (std::is_same_v<T, FixedPoint>)
207 LLFIX_UNUSED(decimal_points);
208 auto len = val.to_chars(str_value->data());
209 str_value->set_length(
static_cast<uint32_t
>(len));
211 else if constexpr (std::is_floating_point<T>::value)
213 llfix_assert_msg(decimal_points > 0,
"When you pass double/float to set_tag, you should also specify decimal points");
214 auto length = Converters::double_to_chars(val, str_value->data(), str_value->capacity(), decimal_points);
215 str_value->set_length(
static_cast<uint32_t
>(length));
217 else if constexpr (std::is_integral<T>::value && std::is_signed<T>::value)
219 LLFIX_UNUSED(decimal_points);
220 auto length = Converters::int_to_chars(val, str_value->data());
221 str_value->set_length(
static_cast<uint32_t
>(length));
223 else if constexpr (std::is_integral<T>::value &&
sizeof(T) ==
sizeof(uint64_t))
225 LLFIX_UNUSED(decimal_points);
226 auto length = Converters::unsigned_int_to_chars<uint64_t>(val, str_value->data());
227 str_value->set_length(
static_cast<uint32_t
>(length));
229 else if constexpr (std::is_integral<T>::value &&
sizeof(T) ==
sizeof(uint32_t))
231 LLFIX_UNUSED(decimal_points);
232 auto length = Converters::unsigned_int_to_chars<uint32_t>(val, str_value->data());
233 str_value->set_length(
static_cast<uint32_t
>(length));
237 static_assert(always_false_v<T>,
"set_tag unsupported type");
240 set_tag_internal<component>(tag, str_value);
254 template<FixMessageComponent component = FixMessageComponent::BODY>
257 FixString* str_value = m_fix_string_cache.allocate();
258 str_value->copy_from(buffer, data_length);
259 set_tag_internal<component>(tag, str_value);
275 template<FixMessageComponent component = FixMessageComponent::BODY>
278 if (m_fix_string_send_time_set ==
false)
280 FixUtilities::encode_current_time(&m_fix_string_send_time, m_session_settings->timestamp_subseconds_precision);
281 m_fix_string_send_time_set =
true;
284 set_tag_internal<component>(tag, &m_fix_string_send_time);
287 void set_additional_static_header_tag(uint32_t tag,
const std::string& val)
289 OutgoingStaticValue node;
293 node.tag_str_length = Converters::unsigned_int_to_chars<uint32_t>(node.tag, &(node.tag_str[0]));
295 m_additional_static_header_tags.push_back(node);
305 if(m_fix_string_send_time_set ==
false)
307 FixUtilities::encode_current_time(&m_fix_string_send_time, m_session_settings->timestamp_subseconds_precision);
308 m_fix_string_send_time_set =
true;
311 return m_fix_string_send_time.to_string();
314 LLFIX_HOT
void encode(
char* target_buffer, std::size_t target_buffer_length,
const uint32_t sequence_no, std::size_t& encoded_length)
316 assert(target_buffer !=
nullptr && target_buffer_length > 0);
320 auto fix_str_seq_no_length = Converters::unsigned_int_to_chars<uint32_t>(sequence_no, m_fix_string_seq_no.data());
321 m_fix_string_seq_no.set_length(
static_cast<uint32_t
>(fix_str_seq_no_length));
333 int body_length = 20;
335 if (m_fix_string_send_time_set ==
false)
337 FixUtilities::encode_current_time(&m_fix_string_send_time, m_session_settings->timestamp_subseconds_precision);
338 m_fix_string_send_time_set =
true;
341 body_length +=
static_cast<int>(m_fix_string_send_time.length());
343 body_length +=
static_cast<int>(m_msg_type_len);
344 body_length +=
static_cast<int>(m_fix_string_seq_no.length());
345 body_length +=
static_cast<int>(m_session_settings->sender_comp_id.length());
346 body_length +=
static_cast<int>(m_session_settings->target_comp_id.length());
348 if(m_session_settings->include_last_processed_seqnum_in_header)
350 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());
351 m_last_processed_seq_num.set_length(
static_cast<uint32_t
>(last_processed_seq_num_str_len));
352 body_length +=
static_cast<int>(5+ last_processed_seq_num_str_len);
356 for(std::size_t i =0; i < m_header_pointer; i++)
358 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]));
359 body_length +=
static_cast<int>((2 + m_header_vector[i].tag_str_length + m_header_vector[i].value->length()));
363 for(std::size_t i =0; i < m_body_pointer; i++)
365 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]));
366 body_length +=
static_cast<int>((2 + m_body_vector[i].tag_str_length + m_body_vector[i].value->length()));
370 for(std::size_t i =0; i < m_trailer_pointer; i++)
372 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]));
373 body_length +=
static_cast<int>((2 + m_trailer_vector[i].tag_str_length + m_trailer_vector[i].value->length()));
377 for(
const auto & additional_header_tag : m_additional_static_header_tags)
379 body_length +=
static_cast<int>((2 + additional_header_tag.tag_str_length + additional_header_tag.value.length()));
382 auto fix_str_body_len_length = Converters::unsigned_int_to_chars<uint32_t>(body_length, m_fix_string_body_length.data());
383 m_fix_string_body_length.set_length(
static_cast<uint32_t
>(fix_str_body_len_length));
388 auto write_to_buffer = [&target_buffer, &encoded_length](
const char* buffer, std::size_t buffer_len)
391 llfix_builtin_memcpy(target_buffer + encoded_length, buffer, buffer_len);
392 encoded_length += buffer_len;
396 write_to_buffer(
"8=", 2);
397 write_to_buffer(m_session_settings->begin_string.c_str(), m_session_settings->begin_string.length());
398 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
401 write_to_buffer(
"9=", 2);
402 write_to_buffer(m_fix_string_body_length.c_str(), m_fix_string_body_length.length());
403 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
406 write_to_buffer(
"35=", 3);
407 write_to_buffer(&m_msg_type[0], m_msg_type_len);
408 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
411 write_to_buffer(
"34=", 3);
412 write_to_buffer(m_fix_string_seq_no.c_str(), m_fix_string_seq_no.length());
413 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
416 write_to_buffer(
"49=", 3);
417 write_to_buffer(m_session_settings->sender_comp_id.c_str(), m_session_settings->sender_comp_id.length());
418 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
421 write_to_buffer(
"52=", 3);
422 write_to_buffer(m_fix_string_send_time.data(), m_fix_string_send_time.length());
423 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
426 write_to_buffer(
"56=", 3);
427 write_to_buffer(m_session_settings->target_comp_id.c_str(), m_session_settings->target_comp_id.length());
428 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
430 if(m_session_settings->include_last_processed_seqnum_in_header)
433 write_to_buffer(
"369=", 4);
434 write_to_buffer(m_last_processed_seq_num.c_str(), m_last_processed_seq_num.length());
435 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
440 for(
const auto & additional_header_tag : m_additional_static_header_tags)
442 write_to_buffer(&additional_header_tag.tag_str[0], additional_header_tag.tag_str_length);
444 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
446 write_to_buffer(additional_header_tag.value.c_str(), additional_header_tag.value.length());
448 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
453 for(std::size_t i=0; i<m_header_pointer;i++)
455 write_to_buffer(&m_header_vector[i].tag_str[0], m_header_vector[i].tag_str_length);
457 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
459 write_to_buffer(m_header_vector[i].value->c_str(), m_header_vector[i].value->length());
461 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
466 for(std::size_t i=0; i<m_body_pointer;i++)
468 write_to_buffer(&m_body_vector[i].tag_str[0], m_body_vector[i].tag_str_length);
470 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
472 write_to_buffer(m_body_vector[i].value->c_str(), m_body_vector[i].value->length());
474 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
479 for(std::size_t i=0; i<m_trailer_pointer;i++)
481 write_to_buffer(&m_trailer_vector[i].tag_str[0], m_trailer_vector[i].tag_str_length);
483 write_to_buffer(&FixConstants::FIX_EQUALS, 1);
485 write_to_buffer(m_trailer_vector[i].value->c_str(), m_trailer_vector[i].value->length());
487 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
492 write_to_buffer(
"10=", 3);
494 if(llfix_likely(m_session_settings->enable_simd_avx2))
496 FixUtilities::encode_checksum_simd_avx2(target_buffer, encoded_length-3, target_buffer + encoded_length);
500 FixUtilities::encode_checksum_no_simd(target_buffer, encoded_length-3, target_buffer + encoded_length);
502 encoded_length += FixConstants::FIX_CHECKSUM_LENGTH;
504 write_to_buffer(&(FixConstants::FIX_DELIMITER), 1);
508 m_header_pointer = 0;
510 m_trailer_pointer = 0;
511 m_fix_string_cache.reset_pointer();
512 m_fix_string_send_time_set =
false;
515 std::string to_string()
519 for(std::size_t i=0; i< m_header_pointer; i++)
523 ret += std::to_string(m_header_vector[i].tag) +
"=" + m_header_vector[i].value->to_string() +
'|';
527 return "An error occurred during OutgoingFixMessage::to_string call";
531 for(std::size_t i=0; i< m_body_pointer; i++)
535 ret += std::to_string(m_body_vector[i].tag) +
"=" + m_body_vector[i].value->to_string() +
'|';
539 return "An error occurred during OutgoingFixMessage::to_string call";
543 for(std::size_t i=0; i< m_trailer_pointer; i++)
547 ret += std::to_string(m_trailer_vector[i].tag) +
"=" + m_trailer_vector[i].value->to_string() +
'|';
551 return "An error occurred during OutgoingFixMessage::to_string call";
559 void load_from_buffer(
char* buffer, std::size_t buffer_size)
562 assert(buffer_size > 0);
564 std::size_t buffer_read{ 0 };
565 bool looking_for_equals{
true };
567 std::size_t current_tag_start{ 0 };
568 std::size_t current_tag_length{ 0 };
570 std::size_t current_value_start{ 0 };
571 std::size_t current_value_length{ 0 };
573 bool is_replacing_a_non_retransmittable_admin_message {
false};
577 if (looking_for_equals)
579 if (buffer[buffer_read] == FixConstants::FIX_EQUALS)
581 looking_for_equals =
false;
583 current_value_start = buffer_read + 1;
584 current_value_length = 0;
588 current_tag_length++;
593 if (buffer[buffer_read] == FixConstants::FIX_DELIMITER)
595 uint32_t tag = Converters::chars_to_unsigned_int<uint32_t>(buffer + current_tag_start, current_tag_length);
597 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)
599 bool is_one_of_static_header_tags = is_static_header_tag(tag);
601 if (is_one_of_static_header_tags ==
false)
603 auto str_val = m_fix_string_cache.allocate();
604 str_val->copy_from(buffer + current_value_start, current_value_length);
606 if (tag == FixConstants::TAG_MSG_TYPE)
608 is_replacing_a_non_retransmittable_admin_message = FixUtilities::is_a_non_retransmittable_admin_message_type(str_val);
610 if(is_replacing_a_non_retransmittable_admin_message)
616 if (str_val->length() == 1)
626 else if (tag == FixConstants::TAG_SENDING_TIME)
628 set_tag<FixMessageComponent::HEADER>(FixConstants::TAG_ORIG_SENDING_TIME, str_val);
630 else if(tag == FixConstants::TAG_MSG_SEQ_NUM)
632 if(is_replacing_a_non_retransmittable_admin_message)
634 uint32_t sequence_no = Converters::chars_to_unsigned_int<uint32_t>(buffer + current_value_start, current_value_length);
636 set_tag(FixConstants::TAG_NEW_SEQ_NO, sequence_no);
642 if(is_replacing_a_non_retransmittable_admin_message ==
false)
650 looking_for_equals =
true;
652 current_tag_start = buffer_read + 1;
653 current_tag_length = 0;
657 current_value_length++;
663 if (buffer_read == buffer_size)
674 return m_body_vector.begin();
679 return m_body_vector.begin() + m_body_pointer;
683 #ifdef LLFIX_UNIT_TEST
684 std::size_t get_msg_type_length()
const {
return m_msg_type_len; }
689 char m_msg_type[FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH];
690 std::size_t m_msg_type_len = 1;
692 FixString m_fix_string_send_time;
693 bool m_fix_string_send_time_set =
false;
694 FixString m_fix_string_seq_no;
695 FixString m_fix_string_body_length;
696 FixString m_last_processed_seq_num;
698 std::vector<OutgoingStaticValue> m_additional_static_header_tags;
699 std::vector<OutgoingValue> m_header_vector;
700 std::size_t m_header_pointer = 0;
702 void add_placeholder_to_header_vector()
704 OutgoingValue placeholder;
705 m_header_vector.push_back(placeholder);
709 std::vector<OutgoingValue> m_body_vector;
710 std::size_t m_body_pointer = 0;
711 static inline constexpr std::size_t INITIAL_BODY_TAG_PLACEHOLDER_COUNT = 256;
713 void add_placeholder_to_body_vector()
715 OutgoingValue placeholder;
716 m_body_vector.push_back(placeholder);
720 std::vector<OutgoingValue> m_trailer_vector;
721 std::size_t m_trailer_pointer = 0;
723 void add_placeholder_to_trailer_vector()
725 OutgoingValue placeholder;
726 m_trailer_vector.push_back(placeholder);
730 ObjectCache<FixString> m_fix_string_cache;
733 SequenceStore* m_session_sequence_store =
nullptr;
734 FixSessionSettings* m_session_settings =
nullptr;
736 bool is_static_header_tag(uint32_t tag)
const
738 for (
const auto& item : m_additional_static_header_tags)
748 template<FixMessageComponent component = FixMessageComponent::BODY>
749 void set_tag_internal(uint32_t tag, FixString* value)
755 if constexpr (component == FixMessageComponent::BODY)
757 if (llfix_unlikely(m_body_pointer + 1 == m_body_vector.size()))
759 add_placeholder_to_body_vector();
762 m_body_vector[m_body_pointer] = node;
765 else if constexpr (component == FixMessageComponent::HEADER)
767 if (llfix_unlikely(m_header_pointer + 1 == m_header_vector.size()))
769 add_placeholder_to_header_vector();
772 m_header_vector[m_header_pointer] = node;
775 else if constexpr (component == FixMessageComponent::TRAILER)
777 if (llfix_unlikely(m_trailer_pointer + 1 == m_trailer_vector.size()))
779 add_placeholder_to_trailer_vector();
782 m_trailer_vector[m_trailer_pointer] = node;
788 static constexpr
bool always_false_v =
false;
790 OutgoingFixMessage(
const OutgoingFixMessage& other) =
delete;
791 OutgoingFixMessage& operator= (
const OutgoingFixMessage& other) =
delete;
792 OutgoingFixMessage(OutgoingFixMessage&& other) =
delete;
793 OutgoingFixMessage& operator=(OutgoingFixMessage&& other) =
delete;