Skip to content

Conversation

StephanTLavavej
Copy link
Member

@StephanTLavavej StephanTLavavej commented Sep 7, 2025

Over the years, we've minimized the amount of TR1 legacy machinery that we emit in modern modes (C++17 and later). The last headache has been how various <random> engines and distributions were implemented by deriving from their earlier TR1 incarnations. This PR fuses the TR1 machinery into the Standard types, so that the inheritance is no longer necessary, and the TR1 types can now be guarded along with the rest. This also makes the Standard types significantly easier to understand.

Importantly, this doesn't affect runtime behavior or layout, so the change preserves bincompat. I verified this with sizeof, alignof, and our most powerful tool /d1reportSingleClassLayout. This of course has source-breaking impact if someone was referring to the TR1 types in modern modes (and had disregarded our deprecation warnings), with upgrading being fairly easy. There is also minor source-breaking impact for obscure scenarios (e.g. someone giving a pre-Standard engine to a Standard distribution, which happened in one of my old tests being updated here).

This works towards the complete removal of TR1, which I'll do in a followup PR.

⚙️ Commits

Click to expand commit descriptions:
  • Fix &arr[size] in subtract_with_carry_engine/mersenne_twister_engine::seed().
  • Move _Kx to be local to subtract_with_carry_engine::seed().
  • Overhaul _Swc_traits::_Get_wc() to be private, constexpr, and simplified.
    • Manually tested, see below.
  • Fuse subtract_with_carry into subtract_with_carry_engine.
    • We no longer need to suppress the deprecation warning.
    • We inherit directly from _Swc_base now. (After TR1 removal, we can fuse that away too, which will be a much larger simplification.)
    • Drop a pointless comment.
    • We now directly say that _Traits is an _Swc_traits.
    • subtract_with_carry's default constructor passed 0u to _Swc_base's constructor, so we do that.
    • Cleanup: Simplify operator!=().
  • Make more subtract_with_carry_engine machinery private.
  • Fuse mersenne_twister into mersenne_twister_engine.
    • We no longer need to suppress the deprecation warning.
    • We inherit directly from _Circ_buf now. That inheritance continues to be private, whereas mersenne_twister inherits from _Circ_buf publicly.
    • We no longer need a _Mybase alias.
    • When constructing mersenne_twister_engine(_Seed_seq& _Seq), avoid redundantly calling seed(default_seed) before seed(_Seq).
    • _WMSK is a direct member now.
    • Cleanup: Simplify operator!=().
    • Note that operator>>() for mersenne_twister calls _Eng.seed(_Gen) which is radically different from mersenne_twister_engine's seed(_Seed_seq& _Seq). Accordingly I've inlined the old implementation (which directly loads the serialized values).
    • operator<<() for mersenne_twister uses mersenne_twister::state_size as a bound. This is just _Nx, which I've chosen to use for increased symmetry with the other operator.
    • _Refill_lower() etc. are private (same as before when they were inherited privately).
  • Make more mersenne_twister_engine machinery private.
  • mersenne_twister_engine: _Dxval is always _Dx; hardcode it, and note that the data member is retained for bincompat.
  • Fuse _Discard_block_base into discard_block_engine.
    • This was very close to the finish line. Instead of switching between the old discard_block and the newer _Discard_block_base (introduced by Implement LWG-3561 Issue with internal counter in discard_block_engine #4066), simply make _Nx's type vary.
    • Introduce _Block_type (commented with TRANSITION, ABI) and static_cast to avoid sign-comparison warnings,
      which was previously achieved by switching between the base classes. We know the constants are within range, so this is value-preserving.
    • As usual, we no longer need to suppress the deprecation warning.
  • Remove _Discard_block_base.
    • This is a separate commit to improve the previous commit's diff.
  • Fuse uniform_int into uniform_int_distribution.
    • _Eval can always use _Rng_from_urng_v2 for Standard engines.
    • Make equality slightly more efficient in debug mode.
  • Fuse uniform_real into uniform_real_distribution.
    • Make equality slightly more efficient in debug mode.
    • Note that _Read and _Write are public in uniform_real, but remain private in uniform_real_distribution.
  • Guard old classes and test coverage with _HAS_TR1_NAMESPACE.
    • Dev09_181509_tr1_inf_loop_uniform_int_ull: Update comment to describe the Standard machinery being tested. (I know the test name is old.) Wacky min()/max() needs to be constexpr.
    • P0952R2_new_generate_canonical: These tests are comparing tr1 and Standard generators. As they aren't testing absolute behavior, just identical behavior, they're meaningless when the tr1 generators are missing.
    • VSO_0000000_instantiate_iterators_misc: The linear_congruential type being formed is effectively equivalent to minstd_rand0 which is already covered. Now guard the tr1_engine_test_impl() helper. Update comments for searchability.
    • tests/tr1: Switch between tr1 and Standard types. This will continue to serve as a minimal check that the tr1 types keep working until they're ultimately removed soon.
    • tr1/tests/random1 has some coverage for old interfaces that don't apply to the Standard types. We also need to test mersenne_twister_engine's differently-named constants. We need static_cast<int> to avoid sign comparison warnings with discard_block_engine.
    • tr1/tests/random2 has to handle the Standard's different default max for uniform_int_distribution.

🧑‍🔬 _Swc_traits::_Get_wc() Testing

Click to expand science:
template <class T, unsigned long long M>
constexpr int old_get_wc() noexcept {
    int K;
    if constexpr (M == 0) {
        K = (8 * sizeof(T) + 31) / 32;
    } else {
        unsigned long long Val = 1ULL << 32;
        for (K = 1; 0 < Val && Val < M; ++K) {
            Val = Val << 32;
        }
    }
    return K;
}

template <class T, unsigned long long M>
constexpr int new_get_wc() noexcept {
    if constexpr (M == 0) {
        return (8 * sizeof(T) + 31) / 32;
    } else if constexpr (M > (1ULL << 32)) {
        return 2;
    } else {
        return 1;
    }
}

template <unsigned long long M>
constexpr bool test() {
    return old_get_wc<unsigned int, M>() == new_get_wc<unsigned int, M>();
}

static_assert(test<0>());
static_assert(test<1>());
static_assert(test<2>());
static_assert(test<(1ULL << 31)>());
static_assert(test<(1ULL << 32) - 2>());
static_assert(test<(1ULL << 32) - 1>());
static_assert(test<(1ULL << 32)>());
static_assert(test<(1ULL << 32) + 1>());
static_assert(test<(1ULL << 32) + 2>());
static_assert(test<(1ULL << 33)>());
static_assert(test<(1ULL << 63)>());
static_assert(test<0xFFFF'FFFF'FFFF'FFFFULL>());
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /c meow.cpp
meow.cpp

C:\Temp>

🕵️ Layout Test Case

Click to expand layout test case:
C:\Temp>type meow.cpp
#include <cstdint>
#include <print>
#include <random>
#include <string_view>
using namespace std;

template <typename T>
void test(const string_view str) {
    println("{}: size {}, align {}", str, sizeof(T), alignof(T));
}

using BigDiscard = discard_block_engine<ranlux48_base, (1u << 31), 11>;

int main() {
    println("sizeof(void*): {}", sizeof(void*));
    println("_MSVC_STL_UPDATE: {}", _MSVC_STL_UPDATE);
    test<minstd_rand>("(linear_congruential_engine) minstd_rand");
    test<ranlux24_base>("(subtract_with_carry_engine) ranlux24_base");
    test<ranlux48_base>("(subtract_with_carry_engine) ranlux48_base");
    test<mt19937>("(mersenne_twister_engine) mt19937");
    test<mt19937_64>("(mersenne_twister_engine) mt19937_64");
    test<ranlux24>("(discard_block_engine) ranlux24");
    test<ranlux48>("(discard_block_engine) ranlux48");
    test<BigDiscard>("(discard_block_engine) BigDiscard");
    test<uniform_int_distribution<int16_t>>("uniform_int_distribution<int16_t>");
    test<uniform_int_distribution<int32_t>>("uniform_int_distribution<int32_t>");
    test<uniform_int_distribution<int64_t>>("uniform_int_distribution<int64_t>");
    test<uniform_real_distribution<float>>("uniform_real_distribution<float>");
    test<uniform_real_distribution<double>>("uniform_real_distribution<double>");
}

struct Layout1 : minstd_rand {};
struct Layout2 : ranlux24_base {};
struct Layout3 : ranlux48_base {};
struct Layout4 : mt19937 {};
struct Layout5 : mt19937_64 {};
struct Layout6 : ranlux24 {};
struct Layout7 : ranlux48 {};
struct Layout8 : BigDiscard {};
struct Layout9 : uniform_int_distribution<int16_t> {};
struct Layout10 : uniform_int_distribution<int32_t> {};
struct Layout11 : uniform_int_distribution<int64_t> {};
struct Layout12 : uniform_real_distribution<float> {};
struct Layout13 : uniform_real_distribution<double> {};

📚 Layout Results

Click to expand old x64:
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /d1reportSingleClassLayoutLayout meow.cpp && meow
meow.cpp

class Layout1   size(4):
        +---
 0      | +--- (base class std::linear_congruential_engine<unsigned int,48271,0,2147483647>)
 0      | | _Prev
        | +---
        +---

class Layout2   size(200):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned int,24,10,24>)
 0      | | +--- (base class std::subtract_with_carry<unsigned int,16777216,10,24>)
 0      | | | +--- (base class std::_Swc_base<unsigned int,10,24,struct std::_Swc_traits<unsigned int,16777216,24> >)
 0      | | | | +--- (base class std::_Circ_buf<unsigned int,24>)
 0      | | | | | _Idx
 4      | | | | | _Ax
        | | | | +---
196     | | | | _Carry
        | | | +---
        | | +---
        | +---
        +---

class Layout3   size(208):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned __int64,48,5,12>)
 0      | | +--- (base class std::subtract_with_carry<unsigned __int64,281474976710656,5,12>)
 0      | | | +--- (base class std::_Swc_base<unsigned __int64,5,12,struct std::_Swc_traits<unsigned __int64,281474976710656,12> >)
 0      | | | | +--- (base class std::_Circ_buf<unsigned __int64,12>)
 0      | | | | | _Idx
        | | | | | <alignment member> (size=4)
 8      | | | | | _Ax
        | | | | +---
200     | | | | _Carry
        | | | | <alignment member> (size=4)
        | | | +---
        | | +---
        | +---
        +---

class Layout4   size(5000):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>)
 0      | | +--- (base class std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>)
 0      | | | +--- (base class std::_Circ_buf<unsigned int,624>)
 0      | | | | _Idx
 4      | | | | _Ax
        | | | +---
4996    | | | _Dxval
        | | +---
        | +---
        +---

class Layout5   size(5008):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned __int64,64,312,156,31,-5403634167711393303,29,6148914691236517205,17,8202884508482404352,37,-2270628950310912,43,6364136223846793005>)
 0      | | +--- (base class std::mersenne_twister<unsigned __int64,64,312,156,31,-5403634167711393303,29,17,8202884508482404352,37,-2270628950310912,43>)
 0      | | | +--- (base class std::_Circ_buf<unsigned __int64,312>)
 0      | | | | _Idx
        | | | | <alignment member> (size=4)
 8      | | | | _Ax
        | | | +---
5000    | | | _Dxval
        | | +---
        | +---
        +---

class Layout6   size(204):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned int,24,10,24>,223,23>)
 0      | | +--- (base class std::discard_block<class std::subtract_with_carry_engine<unsigned int,24,10,24>,223,23>)
 0      | | | ?$subtract_with_carry_engine@I$0BI@$09$0BI@ _Eng
200     | | | _Nx
        | | +---
        | +---
        +---

class Layout7   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,389,11>)
 0      | | +--- (base class std::discard_block<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,389,11>)
 0      | | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | | _Nx
        | | | <alignment member> (size=4)
        | | +---
        | +---
        +---

class Layout8   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,2147483648,11>)
 0      | | +--- (base class std::_Discard_block_base<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,2147483648,11>)
 0      | | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | | _Nx
        | | +---
        | +---
        +---

class Layout9   size(4):
        +---
 0      | +--- (base class std::uniform_int_distribution<short>)
 0      | | +--- (base class std::uniform_int<short>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout10  size(8):
        +---
 0      | +--- (base class std::uniform_int_distribution<int>)
 0      | | +--- (base class std::uniform_int<int>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout11  size(16):
        +---
 0      | +--- (base class std::uniform_int_distribution<__int64>)
 0      | | +--- (base class std::uniform_int<__int64>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout12  size(8):
        +---
 0      | +--- (base class std::uniform_real_distribution<float>)
 0      | | +--- (base class std::uniform_real<float>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout13  size(16):
        +---
 0      | +--- (base class std::uniform_real_distribution<double>)
 0      | | +--- (base class std::uniform_real<double>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---
sizeof(void*): 8
_MSVC_STL_UPDATE: 202503
(linear_congruential_engine) minstd_rand: size 4, align 4
(subtract_with_carry_engine) ranlux24_base: size 200, align 4
(subtract_with_carry_engine) ranlux48_base: size 208, align 8
(mersenne_twister_engine) mt19937: size 5000, align 4
(mersenne_twister_engine) mt19937_64: size 5008, align 8
(discard_block_engine) ranlux24: size 204, align 4
(discard_block_engine) ranlux48: size 216, align 8
(discard_block_engine) BigDiscard: size 216, align 8
uniform_int_distribution<int16_t>: size 4, align 2
uniform_int_distribution<int32_t>: size 8, align 4
uniform_int_distribution<int64_t>: size 16, align 8
uniform_real_distribution<float>: size 8, align 4
uniform_real_distribution<double>: size 16, align 8
Click to expand new x64:
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /d1reportSingleClassLayoutLayout meow.cpp && meow
meow.cpp

class Layout1   size(4):
        +---
 0      | +--- (base class std::linear_congruential_engine<unsigned int,48271,0,2147483647>)
 0      | | _Prev
        | +---
        +---

class Layout2   size(200):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned int,24,10,24>)
 0      | | +--- (base class std::_Swc_base<unsigned int,10,24,struct std::_Swc_traits<unsigned int,16777216,24> >)
 0      | | | +--- (base class std::_Circ_buf<unsigned int,24>)
 0      | | | | _Idx
 4      | | | | _Ax
        | | | +---
196     | | | _Carry
        | | +---
        | +---
        +---

class Layout3   size(208):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned __int64,48,5,12>)
 0      | | +--- (base class std::_Swc_base<unsigned __int64,5,12,struct std::_Swc_traits<unsigned __int64,281474976710656,12> >)
 0      | | | +--- (base class std::_Circ_buf<unsigned __int64,12>)
 0      | | | | _Idx
        | | | | <alignment member> (size=4)
 8      | | | | _Ax
        | | | +---
200     | | | _Carry
        | | | <alignment member> (size=4)
        | | +---
        | +---
        +---

class Layout4   size(5000):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>)
 0      | | +--- (base class std::_Circ_buf<unsigned int,624>)
 0      | | | _Idx
 4      | | | _Ax
        | | +---
4996    | | _Dxval
        | +---
        +---

class Layout5   size(5008):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned __int64,64,312,156,31,-5403634167711393303,29,6148914691236517205,17,8202884508482404352,37,-2270628950310912,43,6364136223846793005>)
 0      | | +--- (base class std::_Circ_buf<unsigned __int64,312>)
 0      | | | _Idx
        | | | <alignment member> (size=4)
 8      | | | _Ax
        | | +---
5000    | | _Dxval
        | +---
        +---

class Layout6   size(204):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned int,24,10,24>,223,23>)
 0      | | ?$subtract_with_carry_engine@I$0BI@$09$0BI@ _Eng
