Skip to content

Repository files navigation

FastString

Fast, in stack, fixed size string implementation with constexpr noexcept constructors and accessors. FastString improves memory locality and latency of strings by avoiding heap allocations.

Abstract

std::string allocates heap memory for strings not qualified for SSO (small string optimization) and reduces memory locality. FastString is a thin wrapper around a plain char array with constexpr noexcept constructors and accessors for fast, in stack string manipulation. FastString is a fast and efficient alternative for std::string or plain char arrays in low latency applications and can be easily used with std::string_view for further operations.

Requirements

  • C++20 compatible compiler (constexpr std::copy is required for constexpr constructors)
  • Works with
    • Microsoft (R) C/C++ Optimizing Compiler Version 19.27.29111 or above
    • x86-64 gcc-trunk

Build

mkdir build && cd build && cmake .. && make

Performance

  • Compiler version:MSVC 19.28.29334.0
  • Using Google Benchmark (Tests are included in repo)
Run on (8 X 1498 MHz CPU s)CPU Caches: L1 Data 48 KiB (x4) L1 Instruction 32 KiB (x4) L2 Unified 512 KiB (x4) L3 Unified 8192 KiB (x1)--------------------------------------------------------------------------------------Benchmark Time CPU Iterations--------------------------------------------------------------------------------------BM_std_string_from_const_char 498 ns 148 ns 5600000BM_fixed_size_str_from_const_char 46.9 ns 16.3 ns 34461538BM_std_string_from_constexpr_const_char 500 ns 153 ns 4480000BM_fixed_size_str_from_constexpr_const_char 47.8 ns 16.7 ns 37333333BM_std_string_from_buffer 505 ns 158 ns 5146257BM_fixed_size_str_from_buffer 49.6 ns 14.2 ns 37333333BM_std_string_from_constexpr_buffer 503 ns 188 ns 4072727BM_fixed_size_str_from_constexpr_buffer 50.1 ns 12.6 ns 44800000BM_std_string_from_const_char_large_str 1048 ns 384 ns 2240000BM_fixed_size_str_from_const_char_large_str 153 ns 50.0 ns 10000000BM_std_string_append 190 ns 62.5 ns 10000000BM_fixed_size_str_append 164 ns 56.2 ns 14451613BM_std_string_append_large 50.0 ns 16.4 ns 64000000BM_fixed_size_str_append_large 61.5 ns 23.4 ns 37333333
  • Compiler version: x86-64 gcc-trunk
  • Test scenario - Function creates a string from a given char pointer and return length of the created string. Length is returned and assigned to a volatile variable to avoid compiler optimizing out the construction of the variable.
  • Test code
    • Using std::string
      autof(constchar* str)
      {
      std::string a{str};
      return a.length();
      }
      voidg(constchar* str)
      {
      volatileauto x = f(str);
      }
    • Using FastString. Note use of constexpr and noexcept
      constexprautof(constchar* str) noexcept
      {
      using string64 = fss::fixed_size_str<63>;
      string64 a{str};
      return a.length(); }
      voidg(constchar* str)
      {
      volatileauto x = f(str);
      }
  • Comparison of compiler output between std::string and FastString using https://godbolt.org/image

Usage

Refer to below example code

/* define types */using string8 = fss::fixed_size_str<7>;
using string64 = fss::fixed_size_str<63>;
/* default construction */constexpr string8 a{};
constexprauto a_length = a.length(); // a_length is 0constexprauto a_empty = a.empty(); // a_empty is trueconstexprauto a_max_size = a.max_size(); // a_max_size is 7/* copy construction */constexprauto a_copy_c = a;
auto a_copy = a;
/* move construction */auto a_move = std::move(a_copy);
/* copy assignment */constexpr string8 b{ "1234", 4 }; // b is "1234"
string8 c{ "lmnopqrstuvxyz" }; // c is "lmnopqr"
string8 d{ "56789" }; // d is "789". rest is truncated.
c = b; // now c is "1234"/* move assingment */
c = std::move(d); // c is "56789"/* using with string view */constexpr string8 e{ "abcdefghij", 10 }; // truncated. e is "abcdefg";constexprauto e_sub_str = e.str().substr(0, 2); // e_sub_str is "ab"constexprauto e_length = e.length(); // e_length is 7/* comparison */constexpr string8 f{ "abcd" };
constexpr string8 g{ "abcd" };
constexpr string8 h{ "abcf" };
constexprauto i = (f == g); // i is true constexprauto j = (g == h); // j is false/* append */
string8 k{ "abc" }; // k is "abc"
k.append("d"); // k is "abcd"
k.append("efghi", 5); // k is "abcdefg". rest is truncated/* clear */
k.clear(); // k is empty() ""auto k_empty = k.empty(); // k_empty is true/* reset */
k.reset("1234"); // k is "1234";auto k_length = k.length(); // k_length is 4
k.reset("xyz", 3); // k is "xyz"/* remove_suffix *//* there is no boundary check. similar to string_view */
string8 l{ "1234567" };
l.remove_suffix(3); // l is "1234"/* remove_prefix *//* there is no boundary check. similar to string_view */
l.remove_prefix(2); // l is "34"/* stream operator */
std::cout << l << std::endl;
/* using for member variables */structtest_struct
{
std::uint32_t a_{};
std::uint64_t b_{};
string8 c_{ "abcd" }; // uses only 8 + 4 bytes in stackconstexprautoget_c() const { return c_.str(); }
constexprvoidset_c(constchar* str) { c_.reset(str); }
};
auto test_struct_size = sizeof(test_struct);
constexpr test_struct t;
constexprauto t_a = t.get_c();
/* swap */
l.swap(k); // l is "xyz" and k is "34"swap(l, k); // l is "34" and k is "xyz"

About

Fast, in stack, fixed size string implementation with constexpr noexcept constructors and accessors. fixed_size_string improves memory locality and latency of strings by avoiding heap allocations.

Topics

Resources

Stars

27 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages