You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow the file you are in: match its established short-name convention rather than introducing a lone outlier, and do not leave a cryptic domain `a`/`r`/`c` in new code whose neighbours are spelled out.
191
191
-**Braces:** Allman style -- opening brace on its own line for functions and classes, same line for control flow within a function body using K&R-style indented blocks. Single-statement control bodies are not required to be braced: the formatter's `InsertBraces` is intentionally left unset, so a brace-less guard clause (`if (cond) return;`) is fine; brace any multi-line or non-obvious body.
192
192
-**Indentation:** 4 spaces, no tabs.
193
-
-**Namespaces:** All public API lives in `namespace DetourModKit`. No `using namespace` in headers. In `.cpp` files, wrap the library's own definitions in an explicit `namespace DetourModKit { ... }` block rather than a file-scope `using namespace DetourModKit;`; the block form is the house default (the few remaining files that still open with a file-scope `using namespace DetourModKit;` are tolerated and should migrate to the block form when next touched). Every closing namespace brace must have a trailing comment: `} // namespace DetourModKit`. Implementation-only statics in `.cpp` files must be in an anonymous namespace (not a named internal namespace) to guarantee internal linkage.
193
+
-**Namespaces:** All public API lives in `namespace DetourModKit`. No `using namespace` in headers. In `.cpp` files, wrap the library's own definitions in an explicit `namespace DetourModKit { ... }` block rather than a file-scope `using namespace DetourModKit;`; the block form is the house default and is used by every `.cpp` in the library; no translation unit opens with a file-scope `using namespace DetourModKit;`. Every closing namespace brace must have a trailing comment: `} // namespace DetourModKit`. Implementation-only statics in `.cpp` files must be in an anonymous namespace (not a named internal namespace) to guarantee internal linkage.
194
194
-**Include guards:** All headers use `#ifndef DETOURMODKIT_<MODULE>_HPP` / `#define` / `#endif` guards (not `#pragma once`). Guard names must be prefixed with `DETOURMODKIT_` to avoid collisions with consumer projects.
195
195
-**Includes:** Project headers use `"DetourModKit/header.hpp"`. System/external headers use `<angle brackets>`. Group: project headers, then external, then standard library.
196
196
@@ -390,7 +390,7 @@ These are called at 60+ fps from game hook callbacks. Never add allocations, exc
390
390
-`Logger::log()` level check -- single atomic load
-`Memory::is_readable_nonblocking()` -- try_lock_shared + cache lookup (returns Unknown on contention)
393
+
-`Memory::is_readable_nonblocking()` -- try_lock_shared + cache lookup (returns Unknown on lock contention, a cache miss, or the init-publication window; falls back to a blocking VirtualQuery before `init_cache()`)
394
394
-`Memory::read_ptr_unsafe()` -- SEH-protected raw dereference (MSVC), vectored-handler-guarded read on MinGW (no per-call VirtualQuery; the fault guard also closes the stale-cache dereference)
395
395
-`Memory::read_ptr_unchecked()` -- inline pointer dereference with source and result user-mode range guards (a low-address floor plus a `USERSPACE_PTR_MAX` ceiling that rejects kernel-range and non-canonical values, which also subsumes pointer-arithmetic wraparound), no SEH (caller must guarantee structural pointer validity); debug builds add an `is_readable` assert that catches a stale or unmapped source pointer, compiled out in release so the hot path stays a single guarded memcpy
396
396
- `Memory::seh_read<T>()` / `seh_read_bytes()` -- typed and raw SEH-guarded reads; single `__try` frame on MSVC, and on MinGW a single `rep movsb` copy under a process-wide vectored exception handler (installed lazily / by `init_cache`, removed by `shutdown_cache`) that recovers via a non-unwinding `__builtin_setjmp`/`__builtin_longjmp`, so the success path runs no syscall. Both toolchains swallow the same foreign-read fault set -- `EXCEPTION_ACCESS_VIOLATION`, `STATUS_GUARD_PAGE_VIOLATION`, and `EXCEPTION_IN_PAGE_ERROR` (a file-backed or image-mapped page failing to page in, e.g. during an RTTI / section walk) -- via the shared predicate `Memory::detail::is_guarded_read_fault`, and let any other fault continue the handler search; the MinGW handler additionally claims only faults whose address lies in the foreign range being read. A guarded read uses a single per-thread guard, so it must not nest on one thread (DMK reads are synchronous, so it does not); if `AddVectoredExceptionHandler` ever fails the reads fall back to VirtualQuery validation. Used by `Rtti` for chained RTTI walks
@@ -407,7 +407,7 @@ These are called at 60+ fps from game hook callbacks. Never add allocations, exc
407
407
408
408
-**Do not modify** files under `external/` -- these are git submodules.
409
409
-**Do not add**`using namespace` directives in header files.
410
-
-**Prefer** an explicit `namespace DetourModKit { ... }` block over a file-scope `using namespace DetourModKit;` in `.cpp` files (the block form is the majority house style).
410
+
-**Use** an explicit `namespace DetourModKit { ... }` block, never a file-scope `using namespace DetourModKit;`, in `.cpp` files. The block form is the house style across every translation unit.
411
411
-**Do not add** heap allocations on hot paths (see list above).
412
412
-**Do not break** the lock ordering documented in class headers.
413
413
-**Do not weaken** atomic memory orderings without proving correctness.
@@ -437,4 +437,5 @@ These are called at 60+ fps from game hook callbacks. Never add allocations, exc
437
437
-**Do not let** a queue or backlog fed at an external event rate grow without bound -- clamp the pending count to a documented ceiling (see `Input` wheel-notch `MAX_WHEEL_PENDING`).
438
438
-**Do not let** an async/deferred sink diverge from its synchronous counterpart's configuration (timestamp format, level, etc.) -- carry the same settings through, as `Logger::enable_async_mode` does for the timestamp format.
439
439
-**Do not open** a shared append-mode file with `GENERIC_WRITE` plus a one-time `SetFilePointer(FILE_END)` seek -- request `FILE_APPEND_DATA` so the OS positions every write at the current end of file atomically and concurrent appenders cannot interleave or overwrite each other (see `WinFileStreamBuf::open`). Truncating (`out`) mode keeps `GENERIC_WRITE` + `CREATE_ALWAYS`.
440
+
-**Do not assume** a single `WriteFile` drains the whole request -- it can report success with `bytes_written < count` (a short write on a pipe, a near-full volume, or an interrupted write). Loop over the unwritten remainder so a buffered tail is never silently dropped, resetting the put area only after the buffer fully drains or the write hard-fails (see `WinFileStreamBuf::flush_buffer`).
440
441
-**Do not drop** the device source when formatting an off-table input code -- a non-keyboard code must serialize in the source-tagged hex form (`Mouse:0xNN`) that `parse_input_name` reads back, or it silently round-trips to a keyboard key (see `format_input_code` / `parse_input_name`).
0 commit comments