200     | | _Nx
        | +---
        +---

class Layout7   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,389,11>)
 0      | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | _Nx
        | | <alignment member> (size=4)
        | +---
        +---

class Layout8   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,2147483648,11>)
 0      | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | _Nx
        | +---
        +---

class Layout9   size(4):
        +---
 0      | +--- (base class std::uniform_int_distribution<short>)
 0      | | param_type _Par
        | +---
        +---

class Layout10  size(8):
        +---
 0      | +--- (base class std::uniform_int_distribution<int>)
 0      | | param_type _Par
        | +---
        +---

class Layout11  size(16):
        +---
 0      | +--- (base class std::uniform_int_distribution<__int64>)
 0      | | param_type _Par
        | +---
        +---

class Layout12  size(8):
        +---
 0      | +--- (base class std::uniform_real_distribution<float>)
 0      | | param_type _Par
        | +---
        +---

class Layout13  size(16):
        +---
 0      | +--- (base class std::uniform_real_distribution<double>)
 0      | | param_type _Par
        | +---
        +---
sizeof(void*): 8
_MSVC_STL_UPDATE: 202508
(linear_congruential_engine) minstd_rand: size 4, align 4
(subtract_with_carry_engine) ranlux24_base: size 200, align 4
(subtract_with_carry_engine) ranlux48_base: size 208, align 8
(mersenne_twister_engine) mt19937: size 5000, align 4
(mersenne_twister_engine) mt19937_64: size 5008, align 8
(discard_block_engine) ranlux24: size 204, align 4
(discard_block_engine) ranlux48: size 216, align 8
(discard_block_engine) BigDiscard: size 216, align 8
uniform_int_distribution<int16_t>: size 4, align 2
uniform_int_distribution<int32_t>: size 8, align 4
uniform_int_distribution<int64_t>: size 16, align 8
uniform_real_distribution<float>: size 8, align 4
uniform_real_distribution<double>: size 16, align 8
Click to expand old x86:
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /d1reportSingleClassLayoutLayout meow.cpp && meow
meow.cpp

class Layout1   size(4):
        +---
 0      | +--- (base class std::linear_congruential_engine<unsigned int,48271,0,2147483647>)
 0      | | _Prev
        | +---
        +---

class Layout2   size(200):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned int,24,10,24>)
 0      | | +--- (base class std::subtract_with_carry<unsigned int,16777216,10,24>)
 0      | | | +--- (base class std::_Swc_base<unsigned int,10,24,struct std::_Swc_traits<unsigned int,16777216,24> >)
 0      | | | | +--- (base class std::_Circ_buf<unsigned int,24>)
 0      | | | | | _Idx
 4      | | | | | _Ax
        | | | | +---
196     | | | | _Carry
        | | | +---
        | | +---
        | +---
        +---

class Layout3   size(208):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned __int64,48,5,12>)
 0      | | +--- (base class std::subtract_with_carry<unsigned __int64,281474976710656,5,12>)
 0      | | | +--- (base class std::_Swc_base<unsigned __int64,5,12,struct std::_Swc_traits<unsigned __int64,281474976710656,12> >)
 0      | | | | +--- (base class std::_Circ_buf<unsigned __int64,12>)
 0      | | | | | _Idx
        | | | | | <alignment member> (size=4)
 8      | | | | | _Ax
        | | | | +---
200     | | | | _Carry
        | | | | <alignment member> (size=4)
        | | | +---
        | | +---
        | +---
        +---

class Layout4   size(5000):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>)
 0      | | +--- (base class std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>)
 0      | | | +--- (base class std::_Circ_buf<unsigned int,624>)
 0      | | | | _Idx
 4      | | | | _Ax
        | | | +---
4996    | | | _Dxval
        | | +---
        | +---
        +---

class Layout5   size(5008):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned __int64,64,312,156,31,-5403634167711393303,29,6148914691236517205,17,8202884508482404352,37,-2270628950310912,43,6364136223846793005>)
 0      | | +--- (base class std::mersenne_twister<unsigned __int64,64,312,156,31,-5403634167711393303,29,17,8202884508482404352,37,-2270628950310912,43>)
 0      | | | +--- (base class std::_Circ_buf<unsigned __int64,312>)
 0      | | | | _Idx
        | | | | <alignment member> (size=4)
 8      | | | | _Ax
        | | | +---
5000    | | | _Dxval
        | | +---
        | +---
        +---

class Layout6   size(204):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned int,24,10,24>,223,23>)
 0      | | +--- (base class std::discard_block<class std::subtract_with_carry_engine<unsigned int,24,10,24>,223,23>)
 0      | | | ?$subtract_with_carry_engine@I$0BI@$09$0BI@ _Eng
