Skip to content

[C++] Compile-time message initialization check #1076

@szymonwieloch

Description

@szymonwieloch

In our company we sometimes struggle with extending schemas, particularly with extending messages with new fields. The problem is that if one person extends the schema in one repo and a second person maintains C++ code, somebody may not notice that a fields was added. This results in part of the bytes in the buffer not being initialized.

You have already added the checkEncodingIsComplete() method which solves part of the problem - checks if all data and group elements were added. But doesn't check if all fields were set.

So I want to suggest adding a new method to the encoder which will support compilation-time checks:

msg.sbeSetAllFields(field1, field2, field3);


void sbeSetAllFields(uint16 field1, uint32 field2, uint8 field3)
{
this->field(1).field2(field2).field3(field3);

}

The basic idea is that when you add a new field to the schema, the sbeSetAllFields() method gets extended with new arguments. A code that misses some fields simply won't compile. So every time somebody updates the schema, code stops compiling until you fix all differences. This is a very safe approach. And I believe it's also a zero-cost abstraction on top of the existing API.

There are at least several interesting edge cases which I think are worth mentioning with some rough proposal for handling:

  1. Composites.

You can just flatten the list of arguments

void sbeSetAllFields(uint8 field1, uint16 combo_one, uint16 combo_two, uint8 field3)
{
this->field1(field1);
this->combo().one(combo_one).two(combo_two);
this->field3(field3);
}
  1. Bit sets

Simply allow a raw value as the argument.

An alternative to the above examples, a lambda could be added as handler for complex types:

template <typename Handler1, typename Handler2>
void sbeSetAllFields(uint8 field1, Handler1 && combo, Handler2 && bitSet, uint8 field4)
{
this->field1(field1);
combo(this->combo());
bitSet(this->bitSet());
this->field4(field4);
}

And example use:

msg.sbeSetAllFields(
1,
[](auto & combo){combo.one(1).two(2);},
[](auto & bitSet){bitSet.clear().someFlag(true);},
8
);

Optional extensions:

  1. The method could be extended with <data> objects as those can always be set using a pair of pointer and length.
  2. Composites and groups could also get a sbeSetAllFields() method.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions