Regex and Faster

In the series of these posts, I take a regular task, and implement it multiple times in an iteratively manner, while also improving performance.

The task is the following, given an input string with placeholders in it, and a map of placeholders to actual values. Replace the placeholders in the input string with the actual text values from the map and return the final string. For example, given input string Hello [%placeholder%]! and map [%placeholder%] => World should return Hello World!. The placeholder's [%placeholder%] part is referred as the key, and World part as the value in this post.

To further clarify the task, these constraints are also true:

  • placeholder keys are delimited with [% at the beginning and %] at the end

  • placeholders are non-recursive (a placeholder's value may contain another (or the same) placeholder's key, but it should not be processed recursively)

  • input text contains no placeholder that are embedded by other placeholders (such as hello [%outer[%inner%]example%])

  • the key of a placeholder contain letters and underscores

  • the same fixed set of placeholders are used on multiple input strings

  • placeholders are used at most once per input text

Find out more


Regex and Speed

In the series of these posts, I take a rather regular task, and implement it multiple times in an iteratively manner, while also improving performance.

The task is the following: given a string input with placeholders in it, and a set of placeholders to actual value mappings. Replace the placeholders in the input string with the actual text values from the map and return the final string. For example, given input string Hello [%placeholder%]! and map [%placeholder%] => World should return Hello World!. The placeholder's [%placeholder%] part is referred as the key, and World part as the value in this post.

To further clarify the task, these constraints are also true:

  • placeholder keys are delimited with [% at the beginning and %] at the end

  • placeholders are non-recursive (a placeholder's value may contain another (or the same) placeholder's key, but this should not be processed recursively)

  • input text contains no placeholder that are embedded by other placeholders (such as hello [%outer[%inner%]example%])

  • the key of placeholders contain letters and underscores

  • the same fixed set of placeholders are used on multiple input strings

  • placeholders are used at most once per input text

Find out more


GC Allocate Array

In this post I will examine the GC Allocate Array methods along with other array creation alternatives.

Previously, I have looked into array allocation with when investigating SkipInitLocal. In that post it turned out the larger the array was, the larger the gain was to use stack allocation with [SkipInitLocal] attribute.

However during exercise I noticed that the current implementation of ArrayPool has been using GC.AllocateUninitializedArray<T> to create the arrays for its internal pool.

Creating Arrays

Find out more


What is New here? - aka 4 ways or creating structs

In this post I will investigate 4 different approaches for creating structs and I will measure their performance characteristics.

The release of C# 10 removed a previous restriction on struct constructors: structs are allowed have default constructors. This means the code below compiles without a build error.

public struct Person
{
    public int Age { get; set; } = 1;

    public string Name { get; set; } = "Foo";
}

In this case the default constructor will set the property values as 1 and Foo respectively. This behavior is really similar to classes. The 4 ways this post explores creating structs:

Find out more


SkipInitLocal or ArrayPool

Many data processing algorithms require a temporary data storage for certain operations. I have been recently working with one such algorithm in the sound processing domain. In my case a fixed sized temporary byte array has been required for a method execution. In a performance sensitive code, one would prefer to achieve a non-allocating solution for this problem.

In the particular case it was a tight loop for processing live sound data. Allocating a new array for every iteration of the loop is excessive. However, I could also not use a pre-allocated array for the purpose, due to the structure of the code. There are still a few options to acquire a temporary array:

ArrayPool type provides a shared pool of arrays, from which a developer might rent an array, and return it once it is no longer needed. This array exists on the heap as a regular array, and the ArrayPool makes sure to provide an array when renting which is at least the size asked for. Because the array is returned to the pool after usage, the next iteration of the algorithm may re-use the same array, avoiding any excess allocation.

Find out more