Skip to content

Latest commit

 

History

History
386 lines (310 loc) · 11.5 KB

DOCUMENTATION.md

File metadata and controls

386 lines (310 loc) · 11.5 KB

slick-object-pool - Documentation Guide

Overview

This document provides a comprehensive guide to the documentation in slick/object_pool.hpp.

slick/object_pool.h is a deprecated compatibility shim retained for 0.1.x users: it emits a deprecation notice (suppressible with SLICK_OBJECT_POOL_NO_DEPRECATION_WARNING) and includes the .hpp. It carries no implementation and will be removed in a future release.

Documentation Style

The code uses Doxygen-style documentation comments for automatic API documentation generation.

Doxygen Tags Used

Tag Purpose Example
@file File description File-level overview
@brief Short description One-line summary
@details Detailed description In-depth explanation
@tparam Template parameter Template type requirements
@param Function parameter Parameter description
@return Return value What the function returns
@throws Exception specification When exceptions are thrown
@note Important note Additional information
@warning Warning Critical warnings
@pre Precondition Requirements before calling
@post Postcondition State after calling
@par Paragraph heading Subsection headers
@code/@endcode Code example Inline code examples
@section Documentation section Major sections
/// Inline comment Member variable docs

Documentation Coverage

File-Level Documentation

Includes:

  • Brief description of the library
  • Detailed feature list
  • Memory layout diagram
  • Type requirements
  • Thread safety guarantees
  • Usage examples
  • Author and version information

Class Documentation

object_pool Template Class

Comprehensive documentation covering:

  • Purpose and design
  • Template type requirements
  • Thread safety model
  • Performance characteristics
  • Example usage patterns

Public API Documentation

Constructors

  1. object_pool(uint32_t size)
    • Full parameter documentation
    • Exception specifications
    • Preconditions and postconditions
    • Usage examples

Destructor

  • Cleanup behavior documentation
  • Important warnings

Public Methods

  1. uint32_t size() const

    • Pool size query
    • Power-of-2 note
  2. T allocate()*

    • Comprehensive documentation
    • Behavior under different conditions
    • Heap fallback when the pool is exhausted
    • Performance characteristics
    • Thread safety guarantees
    • Usage examples
    • Important warnings
  3. T try_allocate()*

    • Pooled allocation without heap fallback
    • Returns nullptr when the pool is empty
    • Real-time / latency-critical usage
  4. void free(T obj)*

    • Dual behavior (pool vs heap)
    • Automatic detection mechanism
    • Performance notes
    • Critical warnings
  5. bool try_free(T obj)*

    • Returns a pooled object without heap cleanup
    • Reports whether the object was pool-owned
    • Caller retains ownership of non-pool objects
  6. bool is_pool_member(const T obj)*

    • Address-range ownership check
    • Thread-safe (read-only)
  7. void reset()

    • Purpose and use cases
    • Thread safety warnings
    • Testing vs production use
  8. uint32_t available()

    • Approximate objects currently in the pool, saturated into [0, size()]
    • Explicitly documented as an estimate, not a snapshot: both counters are read unsynchronized, so it is for monitoring and tests rather than for deciding whether an allocate() will succeed
  9. uint64_t heap_fallback_count()

    • Cumulative count of allocate() calls that fell through to new T()
    • The production signal for an undersized pool, or for caches parking more objects than the pool can spare
    • Monotonic; reset() does not clear it. Only written on the fallback path, so the fast path is unaffected
  10. object_pool_cache

    • Per-thread freelist that amortizes shared-atomic costs
    • allocate() / free() / flush() members
    • default_capacity(pool) - the derived default, exposed as a static so it can be queried without constructing a cache
    • Capacity sizing rule documented on the class (@section cache_sizing), with the measured floor and ceiling behind it
    • Not thread-safe; own one per thread

Private Implementation Documentation

The Producer/Consumer Handoff

There are no private helper methods - the ring operations are short enough to live inline in try_free() and try_allocate(), which keeps the memory ordering of each step visible in one place.

  1. Producer - try_free()

    • Single fetch_add sequence claim on reserved_ (the only shared operation on the producer side)
    • relaxed store of the object pointer into free_objects_[s & mask_]
    • release store of the sequence onto control_[s & mask_].data_index, which publishes the payload written above
    • The slot for a sequence is a pure function of that sequence, so there is no reservation round-trip and no wraparound bookkeeping
  2. Consumer - try_allocate()

    • relaxed load of consumed_, then an acquire load of the slot's data_index; the item is available exactly when they are equal
    • acquire load of the payload pointer before claiming the slot
    • Single compare_exchange_weak on consumed_ to claim it
    • Ordering matters here: while consumed_ still equals ci, no producer can reach sequence ci + size_ (that would require more completed free()s than completed allocate()s), so the slot cannot be overwritten, and a successful CAS proves consumed_ never left ci. Reading the payload after the claim races the producer that reuses the slot and silently drops the object published at ci

Member Variables

