//===-- cstddef - `std::size_t`, and only because we are the ones who ------===//
//===-- spelled it qualified                                          ------===//
//
// This is what `#include <cstddef>` resolves to when the compiler is NVRTC and
// the include path is a header set carried in the binary rather than a
// directory on a disk. `csrc/shim/cstdint` makes the general argument at
// length and this file is the same rule applied to one more standard header;
// what is worth writing down here is why the two files disagree about `std`.
//
// # Measured, not assumed
//
// The FA2 lattice's root (`csrc/src/attn/fa2.cuh`) reaches
// `attn/attention_score_capture.cuh`, whose line 27 is `#include <cstddef>`.
// Without this file that include is a **catastrophic error: cannot open source
// file "cstddef"** and the compile stops before it has parsed a single
// FlashInfer template -- so the failure arrives with no useful diagnostic
// about anything else. Found with a `/tmp` `libnvrtc` probe against the real
// header, which is the only way it could have been found before a GPU run:
// `tests/layers.rs::every_include_reachable_from_a_unit_resolves` walks QUOTED
// includes and this one is angle-bracketed.
//
// # Why `std` here and not in `cstdint`
//
// `csrc/shim/cstdint` deliberately omits the `std::` half, and its reason is
// specific: FlashInfer spells `uint32_t` and its relatives unqualified at all
// 2928 sites, so `namespace std` there would be dead text.
//
// The inverse holds for this file. `<cstddef>` is included by
// `attention_score_capture.cuh`, which is **ours**, and which writes
// `std::size_t` at five sites (`:108`, `:177`, `:191-193`). NVRTC's built-in
// preamble declares `size_t` in the GLOBAL namespace and nowhere else, so the
// qualified spelling is exactly what is missing and exactly what this file
// supplies. Neither shim is guessing at a standard library surface; each
// carries the names its actual includers write.
//
// The alternative was to unqualify those five sites. It was rejected because
// the direction is wrong: a shim exists so that source compiles unmodified,
// and reaching into a header to change how it spells a standard name to suit
// the impersonator is the habit that ends with a source tree shaped by its
// build. `attention_score_capture.cuh` is also compiled by nvcc today, where
// `std::size_t` is simply correct.
//
// # What is deliberately NOT here
//
// `NULL`, `max_align_t`, `std::byte`. A grep over everything that
// reaches this file names none of them. `csrc/shim/cstdint` argues the
// discipline: a shim that grows to the standard's surface becomes a second set
// of promises to disagree with the first, and the disagreement is silent.
//
// `size_t` and `ptrdiff_t` are NOT typedef'd here either -- NVRTC's preamble
// already declares both in the global namespace, and naming them again would
// be a redefinition rather than a courtesy. This file only re-exports them.
//
// # `offsetof` -- added and REMOVED the same day; the measurement is kept
//
// `csrc/src/moe/moe_glue.cuh` restated probe `C20`'s measured layout of
// `TmaWarpSpecializedGroupedGemmInput` as ten `static_assert`s -- a hazard
// converted to a build error -- and that needs `offsetof` in a **constant
// expression**. That file is deleted with the fused CUTLASS MoE
// (`new-horizon.md` §71), so the macro has no asking site and is not defined
// below: the shim is a floor, and only additions that close a gap belong in
// it.
//
// The measurement stays, because unlike the seven `cutlass/` headers that
// went with it **this one is a fact about NVRTC rather than about CUTLASS**,
// and the next carried header that restates an upstream struct will need it.
// Probe `C22`, CARRIED order, one struct, six candidates:
//
// ```text
//   __builtin_offsetof(S, d)                 rc=6  "type name is not allowed"
//   offsetof(S, d)          (unprefixed)     rc=6  "type name is not allowed"
//   (unsigned long)(&((S*)0)->d)             rc=6  "must have a constant value"
//   (char*)&((S*)0)->d - (char*)(S*)0        rc=6  "must have a constant value"
//   (char*)&s_.d - (char*)&s_   (extern S)   rc=6  "must have a constant value"
//   __INTADDR__(&((S*)0)->d)                 rc=0
// ```
//
// `__INTADDR__` is EDG's intrinsic, and NVRTC's frontend is EDG. The pointer
// forms are the ones the offset *probes* in `nvrtc-probes/` use, and they work
// there for the opposite reason: a `__constant__` initialiser is folded into
// `.b8` bytes rather than evaluated as a constant expression by the front end.
// **The same expression is legal in one position and not the other**, which is
// why this was a row rather than a note saying "use the probe's trick" -- and
// why re-adding it needs no new probe. The one line is:
//
// ```c
//   #define offsetof(T, F) __INTADDR__(&(((T*)0)->F))
// ```

#ifndef PIE_NVRTC_CSTDDEF_
#define PIE_NVRTC_CSTDDEF_

namespace std {

// Re-exports, not declarations. `using` rather than `typedef` so that
// `std::size_t` and `::size_t` are the SAME type by construction: a typedef
// would name the same underlying integer today and could be edited into a
// second opinion, and a mismatch between the two spellings is the kind of
// error that surfaces as a template deduction failure a hundred frames deep.
using ::ptrdiff_t;
using ::size_t;

}  // namespace std

#endif  // PIE_NVRTC_CSTDDEF_