200     | | | _Nx
        | | +---
        | +---
        +---

class Layout7   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,389,11>)
 0      | | +--- (base class std::discard_block<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,389,11>)
 0      | | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | | _Nx
        | | | <alignment member> (size=4)
        | | +---
        | +---
        +---

class Layout8   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,2147483648,11>)
 0      | | +--- (base class std::_Discard_block_base<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,2147483648,11>)
 0      | | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | | _Nx
        | | | <alignment member> (size=4)
        | | +---
        | +---
        +---

class Layout9   size(4):
        +---
 0      | +--- (base class std::uniform_int_distribution<short>)
 0      | | +--- (base class std::uniform_int<short>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout10  size(8):
        +---
 0      | +--- (base class std::uniform_int_distribution<int>)
 0      | | +--- (base class std::uniform_int<int>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout11  size(16):
        +---
 0      | +--- (base class std::uniform_int_distribution<__int64>)
 0      | | +--- (base class std::uniform_int<__int64>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout12  size(8):
        +---
 0      | +--- (base class std::uniform_real_distribution<float>)
 0      | | +--- (base class std::uniform_real<float>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---

class Layout13  size(16):
        +---
 0      | +--- (base class std::uniform_real_distribution<double>)
 0      | | +--- (base class std::uniform_real<double>)
 0      | | | param_type _Par
        | | +---
        | +---
        +---
sizeof(void*): 4
_MSVC_STL_UPDATE: 202503
(linear_congruential_engine) minstd_rand: size 4, align 4
(subtract_with_carry_engine) ranlux24_base: size 200, align 4
(subtract_with_carry_engine) ranlux48_base: size 208, align 8
(mersenne_twister_engine) mt19937: size 5000, align 4
(mersenne_twister_engine) mt19937_64: size 5008, align 8
(discard_block_engine) ranlux24: size 204, align 4
(discard_block_engine) ranlux48: size 216, align 8
(discard_block_engine) BigDiscard: size 216, align 8
uniform_int_distribution<int16_t>: size 4, align 2
uniform_int_distribution<int32_t>: size 8, align 4
uniform_int_distribution<int64_t>: size 16, align 8
uniform_real_distribution<float>: size 8, align 4
uniform_real_distribution<double>: size 16, align 8
Click to expand new x86:
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /d1reportSingleClassLayoutLayout meow.cpp && meow
meow.cpp

class Layout1   size(4):
        +---
 0      | +--- (base class std::linear_congruential_engine<unsigned int,48271,0,2147483647>)
 0      | | _Prev
        | +---
        +---

class Layout2   size(200):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned int,24,10,24>)
 0      | | +--- (base class std::_Swc_base<unsigned int,10,24,struct std::_Swc_traits<unsigned int,16777216,24> >)
 0      | | | +--- (base class std::_Circ_buf<unsigned int,24>)
 0      | | | | _Idx
 4      | | | | _Ax
        | | | +---
196     | | | _Carry
        | | +---
        | +---
        +---

class Layout3   size(208):
        +---
 0      | +--- (base class std::subtract_with_carry_engine<unsigned __int64,48,5,12>)
 0      | | +--- (base class std::_Swc_base<unsigned __int64,5,12,struct std::_Swc_traits<unsigned __int64,281474976710656,12> >)
 0      | | | +--- (base class std::_Circ_buf<unsigned __int64,12>)
 0      | | | | _Idx
        | | | | <alignment member> (size=4)
 8      | | | | _Ax
        | | | +---
200     | | | _Carry
        | | | <alignment member> (size=4)
        | | +---
        | +---
        +---

class Layout4   size(5000):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>)
 0      | | +--- (base class std::_Circ_buf<unsigned int,624>)
 0      | | | _Idx
 4      | | | _Ax
        | | +---
4996    | | _Dxval
        | +---
        +---

class Layout5   size(5008):
        +---
 0      | +--- (base class std::mersenne_twister_engine<unsigned __int64,64,312,156,31,-5403634167711393303,29,6148914691236517205,17,8202884508482404352,37,-2270628950310912,43,6364136223846793005>)
 0      | | +--- (base class std::_Circ_buf<unsigned __int64,312>)
 0      | | | _Idx
        | | | <alignment member> (size=4)
 8      | | | _Ax
        | | +---
5000    | | _Dxval
        | +---
        +---

class Layout6   size(204):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned int,24,10,24>,223,23>)
 0      | | ?$subtract_with_carry_engine@I$0BI@$09$0BI@ _Eng
200     | | _Nx
        | +---
        +---

class Layout7   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,389,11>)
 0      | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | _Nx
        | | <alignment member> (size=4)
        | +---
        +---

