xref: /aosp_15_r20/external/emboss/doc/design_docs/default_values.md (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1*99e0aae7SDavid Rees# Design Sketch: Initializer Values for Fields
2*99e0aae7SDavid Rees
3*99e0aae7SDavid Rees## Motivation
4*99e0aae7SDavid Rees
5*99e0aae7SDavid ReesIt is often useful to initialize a structure to some "un-set" value before
6*99e0aae7SDavid Reesstarting to modify it.  For many structures, a simple `memset(buffer, sizeof
7*99e0aae7SDavid Rees*buffer, 0)` suffices, but other structures require specific values at specific
8*99e0aae7SDavid Reeslocations, which are tedious to write out in user code.
9*99e0aae7SDavid Rees
10*99e0aae7SDavid ReesThis design proposes two main elements:
11*99e0aae7SDavid Rees
12*99e0aae7SDavid Rees1.  A way to specify initializer values for specific fields.
13*99e0aae7SDavid Rees2.  A new feature in the generated C++ code to set the memory underlying a view
14*99e0aae7SDavid Rees    to those initializer values, or to 0 if no initializer was specified.
15*99e0aae7SDavid Rees
16*99e0aae7SDavid Rees
17*99e0aae7SDavid Rees## Initializer Value Syntax
18*99e0aae7SDavid Rees
19*99e0aae7SDavid Rees### Attribute
20*99e0aae7SDavid Rees
21*99e0aae7SDavid ReesThe most straightforward option is to use the existing attribute syntax:
22*99e0aae7SDavid Rees
23*99e0aae7SDavid Rees    struct Foo:
24*99e0aae7SDavid Rees      0 [+2]  UInt  bar
25*99e0aae7SDavid Rees        [initialize_to: 7]
26*99e0aae7SDavid Rees
27*99e0aae7SDavid ReesThe exact name TBD, but it should be somewhat visually distinct from the
28*99e0aae7SDavid Reesexisting `$default` keyword for attributes, which specifies that an attribute
29*99e0aae7SDavid Reesshould be used for all descendants of the current node, unless overridden:
30*99e0aae7SDavid Rees
31*99e0aae7SDavid Rees    [$default byte_order = "LittleEndian"]
32*99e0aae7SDavid Rees
33*99e0aae7SDavid Rees
34*99e0aae7SDavid Rees### New Syntax
35*99e0aae7SDavid Rees
36*99e0aae7SDavid ReesOther options might add new syntax.
37*99e0aae7SDavid Rees
38*99e0aae7SDavid Rees
39*99e0aae7SDavid Rees#### Suffix `= value`
40*99e0aae7SDavid Rees
41*99e0aae7SDavid ReesSuffix `= value` looks somewhat similar to the "initialize on construction"
42*99e0aae7SDavid Reessyntax in languages like C++:
43*99e0aae7SDavid Rees
44*99e0aae7SDavid Rees    struct Foo:
45*99e0aae7SDavid Rees      0 [+2]  UInt  bar = 7
46*99e0aae7SDavid Rees
47*99e0aae7SDavid Rees    class Foo {
48*99e0aae7SDavid Rees      int bar = 7;
49*99e0aae7SDavid Rees    };
50*99e0aae7SDavid Rees
51*99e0aae7SDavid ReesHowever, it also looks somewhat confusingly similar to the field number
52*99e0aae7SDavid Reesspecifiers in Proto:
53*99e0aae7SDavid Rees
54*99e0aae7SDavid Rees    message Foo {
55*99e0aae7SDavid Rees      optional uint32 bar = 7;
56*99e0aae7SDavid Rees    }
57*99e0aae7SDavid Rees
58*99e0aae7SDavid Rees
59*99e0aae7SDavid Rees#### Something Else?
60*99e0aae7SDavid Rees
61*99e0aae7SDavid ReesIt is difficult to come up with a syntax that is clear and concise, especially
62*99e0aae7SDavid Reesto a reader who is not particularly familiar with Emboss:
63*99e0aae7SDavid Rees
64*99e0aae7SDavid Rees    struct Foo:
65*99e0aae7SDavid Rees      0 [+2]  UInt  bar := 7
66*99e0aae7SDavid Rees
67*99e0aae7SDavid Rees    struct Foo:
68*99e0aae7SDavid Rees      0 [+2]  UInt  bar [7]
69*99e0aae7SDavid Rees
70*99e0aae7SDavid Rees    struct Foo:
71*99e0aae7SDavid Rees      0 [+2]  UInt [initialize to 7]  bar
72*99e0aae7SDavid Rees
73*99e0aae7SDavid ReesFeel free to propose other options.
74*99e0aae7SDavid Rees
75*99e0aae7SDavid Rees
76*99e0aae7SDavid Rees## `Initialize()` Method
77*99e0aae7SDavid Rees
78*99e0aae7SDavid ReesEmboss *views* do not own their backing storage: creating a view does not
79*99e0aae7SDavid Reesallocate memory, it just provides a structured, well, view of existing bytes.
80*99e0aae7SDavid ReesThis means that there is not a natural place to automatically initialize a
81*99e0aae7SDavid Reesstruct, the way that there is for an object in a typical programming language.
82*99e0aae7SDavid Rees
83*99e0aae7SDavid ReesInstead, I propose adding an `Initialize()` method (name TBD) to each view,
84*99e0aae7SDavid Reeswhich can be called to explicitly initialize the underlying memory.
85*99e0aae7SDavid Rees
86*99e0aae7SDavid ReesFor `external` (`UInt`, `Bcd`, etc.) and `enum` views, `Initialize()` should
87*99e0aae7SDavid Reesjust set the initializer value specified in the `.emb` file, or `0` if none was
88*99e0aae7SDavid Reesspecified.
89*99e0aae7SDavid Rees
90*99e0aae7SDavid ReesFor structure views (`struct` and `bits`), `Initialize()` should set the
91*99e0aae7SDavid Reesinitializer values of each of their fields, recursively.
92*99e0aae7SDavid Rees
93*99e0aae7SDavid ReesTBD whether `Initialize()` should also zero out any bytes that are not part
94*99e0aae7SDavid Reesof any concrete field.
95*99e0aae7SDavid Rees
96*99e0aae7SDavid Rees
97*99e0aae7SDavid Rees## Implementation Notes
98*99e0aae7SDavid Rees
99*99e0aae7SDavid ReesThis is a moderately complex change, touching both the front end and C++ back
100*99e0aae7SDavid Reesend of the compiler, as well as the C++ runtime.
101*99e0aae7SDavid Rees
102*99e0aae7SDavid Rees
103*99e0aae7SDavid Rees### Front End Changes
104*99e0aae7SDavid Rees
105*99e0aae7SDavid ReesOn the front end, adding a new attribute is definitely the most straightforward
106*99e0aae7SDavid Reeschange: mostly just adding the new attribute to `attributes.py`, and updating a
107*99e0aae7SDavid Reesfew things in `dependency_checker.py`, `expression_bounds.py`, and possibly
108*99e0aae7SDavid Rees`constraints.py` to inspect the new attribute.
109*99e0aae7SDavid Rees
110*99e0aae7SDavid Rees
111*99e0aae7SDavid Rees### C++ Back End Changes
112*99e0aae7SDavid Rees
113*99e0aae7SDavid ReesOn the back end, there are a couple of implementation strategies.
114*99e0aae7SDavid Rees
115*99e0aae7SDavid ReesThe easiest strategy is to generate an `Initialize()` method on each structure
116*99e0aae7SDavid Reestype that recursively calls `Initialize()` on each field within the structure
117*99e0aae7SDavid Rees(in dependency-safe order, similar to `WriteToTextStream()`).
118*99e0aae7SDavid Rees
119*99e0aae7SDavid ReesAn alternate strategy would be to generate an "empty image" for each structure,
120*99e0aae7SDavid Reesand have `Initialize()` `memcpy()` the image into its backing storage.  This
121*99e0aae7SDavid Reesseems like it would be faster at runtime, but may bloat binary size quite a bit
122*99e0aae7SDavid Rees-- a 4kb `struct` would need 4kb of const data in your binary to support
123*99e0aae7SDavid Rees`Initialize()`, whereas iteratively calling `Initialize()` on each element of
124*99e0aae7SDavid Reesan array does not require any extra code space for each element of the array.
125*99e0aae7SDavid ReesFor this reason, there would likely still need to be a fallback to recursively
126*99e0aae7SDavid Reescalling `Initialize()`.
127*99e0aae7SDavid Rees
128*99e0aae7SDavid ReesEither way, fields with an explicit initializer value need to be wrapped in a
129*99e0aae7SDavid Reesview adapter when accessed, similar to how `[requires]` is handled now.
130*99e0aae7SDavid Rees
131*99e0aae7SDavid ReesEnum views can be generated with a simple `Initialize()` method that just sets
132*99e0aae7SDavid Reestheir backing storage to 0.
133*99e0aae7SDavid Rees
134*99e0aae7SDavid Rees
135*99e0aae7SDavid Rees### C++ Runtime Changes
136*99e0aae7SDavid Rees
137*99e0aae7SDavid ReesEach of the views for Prelude types (`UInt`, `Int`, `Flag`, etc.) in
138*99e0aae7SDavid Rees`runtime/cpp/emboss_prelude.h` will need to have the new `Initialize()` method.
139