I managed to make it run 25% faster with a few small tweaks. I haven't checked if it still works, you probably have unit tests, right?
public class FixDictionaryBase2
{
private readonly Dictionary<int, string> _dict;
protected FixDictionaryBase2()
{
_dict = [];
}
protected void Parse(ReadOnlySpan<char> inputSpan, out List<Dictionary<int, string>> groups)
{
// Algorithm for processing FIX message string:
// 1. Iterate through the input string and extract key-value pairs based on the splitter character.
// 2. If the key is RptSeq (83), initialize a new group and add it to the groups list.
// 3. Assign key-value pairs to the appropriate dictionary:
// - If the key is 10 (Checksum), store it in the main _dict.
// - If currently inside a group, store it in the dictionary of the current group.
// - Otherwise, store it in the main _dict.
// 4. Continue processing until no more splitter characters are found in the input string.
groups = [];
Dictionary<int, string> currentGroup = new();
// Special characters used to separate data
const char splitter = '\x01';
const char equalChar = '=';
const int rptSeq = 83;
// Find the first occurrence of the splitter character
int splitterIndex = inputSpan.IndexOf(splitter);
while (splitterIndex != -1)
{
// Extract the part before the splitter to get the key-value pair
var leftPart = inputSpan[..splitterIndex];
// Find the position of '=' to separate key and value
var equalIndex = leftPart.IndexOf(equalChar);
// Extract key from the part before '='
var key = int.Parse(leftPart[..equalIndex]);
// Extract value from the part after '='
var value = leftPart.Slice(equalIndex + 1).ToString();
// If the key is RptSeq (83), start a new group and add it to the groups list
// Determine the appropriate dictionary to store data
// - If the key is 10 (Checksum), always store it in the main _dict
// - If a group has been identified (hasGroup == true), store it in the current group's dictionary
// - Otherwise, store it in the main _dict
if (key == rptSeq)
{
groups.Add(new());
if (key == 10)
{
_dict[key] = value;
}
else
{
currentGroup[key] = value;
}
}
else
{
_dict[key] = value;
}
// Remove the processed part and continue searching for the next splitter
inputSpan = inputSpan.Slice(splitterIndex + 1);
splitterIndex = inputSpan.IndexOf(splitter);
}
}
}
public sealed class FixDictionary2 : FixDictionaryBase2
{
private readonly string _fixString;
public FixDictionary2(string fixString) : base()
{
_fixString = fixString;
Parse(fixString, out var groups);
Groups = groups;
}
public IReadOnlyList<Dictionary<int, string>> Groups { get; }
public string GetFixString() => _fixString;
}