Skip to content

Instantly share code, notes, and snippets.

@benkant
Last active August 15, 2025 05:40
Show Gist options
  • Save benkant/9937f7468e9da38ac209b67847d7dc8c to your computer and use it in GitHub Desktop.
Save benkant/9937f7468e9da38ac209b67847d7dc8c to your computer and use it in GitHub Desktop.
Transformer Friendly C++
# .clang-format for Transformer Friendly C++ (see attached)
BasedOnStyle: Google
Language: Cpp
# Indentation and tabs
IndentWidth: 4
TabWidth: 4
UseTab: Never
# Line length
ColumnLimit: 100
# Braces on own line
BreakBeforeBraces:
Function: True
Class: True
Namespace: True
Control: True
Enum: True
Block: True
# Keep one statement per line
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
# Pointer and reference alignment
PointerAlignment: Left # Test* ptr, not Test *ptr
ReferenceAlignment: Left # Test& ref, not Test &ref
# Spaces
SpaceBeforeParens:
ControlStatements: True
FunctionDeclaration: False
FunctionCall: False
# C-style arrays and pointers
DerivePointerBinding: false
# Namespace and include guard style
NamespaceIndentation: Inner # indent code inside namespaces
IncludeBlocks: Regroup
# Align consecutive assignments and declarations
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
# Indent case labels at same level as switch
IndentCaseLabels: false
# Formatting of comments
ReflowComments: false
CommentPragmas: '^ IWYU pragma:'
# Keep includes and macros at the left margin
AllowAllParametersOfDeclarationOnNextLine: false
# Avoid reflowing preprocessor directives
PPIndentWidth: 0
# Misc
SortIncludes: false
Standard: Cpp14

Transformer friendly C++ Style

Not very scientific, but it works better for me than my usual mix of C++11-17.


File and Module Layout

  • Filenames: module.h / module.cpp. Header first, then implementation.
  • Include Guards: Simple and unique, matching the header name:
    #ifndef AUDIO_H
    #define AUDIO_H
    //
    #endif // AUDIO_H
  • Ordering in Headers:
    1. Public API functions (create_…, destroy_…)
    2. Data types and structs
    3. Internal helpers declared static in the .cpp only

Coding Conventions

1. Formatting and Indentation

  • Indentation: 4 spaces, no tabs.
  • Braces: Always on their own line:
    void foo()  
    {  
        //
    }
  • Line Length: ≤ 100 characters. Break long expressions sensibly on operators.

2. Naming

  • Types and Structs: PascalCase (e.g., AudioBuffer).
  • Functions: snake_case (e.g., create_audio_buffer).
  • Variables: lower_case with underscores (e.g., sample_count).
  • Macros and Constants: ALL_CAPS (e.g., MAX_SAMPLE_COUNT).
  • Member Variables: Prefix with m_ (e.g., m_samples), but avoid if the code is C-style plain structs.

3. Commenting

  • Function Headers: Brief one-line description, parameters, return value.
  • Block Comments: Use /* … */ for lengthy explanations; // for line comments.
  • No Redundant Comments: Don’t comment “increments i” next to i++; reserve comments for design rationale or non-obvious behavior.

Language Subset and Patterns

4. C-Style Allocation & Ownership

  • Factory/Destructor Pairs:
    AudioBuffer* create_audio_buffer(int sample_count);  
    void          destroy_audio_buffer(AudioBuffer* buf);
  • malloc/free preferred over new/delete to avoid exceptions and simplify failure handling.
  • Explicit Null Checks: Always verify returned pointers before use.

5. Plain Data Structures

  • No STL Containers: Use raw arrays or hand-rolled pools for predictability.
  • Separate Pointer and Size:
    void process_samples(float* samples, int count);

6. Functions: Single Responsibility

  • create_*: allocates resources only.
  • destroy_*: frees resources only.
  • process_*: operates on existing data only.

C++ Features: The Minimal Subset

7. Permitted Features

  • Classes and Inheritance: Single inheritance only; pure virtual interfaces allowed.
  • Lambdas: Sparingly, for simple callbacks—no std::function.
  • constexpr: For compile-time constants (e.g., buffer-size limits).
  • static_assert: Validate assumptions (e.g., static_assert(sizeof(AudioBuffer) == 16);).

8. Forbidden or Discouraged Features

  • Exceptions: Disabled (-fno-exceptions); use error codes instead.
  • RTTI: Disabled (-fno-rtti); avoid dynamic_cast or typeid.
  • Templates: No custom template classes; only standard std::uint32_t, etc.
  • STL Algorithms/Containers: No <vector>, <string>, or their algorithms.

Performance and Multithreading


9. Data Locality and Alignment (Optimized for Ryzen 9 + Radeon 780M)

  • Cache-Friendly Structs
    • Organize hot-path data to fit within the Ryzen’s 32 KiB L1 and 512 KiB L2 per core caches.
    • Group frequently accessed members together; pad to 64-byte cache lines only when absolutely necessary.
  • SIMD Alignment
    • Align performance-critical buffers to 32-byte boundaries to leverage AVX2 on the 7940HS.
    • Use posix_memalign(&ptr, 32, size) for frame-buffer or particle data structures.
  • Memory Bandwidth
    • Spread large read-only tables across the 96 GiB DDR5 channels to avoid saturating a single channel.
    • Pre-touch pages during load to avoid page-fault stalls on Linux.

10. Job System and SMP (8 Cores / 16 Threads)

  • Fine-Grained Job Queues
    • Split work into small jobs (~1–2 ms each) so the 16 hardware threads stay busy without contention.
    • Use a lock-free ring buffer per NUMA node to reduce cross-core cache bouncing.
  • Affinity and Load Balancing
    • Pin rendering jobs to one physical core’s thread pair to isolate Vulkan calls on the launch thread.
    • Distribute workers and services evenly across the remaining 14 threads.
  • Vulkan Command Submission
    • Record command buffers in parallel on multiple threads, then submit on the dedicated render thread.
    • Triple-buffer your per-frame resources (descriptor pools, dynamic uniform buffers) to avoid CPU–GPU synchronization stalls.
  • Thread Synchronization
    • Favor lightweight spin-locks or atomic flags for sub-microsecond critical sections.
    • Batch cross-thread wake-ups (e.g., futex on Linux) to reduce scheduling overhead.

Error Handling and Diagnostics

11. Error Codes

  • Return int or enum: Zero for success, nonzero for failure.
  • Logging: Use common->Warning or common->FatalError for non-recoverable issues; no exceptions.

12. Assertions

  • assert() for invariant checks in debug builds only.
  • No Release aborts: Code must handle all edge cases gracefully.

Integration Guidelines

13. Scripting vs. Native Code

  • Game Logic: In native C++ only—no reliance on interpreted bytecode for core behaviors.
  • Scripting Engine: Reserved for high-level events; minimal performance impact.

14. Text vs. Binary Data

  • Binary Formats: Preferred for large meshes or textures (avoid startup slowdowns).
  • Text Formats: Only for small, frequently edited assets (e.g., scripting, config).

Summary

  1. C-Style APIs: Raw pointers, explicit counts.
  2. Manual Memory Management: malloc/free, create_…/destroy_….
  3. Minimal C++: No exceptions, RTTI, templates, or STL.
  4. Predictable Structure: One function, one job; rigid naming; no hidden state.
  5. Performance-Centric: Data locality, simple threading, and compile-time checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment