Add user dynamic array field support
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 9 Sep 2020 20:50:51 +0000 (16:50 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 10 Sep 2020 01:30:17 +0000 (21:30 -0400)
commitbe9f12dcc7161c727df017eb2631eef85f471485
tree5ff156b4a894ca7eb8938f37dd41294dbae5484f
parent2c42a1c00379b15026dac74f540ec4a69c9303c4
Add user dynamic array field support

This patch adds support for user dynamic array fields.

The element field type of a user dynamic array field type can be any of
the following:

* Bit array field type.
* String field type.
* Static array field type.

Note that it _cannot_ be another dynamic array field type.

The new `barectf.DynamicArrayFieldType` represents a dynamic array field
type. Its constructor accepts a length field type. As of this version,
this length field type must be within the same immediate structure field
type and before it.

The YAML ways to specify a dynamic array field type are:

barectf 2 configuration:
    class: array
    length: dynamic
    element-type:
      ...

barectf 3 configuration:
    class: dynamic-array
    element-field-type:
      ...

Note that in YAML, you don't specify the length field type: the parser
automatically creates a 32-bit, byte-aligned unsigned integer field type
before which, for a dynamic array field type named `a`, has the name
`__a_len`. This also becomes part of the corresponding tracing function
parameter's name.

In the future, I can add a `length-field-type` property to a barectf 3
YAML dynamic array field type to point to an anterior unsigned integer
field type using some kind of reference, for example:

    class: structure
    members:
      - my_length: uint16
      - my_array:
          field-type:
            class: dynamic-array
            length-field-type-name: my_length
            element-field-type:
              ...

This would make it possible for more than one dynamic array fields
to use the same length field, for example:

    class: structure
    members:
      - my_length: uint16
      - my_uint_array:
          field-type:
            class: dynamic-array
            length-field-type-name: my_length
            element-field-type: uint8
      - my_string_array:
          field-type:
            class: dynamic-array
            length-field-type-name: my_length
            element-field-type: string

The constructor of `barectf.StructureFieldType` calls
_set_dyn_array_ft_length_ft_member_names() which, for each member having
a dynamic array field type:

* Sets its `_length_ft_member_name` attribute to the name of the
  structure field type member having its length field type.

* Sets its length field type's `_is_len` attribute to `True`.

I consider those as hacks, but considering the current constraints, it
makes parts of the (barectf) code easier to implement and maintain.

The C code generation approach is similar to the static array field
case. The `*-write-static-array-statements.j2` templates are renamed to
`*-write-array-statements.j2` and use the `length_src` variable as the
loop's length's value. `*-write-static-array-statements.j2` and the new
`*-write-dynamic-array-statements.j2` set `length_src` before including
`*-write-array-statements.j2`.

To make things easier, barectf now systematically generates alignment
statements if the alignment is greater than one. This could be optimized
again in the future, considering arrays this time. The
`_WriteOp.offset_in_byte` optimization still exists, although as soon as
it's not statically known, it's now `None` and
`serialize-write-bit-array-statements.j2` uses the safe, dynamic
`ctx->at % 8` expression. try_create_align_op() does this, more or less:

    If `self._offset_in_byte` is not currently known and the requested
    alignment is 8:
      Set `self._offset_in_byte` to 0.
    Else:
      If we're currently within an array operation:
        Reset `self._offset_in_byte`.
      Else:
        If `self._offset_in_byte` is currently known:
          Align `self._offset_in_byte` with the requested alignment.

This ensures that each array field's element is aligned before being
written.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
19 files changed:
barectf/__init__.py
barectf/cgen.py
barectf/config.py
barectf/config_parse_v2.py
barectf/config_parse_v3.py
barectf/schemas/config/2/config.yaml
barectf/schemas/config/2/field-type.yaml
barectf/schemas/config/3/field-type.yaml
barectf/templates/c/barectf.c-macros.j2
barectf/templates/c/common.j2
barectf/templates/c/serialize-write-array-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-bit-array-statements.j2
barectf/templates/c/serialize-write-dynamic-array-statements.j2 [new file with mode: 0644]
barectf/templates/c/serialize-write-static-array-statements.j2
barectf/templates/c/size-write-array-statements.j2 [new file with mode: 0644]
barectf/templates/c/size-write-dynamic-array-statements.j2 [new file with mode: 0644]
barectf/templates/c/size-write-static-array-statements.j2
barectf/templates/metadata/struct-ft.j2
barectf/tsdl182gen.py
This page took 0.024594 seconds and 4 git commands to generate.