All member variables are documented with inline comments (///):

  • Configuration: size_, mask_
  • Storage: buffer_, lower_bound_, upper_bound_, free_objects_
  • Control: control_, reserved_, consumed_
  • Diagnostics: heap_fallbacks_ - cache-line aligned so that writing it on the fallback path does not invalidate the line holding size_/mask_, which every operation reads

Internal Structures

  1. struct slot

    • Absolute publication sequence (data_index) used to test availability
    • Member documentation
  2. Hot counters (64-bit)

    • reserved_ - producer sequence counter (single fetch_add on free())
    • consumed_ - consumer sequence counter (single CAS on allocate)
    • Each cache-line aligned to a private line to prevent false sharing
    • The consumer never reads reserved_, so the producer's fetch_add does not invalidate a line the consumer is spinning on

Generating API Documentation

Using Doxygen

  1. Install Doxygen:

    # Ubuntu/Debian
    sudo apt-get install doxygen graphviz
    
    # macOS
    brew install doxygen graphviz
    
    # Windows
    # Download from https://www.doxygen.nl/download.html
  2. Create Doxyfile:

    cd y:\repo\slick-object-pool
    doxygen -g
  3. Configure Doxyfile:

    PROJECT_NAME           = "slick-object-pool"
    PROJECT_BRIEF          = "Lock-free object pool for C++20"
    PROJECT_VERSION        = "0.2.0"
    OUTPUT_DIRECTORY       = docs
    INPUT                  = include/slick
    RECURSIVE              = YES
    EXTRACT_ALL            = YES
    EXTRACT_PRIVATE        = NO
    EXTRACT_STATIC         = YES
    GENERATE_HTML          = YES
    GENERATE_LATEX         = NO
    SOURCE_BROWSER         = YES
    INLINE_SOURCES         = YES
    HAVE_DOT               = YES
    CALL_GRAPH             = YES
    CALLER_GRAPH           = YES
    
  4. Generate Documentation:

    doxygen Doxyfile
  5. View Documentation:

    # Open in browser
    open docs/html/index.html  # macOS
    xdg-open docs/html/index.html  # Linux
    start docs/html/index.html  # Windows

Documentation Best Practices

What's Documented

✅ All public APIs - Complete parameter and return value docs ✅ Examples - Working code examples for common use cases ✅ Thread safety - Explicit guarantees and warnings ✅ Performance - Expected performance characteristics ✅ Exceptions - What exceptions are thrown and when ✅ Preconditions - Requirements before calling ✅ Postconditions - Expected state after calling ✅ Warnings - Critical usage warnings ✅ Platform notes - Platform-specific behavior

Documentation Quality

Aspect Coverage
Public API 100%
Private methods 100%
Member variables 100%
Code examples Extensive
Thread safety Explicit
Performance notes Detailed
Platform specifics Complete

Reading the Documentation

For Users (Public API)

Focus on:

  • Constructor documentation
  • allocate() and free() methods
  • Thread safety guarantees
  • Code examples
  • Warnings and notes

For Contributors (Implementation)

Additionally review:

  • Private method documentation
  • Internal structure documentation
  • Memory layout details
  • Platform-specific implementations

For Library Maintainers

Full documentation including:

  • Implementation algorithms
  • Memory ordering semantics
  • Platform-specific details
  • Performance characteristics

Documentation Examples

Well-Documented Function

/**
 * @brief Allocate an object from the pool
 *
 * @details
 * Attempts to allocate an object from the pool using lock-free operations.
 * If the pool is exhausted, allocates a new object from the heap instead.
 *
 * This method is thread-safe and lock-free for multiple concurrent callers.
 *
 * @return Pointer to an object (never returns nullptr)
 *
 * @par Behavior
 * - Pool has available objects: Returns pooled object (fast path)
 * - Pool is exhausted: Allocates from heap (slower fallback)
 *
 * @par Performance
 * - Average: O(1) with low latency (~10-30ns typical)
 * - Worst case: O(number of concurrent allocators) due to CAS retry
 *
 * @par Thread Safety
 * Lock-free, safe for concurrent calls from multiple threads
 *
 * @par Example
 * @code
 * slick::object_pool<MyStruct> pool(1024);
 * MyStruct* obj = pool.allocate();
 * obj->field = value;
 * pool.free(obj);
 * @endcode
 *
 * @note Must be paired with free() to avoid memory leaks
 * @note Returned object is NOT automatically initialized
 */
T* allocate();

Key Elements

  1. Brief - One line summary
  2. Details - In-depth explanation
  3. Return - What it returns
  4. Behavior - Different scenarios
  5. Performance - Expected performance
  6. Thread Safety - Concurrency guarantees
  7. Example - Working code
  8. Notes - Important information

Updating Documentation

When to Update

  • Adding new public methods
  • Changing method signatures
  • Modifying behavior
  • Adding new features
  • Fixing bugs that change semantics
  • Performance improvements

Documentation Checklist

When adding/modifying code:

  • Add/update @brief description
  • Add/update @details if complex
  • Document all parameters with @param
  • Document return value with @return
  • List exceptions with @throws
  • Add thread safety notes
  • Include performance characteristics
  • Add code example if helpful
  • Add warnings if needed
  • Update file-level docs if major change

Related Documentation

  • README.md - User-facing documentation and examples
  • CHANGES.md - Migration guide and changelog
  • Comments in code - Implementation notes (not in public API docs)

Documentation Version: 1.0 Last Updated: 2025 Maintained By: SlickQuant