UTL C++ Utility Libraries

repository·master·Indexed 43 days ago

https://github.com/dmitribogdanov/utl

A collection of small, self-contained, header-only C++17 libraries for simplicity and fast prototyping in gamedev and mathematical research. Features specialized modules for enum and struct reflection (utl::enum_reflect, utl::struct_reflect), JSON parsing, parallel algorithms, PRNGs, and mathematical containers. Supports integration via individual headers, an amalgamated single-header (UTL.hpp), or CMake FetchContent.

Tokens
61.8K
Snippets
203
Records
266
Agent score
55%

What's inside UTL

  1. Overview of the utl::parallel module

    master
    The utl::parallel module is a lightweight, portable C++17 threading library designed for concurrent algorithms. It provides building blocks similar to Intel TBB, including tasks, parallel loops, and reductions. It features a work-stealing thread pool that supports recursive parallelism and a simple, uniform API. The module is header-only and has no external dependencies.
  2. Overview of utl::stre (string expansions)

    master
    The utl::stre header provides a collection of robust and efficient string utility implementations. It aims to solve common string manipulation tasks that are often implemented inefficiently or incorrectly in other libraries. The module includes tools for character classification, case conversion, trimming, padding, substring operations, tokenization, and more.
  3. Overview of utl::table

    master

    The utl::table module is a lightweight, header-only C++ utility for exporting data into various tabular formats. It is designed for concise API usage, high performance, and locale-independent formatting. It is particularly useful for numerical work, visualization, and generating reports.

    Supported formats include:

    • ASCII: For terminal output.
    • Markdown: For documentation and web-based tables.
    • LaTeX: For academic and scientific typesetting.
    • Mathematica: For Wolfram software integration.
    • CSV: For spreadsheet and data processing tools (follows RFC-4180 guidelines).
  4. Overview of the utl::json module

    master

    The utl::json module provides an intuitive, lightweight JSON manipulation API for C++17. It is designed to be a high-performance alternative to nlohmann_json with a single-header integration (less than 1k lines of code) and no external dependencies.

    Key characteristics:

    • Standard Container Mapping: All JSON types map directly to standard library containers (std::map for objects, std::vector for arrays, etc.), making it easy to integrate with existing C++ code.
    • Transparent Lookups: Objects support transparent comparators, allowing you to use std::string_view or const char* for key lookups without unnecessary allocations.
    • Recursive Reflection: Supports recursive structure reflection, including nested types and containers.
    • Type-Trait Based: Uses type-traits for conversions, allowing assignment and construction from various types.
    • Error Handling: Provides validation with descriptive error messages via exceptions.
    /* Note: This module is header-only and requires C++17 */
  5. Overview of utl::mvl (Matrix View Library)

    master

    The utl::mvl module (Matrix View Library) provides generic classes for dense, strided, and sparse vectors, matrices, and views.

    Unlike traditional matrix libraries, mvl is designed for data-oriented matrices that support arbitrary element types and behave similarly to std::vector. Its primary goals are API simplicity and interoperability with existing implementations.

    Warning: This module is currently experimental. The API and stability are not guaranteed.

  6. Overview of UTL modules

    master

    UTL provides a wide range of specialized utility modules. Each module resides in its own utl:: namespace to ensure non-intrusive usage. Key modules include:

    • utl::assertion: Enhanced diagnostic macros.
    • utl::bit: Bit-twiddling and enum bitflags.
    • utl::enum_reflect: Enum reflection capabilities.
    • utl::integral: Saturated math, safe integer casts, and rounding.
    • utl::json: JSON parsing, serialization, and reflection.
    • utl::log: Logging utilities.
    • utl::math: Additional mathematical functions.
    • utl::mvl: Generalized matrix and vector containers.
    • utl::parallel: Thread pools, async tasks, and parallel algorithms.
    • utl::predef: Architecture, compiler, and platform detection.
    • utl::profiler: Call graph and thread profiling.
    • utl::progressbar: CLI progress bars.
    • utl::random: PRNGs and random number generation.
    • utl::shell: Shell commands and temporary file management.
    • utl::sleep: Precise sleep implementations.
    • utl::stre: Efficient string utilities.
    • utl::strong_type: Strong typedefs and RAII wrappers.
    • utl::struct_reflect: Struct reflection.
    • utl::table: Exporting tables to ASCII, Markdown, LaTeX, Mathematica, and CSV.
    • utl::time: Timers, stopwatches, and datetime handling.
  7. Overview of utl::random PRNG implementations

    master

    The utl::random module provides <random>-compatible implementations of several modern Pseudorandom Number Generators (PRNGs). By default, rand functions in this header use Xoshiro256++, which offers an excellent balance of speed and statistical quality.

    When choosing a generator, consider the following trade-offs:

    • Speed: RomuMono16, RomuTrio32, and RomuDuoJr64 are extremely fast but have lower statistical quality.
    • Security: ChaCha8, ChaCha12, and ChaCha20 are cryptographically secure (CSPRNG) but come with a performance cost.
    • General Purpose: Xoshiro128PP (32-bit) and Xoshiro256PP (64-bit) are recommended for most non-cryptographic use cases.
    • Memory: Generators like SplitMix32 and SplitMix64 have very small state footprints.
    /* 
    Available PRNGs summary:
    - RomuMono16: Fastest 16-bit
    - RomuTrio32: Fastest 32-bit (Chaotic)
    - SplitMix32: Smallest state 32-bit
    - Xoshiro128PP: Best all-purpose 32-bit
    - RomuDuoJr64: Fastest 64-bit (Chaotic)
    - SplitMix64: Smallest state 64-bit
    - Xoshiro256PP: Best all-purpose 64-bit
    - ChaCha8/12/20: Cryptographically secure
    */
  8. Overview of utl::random

    master

    The utl::random module provides enhancements to the standard C++ <random> library. It is designed to be more user-friendly for common use cases, offer better performance, and provide higher-quality random number generation compared to many standard library implementations.

    Key advantages include:

    • Easier API: Simplified functions for common tasks.
    • Performance: Optimized PRNGs.
    • Reproducibility: Consistent results across different compilers.
    • constexpr Support: Generators and distributions work in constant expressions.
    • Security: Includes cryptographically secure PRNGs (CSPRNGs) like ChaCha.
    • Reliable Entropy: Better entropy sources than std::random_device.
  9. Use utl::assertion for enhanced debugging

    master

    The utl::assertion module provides a replacement for the standard C++ assert() macro. It offers improved diagnostics by decomposing expressions (printing both the condition and its evaluated value), supporting optional context messages, and allowing for custom failure handlers.

    By default, assertions are active in Debug mode (where NDEBUG is not defined) and compiled away in Release mode.

    Key Features:

    • Expression Decomposition: Automatically prints the values of simple expressions (e.g., a + b).
    • Context Messages: Pass a string as a second argument to provide specific error context.
    • Custom Handlers: Replace the default behavior (printing to std::cerr and calling std::abort()) with custom logging or stack trace logic.
    • Colorized Output: Uses ANSI colors for better readability in terminals.
    const int rows = 10;
    const int cols = 12;
    
    ASSERT(rows == cols, "Linear system requires a square matrix.");
  10. Performance characteristics of utl::parallel::ThreadPool

    master

    utl::parallel::ThreadPool is designed as a simple, standard C++17 threading API (~600 LOC) that supports recursion, a feature missing from many common standalone thread pools.

    Key Performance Insights

    • Small, Non-Recursive Tasks: utl::parallel::ThreadPool significantly outperforms std::async() because it avoids the overhead of frequent thread creation. It performs comparably to other popular thread pools like BS::thread_pool and progschj/ThreadPool.
    • Large, Non-Recursive Tasks: When task duration is large enough (typically >1ms) to overshadow scheduling overhead, std::async() performance approaches that of thread pools.
    • Recursive Tasks: This is a primary differentiator. While std::async() can handle recursion, it suffers significant slowdowns. Most popular standalone thread pools (like BS::thread_pool and progschj/ThreadPool) will deadlock when encountering recursive tasks. utl::parallel::ThreadPool handles both shallow and deep recursion efficiently without deadlocking.

    Benchmarking Context

    Benchmarks were conducted on an AMD Ryzen 5 5600H (6-core, hyper-threading disabled) using g++ 11.4.0 at -O2.

  11. Understand alternative reflection approaches

    master

    When choosing a reflection strategy for your C++ project, consider these common methodologies:

    Pretty Function Parsing

    Libraries like magic_enum or Glaze parse compiler intrinsics like __PRETTY_FUNCTION__ or __FUNCSIG__.

    • Pros: No registration macros required; very convenient.
    • Cons: Relies on implementation-defined compiler behavior; can increase compile times; may have limitations on reflected types.

    Template Metadata & Inheritance

    Some libraries use template metadata fields and inheritance.

    • Pros: Relies on language semantics rather than the preprocessor.
    • Cons: High boilerplate; intrusive semantics (difficult to use with 3rd party types).

    Map-macro (utl approach)

    Uses the preprocessor to generate metadata.

    • Pros: Minimalistic, constexpr friendly, and works well with C++17.
  12. Wrap external data with Matrix Views

    master

    To avoid copying data from external libraries (e.g., C libraries), use views. Views wrap existing memory and expose the mvl API without overhead.

    • mvl::ConstMatrixView<T, Checking, Layout>: Wraps immutable external data. Supports different memory layouts like mvl::Layout::CR (Column-Major).
    • mvl::ConstStridedMatrixView<T>: Useful for slicing specific channels from interleaved data (like RGB image buffers).
    using namespace utl;
    
    // Wrap external col-major data
    const float data[] = { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f };
    mvl::ConstMatrixView<float, mvl::Checking::NONE, mvl::Layout::CR> A(
        2, 3, data
    );
    
    // Wrap image channels from interleaved RGB data
    const uint8_t* data = { /* ... */ };
    mvl::ConstStridedMatrixView<uint8_t> R(w, h, 0, channels, data + 0);