33 #include <string_view>
35 #include <immintrin.h>
37 #ifdef __linux__ // VOLTRON_EXCLUDE
39 #endif // VOLTRON_EXCLUDE
41 #include "core/compiler/hints_branch_predictor.h"
42 #include "core/compiler/hints_hot_code.h"
43 #include "core/cpu/simd_attributes.h"
44 #include "core/os/vdso.h"
46 #include "core/utilities/converters.h"
47 #include "core/utilities/std_string_utilities.h"
49 #include "fix_constants.h"
50 #include "fix_string.h"
65 static void get_reject_reason_text(
char* target, std::size_t& copied_length, uint32_t reject_reason_code)
68 const char* text =
nullptr;
70 switch (reject_reason_code)
72 case FixConstants::FIX_ERROR_CODE_INVALID_TAG_NUMBER : text =
"Invalid tag number";
break;
73 case FixConstants::FIX_ERROR_CODE_REQUIRED_TAG_MISSING : text =
"Required tag missing";
break;
74 case FixConstants::FIX_ERROR_CODE_TAG_UNDEFINED_FOR_MSG_TYPE : text =
"Tag not defined for this message type";
break;
75 case FixConstants::FIX_ERROR_CODE_UNDEFINED_TAG : text =
"Undefined Tag";
break;
76 case FixConstants::FIX_ERROR_CODE_TAG_WITHOUT_VALUE : text =
"Tag specified without a value";
break;
77 case FixConstants::FIX_ERROR_CODE_VALUE_INCORRECT_FOR_TAG : text =
"Value is incorrect (out of range) for this tag";
break;
78 case FixConstants::FIX_ERROR_CODE_FORMAT_INCORRECT_FOR_TAG : text =
"Incorrect data format for value";
break;
79 case FixConstants::FIX_ERROR_CODE_FORMAT_DECRYPTION_PROBLEM : text =
"Decryption problem";
break;
80 case FixConstants::FIX_ERROR_CODE_FORMAT_SIGNATURE_PROBLEM : text =
"Signature <89> problem";
break;
81 case FixConstants::FIX_ERROR_CODE_COMPID_PROBLEM : text =
"CompID problem";
break;
82 case FixConstants::FIX_ERROR_CODE_SENDING_TIME_ACCURACY_PROBLEM : text =
"SendingTime <52> accuracy problem";
break;
83 case FixConstants::FIX_ERROR_CODE_INVALID_MSG_TYPE : text =
"Invalid MsgType <35>";
break;
84 case FixConstants::FIX_ERROR_CODE_XML_VALIDATION_ERROR : text =
"XML Validation error";
break;
85 case FixConstants::FIX_ERROR_CODE_TAG_APPEARS_MORE_THAN_ONCE : text =
"Tag appears more than once";
break;
86 case FixConstants::FIX_ERROR_CODE_TAG_OUT_OF_ORDER : text =
"Tag specified out of required order";
break;
87 case FixConstants::FIX_ERROR_CODE_RG_OUT_OF_ORDER : text =
"Repeating group fields out of order";
break;
88 case FixConstants::FIX_ERROR_CODE_INCORRECT_NUMINGROUP : text =
"Incorrect NumInGroup count for repeating group";
break;
89 case FixConstants::FIX_ERROR_CODE_NON_BINARY_VALUE_WITH_SOH : text =
"Non \"Data\" value includes field delimiter (<SOH> character)";
break;
90 case FixConstants::FIX_ERROR_CODE_OTHER: text =
"Other";
break;
91 default: text =
"Other";
break;
94 copied_length = strlen(text);
95 llfix_builtin_memcpy(target, text, copied_length);
96 target[copied_length] =
'\0';
110 assert(buffer !=
nullptr && buffer_length > 0 );
112 ret.reserve(buffer_length);
114 for (std::size_t i = 0; i < buffer_length; ++i)
116 ret.push_back(buffer[i] == FixConstants::FIX_DELIMITER ?
'|' : buffer[i]);
122 static bool is_a_non_retransmittable_admin_message_type(FixString* str)
125 assert(str->length());
127 if(str->length() != 1)
132 char single_char_msg_type = str->data()[0];
134 switch(single_char_msg_type)
137 case FixConstants::MSG_TYPE_HEARTBEAT:
return true;
138 case FixConstants::MSG_TYPE_TEST_REQUEST:
return true;
139 case FixConstants::MSG_TYPE_RESEND_REQUEST:
return true;
140 case FixConstants::MSG_TYPE_SEQUENCE_RESET:
return true;
141 case FixConstants::MSG_TYPE_LOGON:
return true;
142 case FixConstants::MSG_TYPE_LOGOUT:
return true;
143 default:
return false;
147 LLFIX_FORCE_INLINE
static void encode_current_time(FixString* target, VDSO::SubsecondPrecision subsecond_precision)
151 static constexpr uint32_t TIME_LENGTHS[] = {
158 using FuncPtr = void (*)(
char*);
160 static constexpr FuncPtr FUNC_TABLE[] =
162 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::NANOSECONDS>,
163 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::MICROSECONDS>,
164 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::MILLISECONDS>,
165 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::NONE>
168 const auto index =
static_cast<std::size_t
>(subsecond_precision);
170 FUNC_TABLE[index](target->data());
171 target->set_length(TIME_LENGTHS[index]);
174 LLFIX_FORCE_INLINE
static bool is_utc_timestamp_stale(
const std::string_view& value,
int max_allowed_age_seconds)
176 const char* value_buffer = value.data();
178 auto to_int_2 = [](
const char* s)
180 return (s[0] -
'0') * 10 + (s[1] -
'0');
183 auto to_int_4 = [](
const char* s)
185 return (s[0] -
'0') * 1000 +
192 tm.tm_year = to_int_4(value_buffer) - 1900;
193 tm.tm_mon = to_int_2(value_buffer + 4) - 1;
194 tm.tm_mday = to_int_2(value_buffer + 6);
195 tm.tm_hour = to_int_2(value_buffer + 9);
196 tm.tm_min = to_int_2(value_buffer + 12);
197 tm.tm_sec = to_int_2(value_buffer + 15);
201 msg_time = timegm(&tm);
203 msg_time = _mkgmtime(&tm);
209 time_t now = time(
nullptr);
210 return (now - msg_time) > max_allowed_age_seconds;
213 LLFIX_FORCE_INLINE
static bool find_delimiter_from_end(
char* buffer, std::size_t buffer_size,
int& index)
216 void* p = memrchr(buffer, FixConstants::FIX_DELIMITER, buffer_size);
218 if (llfix_unlikely(!p) )
223 index =
static_cast<int>(
static_cast<char*
>(p) - buffer);
228 if (buffer[index] == FixConstants::FIX_DELIMITER)
245 LLFIX_FORCE_INLINE
static void find_tag10_start_from_end(
char* buffer, std::size_t buffer_size,
int& index,
int& final_tag10_delimiter_index)
250 const int max_index =
static_cast<int>(buffer_size - 3);
251 if (index > max_index)
257 if (buffer[index] ==
'1' && buffer[index + 1] ==
'0' && buffer[index + 2] == FixConstants::FIX_EQUALS)
260 int temp_index = index + 2;
265 if (temp_index ==
static_cast<int>(buffer_size))
270 if (buffer[temp_index] == FixConstants::FIX_DELIMITER)
272 final_tag10_delimiter_index = temp_index;
290 LLFIX_FORCE_INLINE
static void find_begin_string_position(
char* buffer, std::size_t buffer_size,
int& begin_string_position)
292 std::size_t current_index = 0;
295 while (current_index<buffer_size-1)
297 if(buffer[current_index] ==
'8' && buffer[current_index+1] == FixConstants::FIX_EQUALS)
299 begin_string_position =
static_cast<int>(current_index);
307 LLFIX_FORCE_INLINE
static void encode_checksum_no_simd(
const char* buffer, std::size_t buffer_length,
char* out)
312 for (std::size_t i = 0; i < buffer_length; ++i)
314 sum +=
static_cast<unsigned char>(buffer[i]);
317 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
319 out[0] =
'0' + (checksum / 100);
320 out[1] =
'0' + ((checksum / 10) % 10);
321 out[2] =
'0' + (checksum % 10);
325 LLFIX_SIMD_TARGET_AVX2
326 static void encode_checksum_simd_avx2(
const char* buffer, std::size_t buffer_length,
char* out)
332 const std::size_t simd_width = 32;
333 const __m256i zero = _mm256_setzero_si256();
337 for (; i + simd_width <= buffer_length; i += simd_width)
339 __m256i bytes = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(buffer + i));
341 __m256i lo = _mm256_unpacklo_epi8(bytes, zero);
342 __m256i hi = _mm256_unpackhi_epi8(bytes, zero);
344 acc = _mm256_add_epi16(acc, lo);
345 acc = _mm256_add_epi16(acc, hi);
348 __m128i acc_lo = _mm256_extracti128_si256(acc, 0);
349 __m128i acc_hi = _mm256_extracti128_si256(acc, 1);
350 __m128i total = _mm_add_epi16(acc_lo, acc_hi);
353 _mm_storeu_si128(
reinterpret_cast<__m128i*
>(temp), total);
355 for (
int j = 0; j < 8; ++j)
358 for (; i < buffer_length; ++i)
359 sum +=
static_cast<unsigned char>(buffer[i]);
361 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
363 out[0] =
'0' + (checksum / 100);
364 out[1] =
'0' + ((checksum / 10) % 10);
365 out[2] =
'0' + (checksum % 10);
368 LLFIX_FORCE_INLINE
static bool validate_checksum_no_simd(
const char* buffer, std::size_t buffer_length, uint32_t actual_checksum)
372 for (std::size_t i = 0; i < buffer_length; ++i)
374 sum +=
static_cast<unsigned char>(buffer[i]);
377 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
379 return checksum == actual_checksum;
383 LLFIX_SIMD_TARGET_AVX2
384 static bool validate_checksum_simd_avx2(
const char* buffer, std::size_t buffer_length, uint32_t actual_checksum)
388 const std::size_t simd_width = 32;
389 const __m256i zero = _mm256_setzero_si256();
393 for (; i + simd_width <= buffer_length; i += simd_width)
395 __m256i bytes = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(buffer + i));
397 __m256i lo = _mm256_unpacklo_epi8(bytes, zero);
398 __m256i hi = _mm256_unpackhi_epi8(bytes, zero);
400 acc = _mm256_add_epi16(acc, lo);
401 acc = _mm256_add_epi16(acc, hi);
404 __m128i acc_lo = _mm256_extracti128_si256(acc, 0);
405 __m128i acc_hi = _mm256_extracti128_si256(acc, 1);
406 __m128i total = _mm_add_epi16(acc_lo, acc_hi);
409 _mm_storeu_si128(
reinterpret_cast<__m128i*
>(temp), total);
411 for (
int j = 0; j < 8; ++j)
414 for (; i < buffer_length; ++i)
415 sum +=
static_cast<unsigned char>(buffer[i]);
417 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
419 return checksum == actual_checksum;
422 static uint32_t pack_message_type(
const std::string_view& mt)
424 assert(mt.size()>0 && mt.size() <= FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH);
427 for (std::size_t i = 0; i < mt.size(); ++i)
428 ret |= uint32_t(uint8_t(mt[i])) << (i * 8);
433 static std::string unpack_message_type(uint32_t encoded_msg_type)
436 ret.reserve(FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH);
438 for (std::size_t i = 0; i < FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH; ++i)
440 char c = char((encoded_msg_type >> (i * 8)) & 0xFF);
452 static uint32_t get_sequence_number_value_from_fix_message(
const std::string& buffer)
454 auto tag_value_pairs = StringUtilities::split(buffer, FixConstants::FIX_DELIMITER);
456 for (
const auto& tag_value_pair : tag_value_pairs)
458 if (tag_value_pair.length() > 3)
460 if (tag_value_pair[0] ==
'3' && tag_value_pair[1] ==
'4' && tag_value_pair[2] == FixConstants::FIX_EQUALS)
462 return Converters::chars_to_unsigned_int<uint32_t>(&tag_value_pair[3], tag_value_pair.length() - 3);
472 struct FixMessageSequenceNumberExtractor
474 static uint32_t get_sequence_number_from_message(
const std::string& message)
476 return FixUtilities::get_sequence_number_value_from_fix_message(message);