Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++] Generate extra header files #1041

Open
szymonwieloch opened this issue Jan 1, 2025 · 0 comments
Open

[C++] Generate extra header files #1041

szymonwieloch opened this issue Jan 1, 2025 · 0 comments

Comments

@szymonwieloch
Copy link

While the current generator relieves us from writing a lot of code manually, there are still several things that could be generated that would be very helpful and would reduce the effort of working with SBE. We already have few things we generate from the XML file and it only took few lines of Python code per feature, so it should be easy and straightforward.

In my proposal all files are prefixed with "sbe" to avoid collisions with already existing messages or types.

Forward message declarations - sbeFwd.h

In our code we have files that declare functions that handle all messages types in the given protocol. To improve build speeds we generally declare all messages types. Whenever we extend or change the protocol, code gets re-generated and we have to manually update the list of declarations. It would be better if those declarations were maintained automatically.

This file could contain declarations of message classes. This is very useful to speed up the build process - you can include only declarations instead of full message headers. Example:

#pragma once
namespace Protocol{
class Message1;
class Message2;
} // namespace Protocol

Include complete protocol - sbeAll.h

In our source code we do have files that handle all messages from the given protocol. Currently whenever a new message gets added, a new include needs to be added manually. Instead we would prefer to have just one header that includes the complete protocol:

# pragma once
#include "MessageHeader.h"
#include "Message1.h"
#include "Message2.h"

Automatic parsing and dispatch of messages - sbeParser.h

Currently whenever a new message gets added, we need to manually handle it in a switch statement. Instead we would prefer to use an automatically generated parser. The code would look roughly like this:

#pragman once
namespace Protocol{
template<typename OnMsg, typename OnUnknown>
void sbeParse(const char * buf, size_t len, OnMsg && onMsg, OnUnknown && onUnknown){
  MessageHeader hdr(buf, size);
  // TODO: check schemaId
  switch(hdr.templateId()){
    case Message1.sbeTemplateId():{
      Message1 msg;
      message.wrapForDecode(hdr.buffer(), hdr.encodedLength(), hdr.blockLength(), hdr.version(), hdr.bufferLength());
      onMsg(msg);
    }
    // same for other message types
    default:
      onUnknown(hdr.templateId());
}
}
} // namespace Protocol

And an example use in code:

class Handler {
  void onMessage(Message1 & msg);
  // Other types go here
};

void handle(const char * buf, size_t len){
  Handler handler;
  Protocol::sbeParse(buf, len,
      [&](auto & msg){handler.onMessage(msg);},
      [](auto templateId){std::cerr << "Unknown message: " << templateId;}
  );
}

Alternatively the onUnknown callback could be replaced with some form of returned error, i. e. std::optional<uint16_t> to return the unknown message ID.

Please notice that for the onMsg can dispatch the message to either a class like in the example above or to a template function or to an overloaded function. So this approach is very flexible. It is also effectively zero-cost.

Some benefits:

  • Easier to use for new programmers. Less bugs with parsing.
  • Less code to maintain.
  • Whenever a new message is added, the code enforces adding a parser or it won't compile. No missed/forgotten messages.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant