1+ // File: evolution.C
2+ // Demonstrates a containee with custom alignment embedded directly inside a
3+ // container (no heap allocation). The compiler is responsible for satisfying
4+ // the alignment requirement of the embedded object, inserting padding before it
5+ // if necessary.
6+
7+ #include <iostream>
8+ #include <cstdint> // uintptr_t
9+ #include <cassert>
10+ #include "TError.h"
11+ #include "TFile.h"
12+
13+ // Containee type with a custom alignment (over-aligned)
14+ struct alignas (256 ) Containee {
15+ int id ;
16+ // some payload to make sizeof non-trivial
17+ double payload [7 ];
18+
19+ Containee (int i = -1 ) : id (i ) {}
20+ ~Containee () = default ;
21+ };
22+
23+ struct Wrapper {
24+ Containee c ;
25+ Wrapper (int i = -1 ) : c (i ) {}
26+ ~Wrapper () = default ;
27+ };
28+
29+ static_assert (alignof(Containee ) == 256 , "Containee must be 256-byte aligned" );
30+
31+ // Container that embeds a single Containee object directly as a data member.
32+ // The compiler guarantees the member satisfies alignof(Containee) because the
33+ // member type carries the alignas specifier; it inserts padding before m_data
34+ // as needed.
35+ class Container {
36+ private :
37+ using pair_t = std ::pair < int , Containee > ;
38+ using coll_t = std ::map < int , Containee > ;
39+ using nested_coll_t = std ::map < int , Wrapper > ;
40+
41+ char m_misalign ; // dummy member to show the compiler inserts padding
42+ Containee m_data ; // embedded – no manual aligned allocation
43+ //pair_t m_pair_data; // check on the run-time dictionary generated for pairs
44+ coll_t m_collection ; // check on the run-time dictionary generated for collections
45+ nested_coll_t m_nested_collection ;
46+
47+ public :
48+ Container () = default ;
49+ explicit Container (int id ) : m_misalign (0 ), m_data (id ) {
50+ m_collection .emplace (id , Containee (id + 1 ));
51+ m_nested_collection .emplace (id , Wrapper (id + 2 ));
52+ }
53+ ~Container () = default ; // embedded object is destroyed automatically
54+
55+ // Demonstrate and verify alignment of the embedded element
56+ void showAlignment () const {
57+ const void * addr = static_cast < const void * > (& m_data );
58+ uintptr_t v = reinterpret_cast < uintptr_t > (addr );
59+ std ::cout << "Containee alignment requirement: " << alignof(Containee ) << '\n' ;
60+ std ::cout << "m_data at " << addr
61+ << " (addr % align = " << (v % alignof(Containee )) << ")\n" ;
62+ // runtime check
63+ assert ((v % alignof(Containee )) == 0 && "m_data not correctly aligned" );
64+ }
65+
66+ Containee & get () { return m_data ; }
67+ const Containee & get () const { return m_data ; }
68+
69+ ClassDef (Container , 2 ) // Container with embedded Containee
70+ };
71+
72+ // AlternateContainer: same layout and behaviour as Container.
73+ class AlternateContainer {
74+ private :
75+ double padding ; // dummy member to show the compiler inserts padding
76+ char m_misalign ; // dummy member to show the compiler inserts padding
77+ Containee m_alt_data ; // embedded – no manual aligned allocation
78+
79+ public :
80+ AlternateContainer () = default ;
81+ explicit AlternateContainer (int id ) : m_misalign (0 ), m_alt_data (id ) {}
82+ ~AlternateContainer () = default ; // embedded object is destroyed automatically
83+
84+ // Demonstrate and verify alignment of the embedded element
85+ void showAlignment () const {
86+ const void * addr = static_cast < const void * > (& m_alt_data );
87+ uintptr_t v = reinterpret_cast < uintptr_t > (addr );
88+ std ::cout << "Containee alignment requirement: " << alignof(Containee ) << '\n' ;
89+ std ::cout << "m_alt_data at " << addr
90+ << " (addr % align = " << (v % alignof(Containee )) << ")\n" ;
91+ // runtime check
92+ assert ((v % alignof(Containee )) == 0 && "m_data not correctly aligned" );
93+ }
94+
95+ void copyContainee (const Containee & c ) {
96+ std ::cout << "Copying Containee with id = " << c .id << " into AlternateContainer\n" ;
97+ // Guess the effective alignment of c's address: largest power-of-two
98+ // that divides the address.
99+ uintptr_t addr = reinterpret_cast < uintptr_t > (& c );
100+ uintptr_t guessed = 1 ;
101+ if (addr != 0 ) {
102+ guessed = addr & (~addr + 1 ); // isolate lowest set bit
103+ }
104+ std ::cout << " address of c: " << static_cast < const void * > (& c )
105+ << " (guessed alignment: " << guessed << " bytes)\n" ;
106+ if (reinterpret_cast < uintptr_t > (& c ) % alignof(Containee ) != 0 ) {
107+ Error ("copyContainer" , "Containee object at %p does not satisfy alignment requirement of %zu\n" ,
108+ & c , alignof(Containee ));
109+ }
110+ m_alt_data = c ;
111+ }
112+
113+ Containee & get () { return m_alt_data ; }
114+ const Containee & get () const { return m_alt_data ; }
115+
116+ ClassDef (AlternateContainer , 2 ) // Alternate container with embedded Containee
117+ };
118+
119+
120+ #ifdef __ROOTCLING__
121+ #pragma link C++ class Container+;
122+ #pragma link C++ class Containee+;
123+ #pragma link C++ class Wrapper+;
124+ #pragma link C++ class AlternateContainer+;
125+ #pragma read sourceClass="Container" source="char m_misalign" \
126+ targetClass="AlternateContainer" target="m_misalign" \
127+ code="{ m_misalign = onfile.m_misalign; }";
128+ #pragma read sourceClass="Container" source="Containee m_data" \
129+ targetClass="AlternateContainer" target="m_alt_data" \
130+ code="{ newObj->copyContainee(onfile.m_data); }";
131+ #endif
132+
133+
134+ void writefile (const char * filename )
135+ {
136+ Container c (42 );
137+ c .showAlignment ();
138+ std ::cout << "c.get().id = " << c .get ().id << '\n' ;
139+
140+ TFile file (filename , "RECREATE ");
141+ file .WriteObject (& c , "origContainer ");
142+ file .Write ();
143+ };
144+
145+ void readfile (const char * filename )
146+ {
147+ TFile file (filename , "READ ");
148+ AlternateContainer * alt = file .Get < AlternateContainer > ("origContainer" );
149+ if (alt ) {
150+ std ::cout << "Successfully read AlternateContainer from file:\n" ;
151+ alt -> showAlignment ();
152+ std ::cout << "Containee id = " << alt -> get ().id << '\n' ;
153+ } else {
154+ Fatal ("readfile" , "Failed to read AlternateContainer from file" );
155+ }
156+ };
157+
158+ int evolution () {
159+ const char * filename = "alignment_evolution.root" ;
160+ writefile (filename );
161+ readfile (filename );
162+ return 0 ;
163+ }
164+
165+ int main ()
166+ {
167+ return evolution ();
168+ }
0 commit comments