class Layout8   size(216):
        +---
 0      | +--- (base class std::discard_block_engine<class std::subtract_with_carry_engine<unsigned __int64,48,5,12>,2147483648,11>)
 0      | | ?$subtract_with_carry_engine@_K$0DA@$04$0M@ _Eng
208     | | _Nx
        | | <alignment member> (size=4)
        | +---
        +---

class Layout9   size(4):
        +---
 0      | +--- (base class std::uniform_int_distribution<short>)
 0      | | param_type _Par
        | +---
        +---

class Layout10  size(8):
        +---
 0      | +--- (base class std::uniform_int_distribution<int>)
 0      | | param_type _Par
        | +---
        +---

class Layout11  size(16):
        +---
 0      | +--- (base class std::uniform_int_distribution<__int64>)
 0      | | param_type _Par
        | +---
        +---

class Layout12  size(8):
        +---
 0      | +--- (base class std::uniform_real_distribution<float>)
 0      | | param_type _Par
        | +---
        +---

class Layout13  size(16):
        +---
 0      | +--- (base class std::uniform_real_distribution<double>)
 0      | | param_type _Par
        | +---
        +---
sizeof(void*): 4
_MSVC_STL_UPDATE: 202508
(linear_congruential_engine) minstd_rand: size 4, align 4
(subtract_with_carry_engine) ranlux24_base: size 200, align 4
(subtract_with_carry_engine) ranlux48_base: size 208, align 8
(mersenne_twister_engine) mt19937: size 5000, align 4
(mersenne_twister_engine) mt19937_64: size 5008, align 8
(discard_block_engine) ranlux24: size 204, align 4
(discard_block_engine) ranlux48: size 216, align 8
(discard_block_engine) BigDiscard: size 216, align 8
uniform_int_distribution<int16_t>: size 4, align 2
uniform_int_distribution<int32_t>: size 8, align 4
uniform_int_distribution<int64_t>: size 16, align 8
uniform_real_distribution<float>: size 8, align 4
uniform_real_distribution<double>: size 16, align 8

🔀 Diff Layouts

Diff the layouts in VSCode to see the base classes vanishing without affecting the positions of data members. Thanks @MattStephanson for noticing that I initially forgot to inspect BigDiscard.

…ied.

Manually tested:

```
template <class T, unsigned long long M>
constexpr int old_get_wc() noexcept {
    int K;
    if constexpr (M == 0) {
        K = (8 * sizeof(T) + 31) / 32;
    } else {
        unsigned long long Val = 1ULL << 32;
        for (K = 1; 0 < Val && Val < M; ++K) {
            Val = Val << 32;
        }
    }
    return K;
}

template <class T, unsigned long long M>
constexpr int new_get_wc() noexcept {
    if constexpr (M == 0) {
        return (8 * sizeof(T) + 31) / 32;
    } else if constexpr (M > (1ULL << 32)) {
        return 2;
    } else {
        return 1;
    }
}

template <unsigned long long M>
constexpr bool test() {
    return old_get_wc<unsigned int, M>() == new_get_wc<unsigned int, M>();
}

static_assert(test<0>());
static_assert(test<1>());
static_assert(test<2>());
static_assert(test<(1ULL << 31)>());
static_assert(test<(1ULL << 32) - 2>());
static_assert(test<(1ULL << 32) - 1>());
static_assert(test<(1ULL << 32)>());
static_assert(test<(1ULL << 32) + 1>());
static_assert(test<(1ULL << 32) + 2>());
static_assert(test<(1ULL << 33)>());
static_assert(test<(1ULL << 63)>());
static_assert(test<0xFFFF'FFFF'FFFF'FFFFULL>());

C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /c meow.cpp
meow.cpp

C:\Temp>
```
We no longer need to suppress the deprecation warning.

We inherit directly from _Swc_base now. (After TR1 removal, we can fuse that away too, which will be a much larger simplification.)

Drop a pointless comment.

We now directly say that _Traits is an _Swc_traits.

subtract_with_carry's default constructor passed 0u to _Swc_base's constructor, so we do that.

Cleanup: Simplify operator!=().
We no longer need to suppress the deprecation warning.

We inherit directly from _Circ_buf now. That inheritance continues to be private, whereas mersenne_twister inherits from _Circ_buf publicly.

We no longer need a _Mybase alias.

When constructing `mersenne_twister_engine(_Seed_seq& _Seq)`, avoid redundantly calling `seed(default_seed)` before `seed(_Seq)`.

`_WMSK` is a direct member now.

Cleanup: Simplify operator!=().

Note that operator>>() for mersenne_twister calls `_Eng.seed(_Gen)` which is radically different from mersenne_twister_engine's `seed(_Seed_seq& _Seq)`. Accordingly I've inlined the old implementation (which directly loads the serialized values).

operator<<() for mersenne_twister uses mersenne_twister::state_size as a bound. This is just _Nx, which I've chosen to use for increased symmetry with the other operator.

_Refill_lower() etc. are private (same as before when they were inherited privately).
…that the data member is retained for bincompat.
This was very close to the finish line. Instead of switching between
the old discard_block and the newer _Discard_block_base (introduced by GH 4066),
simply make _Nx's type vary.

Introduce _Block_type (commented with TRANSITION, ABI) and static_cast to avoid sign-comparison warnings,
which was previously achieved by switching between the base classes. We know the constants are within range, so this is value-preserving.

As usual, we no longer need to suppress the deprecation warning.
This is a separate commit to improve the previous commit's diff.
_Eval can always use _Rng_from_urng_v2 for Standard engines.

Make equality slightly more efficient in debug mode.
Make equality slightly more efficient in debug mode.

Note that _Read and _Write are public in uniform_real, but remain private in uniform_real_distribution.
Dev09_181509_tr1_inf_loop_uniform_int_ull:
Update comment to describe the Standard machinery being tested. (I know the test name is old.)
Wacky min()/max() needs to be constexpr.

P0952R2_new_generate_canonical:
These tests are comparing tr1 and Standard generators. As they aren't testing absolute behavior,
just identical behavior, they're meaningless when the tr1 generators are missing.

VSO_0000000_instantiate_iterators_misc:
The linear_congruential type being formed is effectively equivalent to minstd_rand0 which is already covered.
Now guard the tr1_engine_test_impl() helper.
Update comments for searchability.

tests/tr1:
Switch between tr1 and Standard types. This will continue to serve as a minimal check
that the tr1 types keep working until they're ultimately removed soon.

tr1/tests/random1 has some coverage for old interfaces that don't apply to the Standard types.
We also need to test mersenne_twister_engine's differently-named constants.
We need static_cast<int> to avoid sign comparison warnings with discard_block_engine.

tr1/tests/random2 has to handle the Standard's different default max for uniform_int_distribution.
@StephanTLavavej StephanTLavavej requested a review from a team as a code owner September 7, 2025 20:18
@StephanTLavavej StephanTLavavej added the enhancement Something can be improved label Sep 7, 2025
@github-project-automation github-project-automation bot moved this to Initial Review in STL Code Reviews Sep 7, 2025
@StephanTLavavej StephanTLavavej moved this from Initial Review to Final Review in STL Code Reviews Sep 8, 2025
@StephanTLavavej
Copy link
Member Author

I'm mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed

@StephanTLavavej StephanTLavavej moved this from Final Review to Merging in STL Code Reviews Sep 10, 2025
@StephanTLavavej StephanTLavavej merged commit 0cb8132 into microsoft:main Sep 10, 2025
39 checks passed
@github-project-automation github-project-automation bot moved this from Merging to Done in STL Code Reviews Sep 10, 2025
@StephanTLavavej StephanTLavavej deleted the nuclear-fusion branch September 10, 2025 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Something can be improved
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants