Skip to content

Repository files navigation

nfx-stringbuilder

License: MITGitHub release (latest by date)GitHub tag (latest by date)

C++17/20CMakeCross Platform

Linux GCCLinux ClangWindows MinGWWindows MSVCCodeQL

A cross-platform C++17/C++20 high-performance string builder with Small Buffer Optimization and efficient memory management

Overview

nfx-stringbuilder is a modern C++ library providing efficient string building capabilities with zero heap allocations for small strings (≤256 bytes). Designed for applications requiring high-performance string concatenation with minimal allocations, it features Small Buffer Optimization (SBO) and comprehensive type support. It builds with C++17 or C++20: the core API is fully available under C++17, while C++20 additionally enables the std::format-based format() method and the std::formatter specialization.

Key Features

🛠️ Rich String Building Interface

  • Fluent API: Method chaining and stream operators (<<) for natural concatenation
  • Variadic append(): Batch multiple arguments in a single call for optimal performance
  • Type Support: Strings, string_view, C-strings, characters, and numeric types (int8/16/32/64, uint8/16/32/64, float, double)
  • C++20 std::format Integration: Template format() method for modern formatting (requires C++20)
  • std::formatter Specializations: Zero-copy integration with std::format for StringBuilder (requires C++20)
  • Capacity Hints: Pre-allocate buffers with constructor parameter for optimal performance
  • Direct Buffer Access: High-performance operations without wrappers
  • Iterator Support: Range-based for loops and STL algorithms

📊 Real-World Applications

  • Web Servers & HTTP: Building request/response strings, headers, JSON payloads
  • Logging Systems: High-frequency log message formatting with minimal allocations
  • SQL Query Generation: Dynamic query construction from parameters and conditions
  • Template Rendering: Efficient HTML/XML generation from templates
  • Data Serialization: CSV, JSON, XML output generation with streaming performance
  • Command-Line Tools: Building formatted output, tables, and progress indicators

⚡ Performance Optimized

  • Small Buffer Optimization (SBO): 256-byte stack buffer eliminates heap allocations for most strings
  • Zero-Copy Operations: string_view access without allocation
  • Batch Operations: Variadic append() reduces function call overhead
  • Sub-Microsecond Operations: Competitive with {fmt} and Abseil
  • Memory Efficiency: Smart capacity management and growth strategies

🌍 Cross-Platform Support

  • Operating Systems: Linux, Windows
  • Compilers: GCC 14+, Clang 18+, MSVC 2022+
  • Thread-Safe: Each StringBuilder instance is thread-safe when not shared
  • Consistent Behavior: Same performance characteristics across platforms

Quick Start

Requirements

  • C++17 or C++20 compatible compiler:
    • GCC 14+ (14.2.0 tested)
    • Clang 18+ (19.1.7 tested)
    • MSVC 2022+ (19.44+ tested)
  • CMake 3.20 or higher

C++ standard: The library defaults to building with C++20. Select the standard explicitly with -DNFX_STRINGBUILDER_CXX_STANDARD=17 or =20. Under C++17 the entire API is available except the std::format-based format() method and the std::formatter<StringBuilder> specialization, which require C++20. The exported nfx-stringbuilder::static and nfx-stringbuilder::nfx-stringbuilder targets propagate a minimum requirement of C++17 to consumers, who may compile at a higher standard than the library was built with.

CMake Integration

# --- Library build types ---option(NFX_STRINGBUILDER_BUILD_STATIC"Build static library"ON )
option(NFX_STRINGBUILDER_BUILD_SHARED"Build shared library"OFF)
# --- Language standard (17 or 20; C++20 enables std::format APIs) ---set(NFX_STRINGBUILDER_CXX_STANDARD "20"CACHESTRING"C++ standard used to build nfx-stringbuilder (17 or 20)")
# --- Build components ---option(NFX_STRINGBUILDER_BUILD_TESTS"Build tests"OFF)
option(NFX_STRINGBUILDER_BUILD_SAMPLES"Build samples"OFF)
option(NFX_STRINGBUILDER_BUILD_BENCHMARKS"Build benchmarks"OFF)
option(NFX_STRINGBUILDER_BUILD_COMPARATIVE_BENCHMARKS"Build comparative benchmarks"OFF)
option(NFX_STRINGBUILDER_BUILD_DOCUMENTATION"Build Doxygen documentation"OFF)
# --- Performance optimizations ---option(NFX_STRINGBUILDER_ENABLE_SIMD"Enable SIMD optimizations"ON )
# --- Installation ---option(NFX_STRINGBUILDER_INSTALL_PROJECT"Install project"OFF)
# --- Packaging ---option(NFX_STRINGBUILDER_PACKAGE_SOURCE"Enable source package generation"OFF)

Using in Your Project

Option 1: Using FetchContent (Recommended)

include(FetchContent)
FetchContent_Declare(
nfx-stringbuilder
GIT_REPOSITORY https://github.com/nfx-libs/nfx-stringbuilder.git
GIT_TAG main # or use specific version tag like "0.1.0"
)
FetchContent_MakeAvailable(nfx-stringbuilder)
# Link with static librarytarget_link_libraries(your_targetPRIVATEnfx-stringbuilder::static)

Option 2: As a Git Submodule

# Add as submodule
git submodule add https://github.com/nfx-libs/nfx-stringbuilder.git third-party/nfx-stringbuilder
# In your CMakeLists.txtadd_subdirectory(third-party/nfx-stringbuilder)
target_link_libraries(your_targetPRIVATEnfx-stringbuilder::static)

Option 3: Using find_package (After Installation)

find_package(nfx-stringbuilderREQUIRED)
target_link_libraries(your_targetPRIVATEnfx-stringbuilder::static)

Building

Build Commands:

# Clone the repository
git clone https://github.com/nfx-libs/nfx-stringbuilder.git
cd nfx-stringbuilder
# Create build directory
mkdir build &&cd build
# Configure with CMake
cmake .. -DCMAKE_BUILD_TYPE=Release
# Build the library
cmake --build . --config Release --parallel
# Run tests (optional)
ctest -C Release --output-on-failure
# Run benchmarks (optional)
./bin/benchmarks/BM_StringBuilder

Documentation

nfx-stringbuilder includes API documentation generated with Doxygen.

📚 Online Documentation

The complete API documentation is available online at: https://nfx-libs.github.io/nfx-stringbuilder

Building Documentation Locally

# Configure with documentation enabled
cmake .. -DCMAKE_BUILD_TYPE=Release -DNFX_STRINGBUILDER_BUILD_DOCUMENTATION=ON
# Build the documentation
cmake --build . --target nfx-stringbuilder-documentation

Requirements

  • Doxygen - Documentation generation tool
  • Graphviz Dot (optional) - For generating class diagrams

Accessing Local Documentation

After building, open ./build/doc/html/index.html in your web browser.

Usage Examples

Basic String Building

#include<nfx/string/StringBuilder.h>usingnamespacenfx::string;intmain()
{
// Create a StringBuilder instance
StringBuilder builder;
// Build strings with fluent interface
builder.append("Hello")
.append(", ")
.append("World")
.append("!");
// Convert to std::string
std::string result = builder.toString();
// Output: "Hello, World!"return0;
}

Efficient String Concatenation

#include<nfx/string/StringBuilder.h>
#include<vector>usingnamespacenfx::string;
std::string buildReport(const std::vector<std::string>& items)
{
StringBuilder builder;
// Reserve capacity for better performance
builder.reserve(1024);
// Build header
builder.append("=== Report ===\n");
// Add itemsfor (size_t i = 0; i < items.size(); ++i)
{
builder.append("Item ")
.append(std::to_string(i + 1))
.append(": ")
.append(items[i])
.append("\n");
}
// Add footer
builder.append("Total items: ")
.append(std::to_string(items.size()));
return builder.toString();
}

Working with Different String Types

#include<nfx/string/StringBuilder.h>usingnamespacenfx::string;voiddemonstrateStringTypes()
{
StringBuilder builder;
// std::string
std::string stdStr = "from std::string";
builder.append(stdStr)
.append(" | ");
// string_view (zero-copy)
std::string_view sv = "from string_view";
builder.append(sv)
.append(" | ");
// C-string
builder.append("from C-string")
.append(" | ");
// Single characters
builder.append('A')
.append('B')
.append('C');
std::string result = builder.toString();
// Output: "from std::string | from string_view | from C-string | ABC"
}

Numeric Type Support

#include<nfx/string/StringBuilder.h>usingnamespacenfx::string;voiddemonstrateNumericTypes()
{
StringBuilder builder;
// Integer typesint32_ti32 = -42;
uint32_tu32 = 42;
int64_ti64 = -9223372036854775807LL;
uint64_tu64 = 18446744073709551615ULL;
builder.append("int32_t: ")
.append(i32) // Direct numeric append
.append(", uint32_t: ")
.append(u32)
.append(", int64_t: ")
.append(i64)
.append(", uint64_t: ")
.append(u64);
// Floating-point typesfloat f = 3.14159f;
double d = 2.718281828459045;
builder.append("\nfloat: ")
.append(f) // Direct numeric append
.append(", double: ")
.append(d);
std::string result = builder.toString();
// Output: "int32_t: -42, uint32_t: 42, int64_t: -9223372036854775807, uint64_t: 18446744073709551615// float: 3.14159, double: 2.71828"
}
voiddemonstrateStreamOperators()
{
StringBuilder builder;
// Stream operators work with all numeric typesint value = 42;
double price = 19.99;
builder << "Product #" << value << " costs $" << price;
std::string result = builder.toString();
// Output: "Product #42 costs $19.99"
}
voiddemonstrateVariadicAppend()
{
StringBuilder builder;
// Append multiple arguments at onceint userId = 12345;
constchar* userName = "alice";
int64_t timestamp = 1672531200;
builder.append("User ", userId, " (", userName, ") logged in at ", timestamp);
std::string result = builder.toString();
// Output: "User 12345 (alice) logged in at 1672531200"
}

format() Method Integration

#include<nfx/string/StringBuilder.h>usingnamespacenfx::string;voiddemonstrateFormatMethod()
{
StringBuilder builder;
// Using StringBuilder's format() method directly
builder.append("User: ");
builder.format("{} (ID: {:08})", "Alice", 123);
builder.append("\n");
// Format with floating-point precision
builder.append("Price: ");
builder.format("${:.2f}", 19.99);
builder.append("\n");
// Format with hex and binary
builder.append("Value: ");
builder.format("hex=0x{:X}, bin=0b{:b}", 255, 15);
std::string result = builder.toString();
// Output: "User: Alice (ID: 00000123)// Price: $19.99// Value: hex=0xFF, bin=0b1111"
}
voiddemonstrateFormatChaining()
{
StringBuilder builder;
// format() returns reference for chaining
builder.format("Name: {}", "Bob")
.append(" | ")
.format("Age: {}", 30)
.append(" | ")
.format("Score: {:.1f}", 95.7);
std::string result = builder.toString();
// Output: "Name: Bob | Age: 30 | Score: 95.7"
}

C++20 std::formatter Integration

#include<nfx/string/StringBuilder.h>
#include<format>usingnamespacenfx::string;voiddemonstrateStdFormatter()
{
StringBuilder builder;
builder.append("Hello, ")
.append("World!");
std::string formatted = std::format("Result: {}", builder);
std::string bufferFormatted = std::format("Buffer content: {}", builder);
}

Capacity Hints for Pre-allocation

#include<nfx/string/StringBuilder.h>usingnamespacenfx::string;voiddemonstrateCapacityHints()
{
// Pre-allocate 2048 bytes to avoid reallocations
StringBuilder builder(2048);
// Build large strings without reallocationfor (int i = 0; i < 100; ++i)
{
builder.append("Item ")
.append(std::to_string(i))
.append(": Some long description text here\n");
}
std::string result = builder.toString();
// No heap reallocations occurred during building
}

Direct Buffer Manipulation

#include<nfx/string/StringBuilder.h>usingnamespacenfx::string;voiddirectBufferAccess()
{
StringBuilder builder;
// Append methods with chaining
builder.append("Direct ")
.append("buffer ")
.append("access")
.append('!');
// Get size and capacitysize_t size = builder.size(); // Current content sizesize_t capacity = builder.capacity(); // Allocated capacity// Zero-copy string_view access
std::string_view view = builder.toStringView();
// Iterator supportfor (char c : builder)
{
// Process each character
}
// Clear for reuse
builder.clear();
}

Multi-threaded Usage

#include<nfx/string/StringBuilder.h>
#include<thread>
#include<vector>usingnamespacenfx::string;voidthreadWorker(int threadId)
{
// Each thread creates its own StringBuilder instancefor (int i = 0; i < 100; ++i)
{
StringBuilder builder;
builder.append("Thread ")
.append(std::to_string(threadId))
.append(" - Iteration ")
.append(std::to_string(i));
std::string result = builder.toString();
// Process result...
}
}
voiddemonstrateMultithreading()
{
std::vector<std::thread> threads;
// Spawn multiple threadsfor (int i = 0; i < 4; ++i)
{
threads.emplace_back(threadWorker, i);
}
// Wait for completionfor (auto& t : threads)
{
t.join();
}
std::cout << "All threads completed successfully\n";
}

Sample Output:

[INFO] User logged in: username=john.doe, ip=192.168.1.100, timestamp=2025-10-31
[ERROR] Connection failed: timeout after 30s

Project Structure

nfx-stringbuilder/
├── benchmark/ # Performance benchmarks with Google Benchmark
├── cmake/ # CMake modules and configuration
├── include/nfx/ # Public headers
├── samples/ # Example usage and demonstrations
├── src/ # Implementation files
└── test/ # Comprehensive unit tests with GoogleTest

Performance

For detailed performance metrics and benchmarks, see:

Roadmap

See TODO.md for upcoming features and project roadmap.

Changelog

See the CHANGELOG.md for a detailed history of changes, new features, and bug fixes.

License

This project is licensed under the MIT License.

Dependencies

Development Dependencies

  • GoogleTest: Testing framework (BSD 3-Clause License) - Development only
  • Google Benchmark: Performance benchmarking framework (Apache 2.0 License) - Development only
  • {fmt}: Fast formatting library (MIT License) - Benchmarking only
  • Abseil: C++ common libraries (Apache 2.0 License) - Benchmarking only

All dependencies are automatically fetched via CMake FetchContent when building the library, tests, or benchmarks.


Updated on February 15, 2026

About

Cross-platform C++20 library for zero-allocation string building with Small Buffer Optimization

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages