0

I have a protobuf message with non-consecutive enum values something like this:

message Information {
    enum Versions {
        version1 = 0;
        version2 = 1;
        version3 = 10;
        version4 = 20;   
        version5 = 30;    
    }
}

I want to have a C++ function GetNextVersion() which takes in one enum version and gives the next version as output. For eg: GetNextVersion(Information::version4) should give Information::version5 as output. Is there any inbuilt and easy method to do this?

Doraemon
  • 109
  • 1
  • 7

3 Answers3

2

Is there any inbuilt and easy method to do this?

I see no easy method to get that.

But I can suggest metaprogramming approaches (at least on Linux) with C++ code generation.

You could, assuming you have access to the source code of protobuf-c :

  • write some GNU gawk script to parse that C++ code and generate the C++ code of GetNextVersion

  • perhaps write some GNU sed (or a Python one) script doing the same.

  • write some GCC plugin and use it to parse that C++ code and generate the C++ code of GetNextVersion

  • write some GNU emacs code doing the same.

  • wait a few months and (in spring 2021) use Bismon. I am developing it, so contact me by email

  • extend and adapt the Clang static analyzer for your needs.

  • extend and adapt the SWIG tool for your needs.

  • extend and adapt the RPGGEN tool for your needs.

  • use GNU bison or ANTLR to parse C++ code, or design your domain specific language with some documented EBNF syntax and write some code generator with them.

You could also keep the description of enum Versions in some database (sqlite, PostGreSQL, etc...) or some JSON file or some CSV file (or an XML one, using XSLT or libexpat) and emit it (for protobuf) and the source code of GetNextVersion using some Python script, or GNU m4, or GPP.

You could write a GNU guile script or some rules for CLIPS generating some C++ code with your protobuf description.

In a few months (spring 2021), the RefPerSys system might be helpful. Before that, you could contribute and extend it and reuse it for your needs.

A pragmatic approach could be to add a comment in your protobuf declaration to remind you of editing another file when you need to change the protobuf message and protocol.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
2

You can use protobuf's reflection to achieve the goal:

Information::Versions GetNextVersion(Information::Versions ver) {
    const auto *desc = Information::Versions_descriptor();
    auto cur_idx = desc->FindValueByNumber(ver)->index();
    if (cur_idx >= desc->value_count() - 1) {
        throw runtime_error("no next enum");
    }

    auto next_idx = cur_idx + 1;
    return Information::Versions(desc->value(next_idx)->number());
}

int main() {
    try {
        auto ver = Information::version1;
        while (true) {
            cout << ver << endl;
            ver = GetNextVersion(ver);
        }
    } catch (const runtime_error &e) {
        cout << e.what() << endl;
    }
    return 0;
}
for_stack
  • 21,012
  • 4
  • 35
  • 48
1

No, there isn't.

You define your own data type, so you also must define the operators for it.

So, your GetNextVersion()method contains that knowledge how to increment the version number. If you had decided to use an integer, then the compiler knows already how to increment that, but you wanted something special and that is the price you have to pay for it.

U. W.
  • 414
  • 2
  • 10