11 #include <string_view>
13 #include <immintrin.h>
15 #ifdef __linux__ // VOLTRON_EXCLUDE
17 #endif // VOLTRON_EXCLUDE
19 #include "core/compiler/hints_branch_predictor.h"
20 #include "core/compiler/hints_hot_code.h"
21 #include "core/cpu/simd_attributes.h"
22 #include "core/os/vdso.h"
24 #include "core/utilities/converters.h"
25 #include "core/utilities/std_string_utilities.h"
27 #include "fix_constants.h"
28 #include "fix_string.h"
43 static void get_reject_reason_text(
char* target, std::size_t& copied_length, uint32_t reject_reason_code)
46 const char* text =
nullptr;
48 switch (reject_reason_code)
50 case FixConstants::FIX_ERROR_CODE_INVALID_TAG_NUMBER : text =
"Invalid tag number";
break;
51 case FixConstants::FIX_ERROR_CODE_REQUIRED_TAG_MISSING : text =
"Required tag missing";
break;
52 case FixConstants::FIX_ERROR_CODE_TAG_UNDEFINED_FOR_MSG_TYPE : text =
"Tag not defined for this message type";
break;
53 case FixConstants::FIX_ERROR_CODE_UNDEFINED_TAG : text =
"Undefined Tag";
break;
54 case FixConstants::FIX_ERROR_CODE_TAG_WITHOUT_VALUE : text =
"Tag specified without a value";
break;
55 case FixConstants::FIX_ERROR_CODE_VALUE_INCORRECT_FOR_TAG : text =
"Value is incorrect (out of range) for this tag";
break;
56 case FixConstants::FIX_ERROR_CODE_FORMAT_INCORRECT_FOR_TAG : text =
"Incorrect data format for value";
break;
57 case FixConstants::FIX_ERROR_CODE_FORMAT_DECRYPTION_PROBLEM : text =
"Decryption problem";
break;
58 case FixConstants::FIX_ERROR_CODE_FORMAT_SIGNATURE_PROBLEM : text =
"Signature <89> problem";
break;
59 case FixConstants::FIX_ERROR_CODE_COMPID_PROBLEM : text =
"CompID problem";
break;
60 case FixConstants::FIX_ERROR_CODE_SENDING_TIME_ACCURACY_PROBLEM : text =
"SendingTime <52> accuracy problem";
break;
61 case FixConstants::FIX_ERROR_CODE_INVALID_MSG_TYPE : text =
"Invalid MsgType <35>";
break;
62 case FixConstants::FIX_ERROR_CODE_XML_VALIDATION_ERROR : text =
"XML Validation error";
break;
63 case FixConstants::FIX_ERROR_CODE_TAG_APPEARS_MORE_THAN_ONCE : text =
"Tag appears more than once";
break;
64 case FixConstants::FIX_ERROR_CODE_TAG_OUT_OF_ORDER : text =
"Tag specified out of required order";
break;
65 case FixConstants::FIX_ERROR_CODE_RG_OUT_OF_ORDER : text =
"Repeating group fields out of order";
break;
66 case FixConstants::FIX_ERROR_CODE_INCORRECT_NUMINGROUP : text =
"Incorrect NumInGroup count for repeating group";
break;
67 case FixConstants::FIX_ERROR_CODE_NON_BINARY_VALUE_WITH_SOH : text =
"Non \"Data\" value includes field delimiter (<SOH> character)";
break;
68 case FixConstants::FIX_ERROR_CODE_OTHER: text =
"Other";
break;
69 default: text =
"Other";
break;
72 copied_length = strlen(text);
73 llfix_builtin_memcpy(target, text, copied_length);
74 target[copied_length] =
'\0';
88 assert(buffer !=
nullptr && buffer_length > 0 );
90 ret.reserve(buffer_length);
92 for (std::size_t i = 0; i < buffer_length; ++i)
94 ret.push_back(buffer[i] == FixConstants::FIX_DELIMITER ?
'|' : buffer[i]);
100 static bool is_a_non_retransmittable_admin_message_type(FixString* str)
103 assert(str->length());
105 if(str->length() != 1)
110 char single_char_msg_type = str->data()[0];
112 switch(single_char_msg_type)
115 case FixConstants::MSG_TYPE_HEARTBEAT:
return true;
116 case FixConstants::MSG_TYPE_TEST_REQUEST:
return true;
117 case FixConstants::MSG_TYPE_RESEND_REQUEST:
return true;
118 case FixConstants::MSG_TYPE_SEQUENCE_RESET:
return true;
119 case FixConstants::MSG_TYPE_LOGON:
return true;
120 case FixConstants::MSG_TYPE_LOGOUT:
return true;
121 default:
return false;
125 LLFIX_FORCE_INLINE
static void encode_current_time(FixString* target, VDSO::SubsecondPrecision subsecond_precision)
129 static constexpr uint32_t TIME_LENGTHS[] = {
136 using FuncPtr = void (*)(
char*);
138 static constexpr FuncPtr FUNC_TABLE[] =
140 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::NANOSECONDS>,
141 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::MICROSECONDS>,
142 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::MILLISECONDS>,
143 &VDSO::get_datetime_as_string<true, VDSO::SubsecondPrecision::NONE>
146 const auto index =
static_cast<std::size_t
>(subsecond_precision);
148 FUNC_TABLE[index](target->data());
149 target->set_length(TIME_LENGTHS[index]);
152 LLFIX_FORCE_INLINE
static bool is_utc_timestamp_stale(
const std::string_view& value,
int max_allowed_age_seconds)
154 const char* value_buffer = value.data();
156 auto to_int_2 = [](
const char* s)
158 return (s[0] -
'0') * 10 + (s[1] -
'0');
161 auto to_int_4 = [](
const char* s)
163 return (s[0] -
'0') * 1000 +
170 tm.tm_year = to_int_4(value_buffer) - 1900;
171 tm.tm_mon = to_int_2(value_buffer + 4) - 1;
172 tm.tm_mday = to_int_2(value_buffer + 6);
173 tm.tm_hour = to_int_2(value_buffer + 9);
174 tm.tm_min = to_int_2(value_buffer + 12);
175 tm.tm_sec = to_int_2(value_buffer + 15);
179 msg_time = timegm(&tm);
181 msg_time = _mkgmtime(&tm);
187 time_t now = time(
nullptr);
188 return (now - msg_time) > max_allowed_age_seconds;
191 LLFIX_FORCE_INLINE
static bool find_delimiter_from_end(
char* buffer, std::size_t buffer_size,
int& index)
194 void* p = memrchr(buffer, FixConstants::FIX_DELIMITER, buffer_size);
196 if (llfix_unlikely(!p) )
201 index =
static_cast<int>(
static_cast<char*
>(p) - buffer);
206 if (buffer[index] == FixConstants::FIX_DELIMITER)
223 LLFIX_FORCE_INLINE
static void find_tag10_start_from_end(
char* buffer, std::size_t buffer_size,
int& index,
int& final_tag10_delimiter_index)
228 const int max_index =
static_cast<int>(buffer_size - 3);
229 if (index > max_index)
235 if (buffer[index] ==
'1' && buffer[index + 1] ==
'0' && buffer[index + 2] == FixConstants::FIX_EQUALS)
238 int temp_index = index + 2;
243 if (temp_index ==
static_cast<int>(buffer_size))
248 if (buffer[temp_index] == FixConstants::FIX_DELIMITER)
250 final_tag10_delimiter_index = temp_index;
268 LLFIX_FORCE_INLINE
static void find_begin_string_position(
char* buffer, std::size_t buffer_size,
int& begin_string_position)
270 std::size_t current_index = 0;
273 while (current_index<buffer_size-1)
275 if(buffer[current_index] ==
'8' && buffer[current_index+1] == FixConstants::FIX_EQUALS)
277 begin_string_position =
static_cast<int>(current_index);
285 LLFIX_FORCE_INLINE
static void encode_checksum_no_simd(
const char* buffer, std::size_t buffer_length,
char* out)
290 for (std::size_t i = 0; i < buffer_length; ++i)
292 sum +=
static_cast<unsigned char>(buffer[i]);
295 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
297 out[0] =
'0' + (checksum / 100);
298 out[1] =
'0' + ((checksum / 10) % 10);
299 out[2] =
'0' + (checksum % 10);
303 LLFIX_SIMD_TARGET_AVX2
304 static void encode_checksum_simd_avx2(
const char* buffer, std::size_t buffer_length,
char* out)
310 const std::size_t simd_width = 32;
311 const __m256i zero = _mm256_setzero_si256();
315 for (; i + simd_width <= buffer_length; i += simd_width)
317 __m256i bytes = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(buffer + i));
319 __m256i lo = _mm256_unpacklo_epi8(bytes, zero);
320 __m256i hi = _mm256_unpackhi_epi8(bytes, zero);
322 acc = _mm256_add_epi16(acc, lo);
323 acc = _mm256_add_epi16(acc, hi);
326 __m128i acc_lo = _mm256_extracti128_si256(acc, 0);
327 __m128i acc_hi = _mm256_extracti128_si256(acc, 1);
328 __m128i total = _mm_add_epi16(acc_lo, acc_hi);
331 _mm_storeu_si128(
reinterpret_cast<__m128i*
>(temp), total);
333 for (
int j = 0; j < 8; ++j)
336 for (; i < buffer_length; ++i)
337 sum +=
static_cast<unsigned char>(buffer[i]);
339 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
341 out[0] =
'0' + (checksum / 100);
342 out[1] =
'0' + ((checksum / 10) % 10);
343 out[2] =
'0' + (checksum % 10);
346 LLFIX_FORCE_INLINE
static bool validate_checksum_no_simd(
const char* buffer, std::size_t buffer_length, uint32_t actual_checksum)
350 for (std::size_t i = 0; i < buffer_length; ++i)
352 sum +=
static_cast<unsigned char>(buffer[i]);
355 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
357 return checksum == actual_checksum;
361 LLFIX_SIMD_TARGET_AVX2
362 static bool validate_checksum_simd_avx2(
const char* buffer, std::size_t buffer_length, uint32_t actual_checksum)
366 const std::size_t simd_width = 32;
367 const __m256i zero = _mm256_setzero_si256();
371 for (; i + simd_width <= buffer_length; i += simd_width)
373 __m256i bytes = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(buffer + i));
375 __m256i lo = _mm256_unpacklo_epi8(bytes, zero);
376 __m256i hi = _mm256_unpackhi_epi8(bytes, zero);
378 acc = _mm256_add_epi16(acc, lo);
379 acc = _mm256_add_epi16(acc, hi);
382 __m128i acc_lo = _mm256_extracti128_si256(acc, 0);
383 __m128i acc_hi = _mm256_extracti128_si256(acc, 1);
384 __m128i total = _mm_add_epi16(acc_lo, acc_hi);
387 _mm_storeu_si128(
reinterpret_cast<__m128i*
>(temp), total);
389 for (
int j = 0; j < 8; ++j)
392 for (; i < buffer_length; ++i)
393 sum +=
static_cast<unsigned char>(buffer[i]);
395 const uint32_t checksum = sum % FixConstants::FIX_CHECKSUM_MODULO;
397 return checksum == actual_checksum;
400 static uint32_t pack_message_type(
const std::string_view& mt)
402 assert(mt.size()>0 && mt.size() <= FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH);
405 for (std::size_t i = 0; i < mt.size(); ++i)
406 ret |= uint32_t(uint8_t(mt[i])) << (i * 8);
411 static std::string unpack_message_type(uint32_t encoded_msg_type)
414 ret.reserve(FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH);
416 for (std::size_t i = 0; i < FixConstants::MAX_SUPPORTED_MESSAGE_TYPE_LENGTH; ++i)
418 char c = char((encoded_msg_type >> (i * 8)) & 0xFF);
430 static uint32_t get_sequence_number_value_from_fix_message(
const std::string& buffer)
432 auto tag_value_pairs = StringUtilities::split(buffer, FixConstants::FIX_DELIMITER);
434 for (
const auto& tag_value_pair : tag_value_pairs)
436 if (tag_value_pair.length() > 3)
438 if (tag_value_pair[0] ==
'3' && tag_value_pair[1] ==
'4' && tag_value_pair[2] == FixConstants::FIX_EQUALS)
440 return Converters::chars_to_unsigned_int<uint32_t>(&tag_value_pair[3], tag_value_pair.length() - 3);
450 struct FixMessageSequenceNumberExtractor
452 static uint32_t get_sequence_number_from_message(
const std::string& message)
454 return FixUtilities::get_sequence_number_value_from_fix_message(message);