Skip to content

Commit 7cb0bcb

Browse files
C++ Feature: Mutable union getters (#8852)
* generate mutable union accessors * add test * Revert "add test" This reverts commit 45e352b. * update file * formatter got in the way * merge conflicts * updated genned code * manually fix code gen bc I can't figure out why this file won't code gen --------- Co-authored-by: Wouter van Oortmerssen <[email protected]>
1 parent b1e7868 commit 7cb0bcb

File tree

11 files changed

+375
-8
lines changed

11 files changed

+375
-8
lines changed

samples/monster_generated.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
328328
const MyGame::Sample::Weapon *equipped_as_Weapon() const {
329329
return equipped_type() == MyGame::Sample::Equipment_Weapon ? static_cast<const MyGame::Sample::Weapon *>(equipped()) : nullptr;
330330
}
331+
template<typename T> T *mutable_equipped_as();
332+
MyGame::Sample::Weapon *mutable_equipped_as_Weapon() {
333+
return equipped_type() == MyGame::Sample::Equipment_Weapon ? static_cast<MyGame::Sample::Weapon *>(mutable_equipped()) : nullptr;
334+
}
331335
void *mutable_equipped() {
332336
return GetPointer<void *>(VT_EQUIPPED);
333337
}
@@ -367,6 +371,10 @@ template<> inline const MyGame::Sample::Weapon *Monster::equipped_as<MyGame::Sam
367371
return equipped_as_Weapon();
368372
}
369373

374+
template<> inline MyGame::Sample::Weapon *Monster::mutable_equipped_as<MyGame::Sample::Weapon>() {
375+
return mutable_equipped_as_Weapon();
376+
}
377+
370378
struct MonsterBuilder {
371379
typedef Monster Table;
372380
::flatbuffers::FlatBufferBuilder &fbb_;

src/idl_gen_cpp.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2685,14 +2685,18 @@ class CppGenerator : public BaseGenerator {
26852685
code_ += " }";
26862686
}
26872687

2688-
void GenTableUnionAsGetters(const FieldDef& field) {
2688+
void GenTableUnionAsGetters(const FieldDef& field, bool is_mutable) {
26892689
const auto& type = field.value.type;
26902690
auto u = type.enum_def;
26912691

2692+
code_.SetValue("MUTABLE_EXT", is_mutable ? "" : " const");
2693+
code_.SetValue("MUTABLE", is_mutable ? "mutable_" : "");
2694+
26922695
if (!type.enum_def->uses_multiple_type_instances)
26932696
code_ +=
2694-
" template<typename T> "
2695-
"const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
2697+
" template<typename T>"
2698+
"{{MUTABLE_EXT}} T *{{MUTABLE}}{{NULLABLE_EXT}}{{FIELD_NAME}}_as()"
2699+
"{{MUTABLE_EXT}};";
26962700

26972701
for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
26982702
auto& ev = **u_it;
@@ -2706,15 +2710,19 @@ class CppGenerator : public BaseGenerator {
27062710
EscapeKeyword(Name(field) + UnionTypeFieldSuffix()));
27072711
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
27082712
GetEnumValUse(*u, ev)));
2709-
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2713+
code_.SetValue("U_FIELD_TYPE",
2714+
(is_mutable ? "" : "const ") + full_struct_name + " *");
27102715
code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
27112716
code_.SetValue("U_NULLABLE", NullableExtension());
27122717

27132718
// `const Type *union_name_asType() const` accessor.
2714-
code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
2719+
// and `Type *mutable_union_name_asType()` accessor.
2720+
code_ +=
2721+
" {{U_FIELD_TYPE}}{{U_NULLABLE}}{{MUTABLE}}{{U_FIELD_NAME}}()"
2722+
"{{MUTABLE_EXT}} {";
27152723
code_ +=
27162724
" return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
2717-
"static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2725+
"static_cast<{{U_FIELD_TYPE}}>({{MUTABLE}}{{FIELD_NAME}}()) "
27182726
": nullptr;";
27192727
code_ += " }";
27202728
}
@@ -2755,7 +2763,7 @@ class CppGenerator : public BaseGenerator {
27552763
code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
27562764
code_.SetValue("NULLABLE_EXT", NullableExtension());
27572765
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2758-
if (IsVector(type) && field.value.constant == "[]") {
2766+
if (IsVector(type) && field.value.constant == "[]") {
27592767
const auto& vec_type = type.VectorType();
27602768
const std::string vtype_wire = GenTypeWire(
27612769
vec_type, "", VectorElementUserFacing(vec_type), field.offset64);
@@ -2799,7 +2807,7 @@ class CppGenerator : public BaseGenerator {
27992807
}
28002808

28012809
if (type.base_type == BASE_TYPE_UNION) {
2802-
GenTableUnionAsGetters(field);
2810+
GenTableUnionAsGetters(field, false);
28032811
}
28042812
}
28052813

@@ -2974,6 +2982,11 @@ class CppGenerator : public BaseGenerator {
29742982
auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
29752983
code_.SetValue("FIELD_TYPE", wire_type);
29762984

2985+
// mutable union accessors
2986+
if (type.base_type == BASE_TYPE_UNION) {
2987+
GenTableUnionAsGetters(field, true);
2988+
}
2989+
29772990
if (IsVector(type) && field.value.constant == "[]") {
29782991
const auto& vec_type = type.VectorType();
29792992
const std::string vtype_wire = GenTypeWire(
@@ -3185,13 +3198,28 @@ class CppGenerator : public BaseGenerator {
31853198
code_.SetValue("U_FIELD_NAME", Name(*field) + "_as_" + Name(ev));
31863199

31873200
// `template<> const T *union_name_as<T>() const` accessor.
3201+
// and `template<> T *mutable_union_name_as<T>()` accessor.
31883202
code_ +=
31893203
"template<> "
31903204
"inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
31913205
"<{{U_ELEMENT_NAME}}>() const {";
31923206
code_ += " return {{U_FIELD_NAME}}();";
31933207
code_ += "}";
31943208
code_ += "";
3209+
3210+
if (opts_.mutable_buffer) {
3211+
code_.SetValue("U_FIELD_TYPE", full_struct_name + " *");
3212+
code_.SetValue("U_FIELD_NAME",
3213+
"mutable_" + Name(*field) + "_as_" + Name(ev));
3214+
code_ +=
3215+
"template<> "
3216+
"inline {{U_FIELD_TYPE}}"
3217+
"{{STRUCT_NAME}}::mutable_{{FIELD_NAME}}_as"
3218+
"<{{U_ELEMENT_NAME}}>() {";
3219+
code_ += " return {{U_FIELD_NAME}}();";
3220+
code_ += "}";
3221+
code_ += "";
3222+
}
31953223
}
31963224
}
31973225

tests/cpp17/generated_cpp17/monster_test_generated.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
14811481
const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const {
14821482
return test_type() == MyGame::Example::Any::MyGame_Example2_Monster ? static_cast<const MyGame::Example2::Monster *>(test()) : nullptr;
14831483
}
1484+
template<typename T> T *mutable_test_as();
1485+
MyGame::Example::Monster *mutable_test_as_Monster() {
1486+
return test_type() == MyGame::Example::Any::Monster ? static_cast<MyGame::Example::Monster *>(mutable_test()) : nullptr;
1487+
}
1488+
MyGame::Example::TestSimpleTableWithEnum *mutable_test_as_TestSimpleTableWithEnum() {
1489+
return test_type() == MyGame::Example::Any::TestSimpleTableWithEnum ? static_cast<MyGame::Example::TestSimpleTableWithEnum *>(mutable_test()) : nullptr;
1490+
}
1491+
MyGame::Example2::Monster *mutable_test_as_MyGame_Example2_Monster() {
1492+
return test_type() == MyGame::Example::Any::MyGame_Example2_Monster ? static_cast<MyGame::Example2::Monster *>(mutable_test()) : nullptr;
1493+
}
14841494
void *mutable_test() {
14851495
return GetPointer<void *>(VT_TEST);
14861496
}
@@ -1716,6 +1726,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
17161726
const MyGame::Example2::Monster *any_unique_as_M2() const {
17171727
return any_unique_type() == MyGame::Example::AnyUniqueAliases::M2 ? static_cast<const MyGame::Example2::Monster *>(any_unique()) : nullptr;
17181728
}
1729+
template<typename T> T *mutable_any_unique_as();
1730+
MyGame::Example::Monster *mutable_any_unique_as_M() {
1731+
return any_unique_type() == MyGame::Example::AnyUniqueAliases::M ? static_cast<MyGame::Example::Monster *>(mutable_any_unique()) : nullptr;
1732+
}
1733+
MyGame::Example::TestSimpleTableWithEnum *mutable_any_unique_as_TS() {
1734+
return any_unique_type() == MyGame::Example::AnyUniqueAliases::TS ? static_cast<MyGame::Example::TestSimpleTableWithEnum *>(mutable_any_unique()) : nullptr;
1735+
}
1736+
MyGame::Example2::Monster *mutable_any_unique_as_M2() {
1737+
return any_unique_type() == MyGame::Example::AnyUniqueAliases::M2 ? static_cast<MyGame::Example2::Monster *>(mutable_any_unique()) : nullptr;
1738+
}
17191739
void *mutable_any_unique() {
17201740
return GetPointer<void *>(VT_ANY_UNIQUE);
17211741
}
@@ -1734,6 +1754,15 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
17341754
const MyGame::Example::Monster *any_ambiguous_as_M3() const {
17351755
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases::M3 ? static_cast<const MyGame::Example::Monster *>(any_ambiguous()) : nullptr;
17361756
}
1757+
MyGame::Example::Monster *mutable_any_ambiguous_as_M1() {
1758+
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases::M1 ? static_cast<MyGame::Example::Monster *>(mutable_any_ambiguous()) : nullptr;
1759+
}
1760+
MyGame::Example::Monster *mutable_any_ambiguous_as_M2() {
1761+
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases::M2 ? static_cast<MyGame::Example::Monster *>(mutable_any_ambiguous()) : nullptr;
1762+
}
1763+
MyGame::Example::Monster *mutable_any_ambiguous_as_M3() {
1764+
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases::M3 ? static_cast<MyGame::Example::Monster *>(mutable_any_ambiguous()) : nullptr;
1765+
}
17371766
void *mutable_any_ambiguous() {
17381767
return GetPointer<void *>(VT_ANY_AMBIGUOUS);
17391768
}
@@ -2008,26 +2037,50 @@ template<> inline const MyGame::Example::Monster *Monster::test_as<MyGame::Examp
20082037
return test_as_Monster();
20092038
}
20102039

2040+
template<> inline MyGame::Example::Monster *Monster::mutable_test_as<MyGame::Example::Monster>() {
2041+
return mutable_test_as_Monster();
2042+
}
2043+
20112044
template<> inline const MyGame::Example::TestSimpleTableWithEnum *Monster::test_as<MyGame::Example::TestSimpleTableWithEnum>() const {
20122045
return test_as_TestSimpleTableWithEnum();
20132046
}
20142047

2048+
template<> inline MyGame::Example::TestSimpleTableWithEnum *Monster::mutable_test_as<MyGame::Example::TestSimpleTableWithEnum>() {
2049+
return mutable_test_as_TestSimpleTableWithEnum();
2050+
}
2051+
20152052
template<> inline const MyGame::Example2::Monster *Monster::test_as<MyGame::Example2::Monster>() const {
20162053
return test_as_MyGame_Example2_Monster();
20172054
}
20182055

2056+
template<> inline MyGame::Example2::Monster *Monster::mutable_test_as<MyGame::Example2::Monster>() {
2057+
return mutable_test_as_MyGame_Example2_Monster();
2058+
}
2059+
20192060
template<> inline const MyGame::Example::Monster *Monster::any_unique_as<MyGame::Example::Monster>() const {
20202061
return any_unique_as_M();
20212062
}
20222063

2064+
template<> inline MyGame::Example::Monster *Monster::mutable_any_unique_as<MyGame::Example::Monster>() {
2065+
return mutable_any_unique_as_M();
2066+
}
2067+
20232068
template<> inline const MyGame::Example::TestSimpleTableWithEnum *Monster::any_unique_as<MyGame::Example::TestSimpleTableWithEnum>() const {
20242069
return any_unique_as_TS();
20252070
}
20262071

2072+
template<> inline MyGame::Example::TestSimpleTableWithEnum *Monster::mutable_any_unique_as<MyGame::Example::TestSimpleTableWithEnum>() {
2073+
return mutable_any_unique_as_TS();
2074+
}
2075+
20272076
template<> inline const MyGame::Example2::Monster *Monster::any_unique_as<MyGame::Example2::Monster>() const {
20282077
return any_unique_as_M2();
20292078
}
20302079

2080+
template<> inline MyGame::Example2::Monster *Monster::mutable_any_unique_as<MyGame::Example2::Monster>() {
2081+
return mutable_any_unique_as_M2();
2082+
}
2083+
20312084
struct MonsterBuilder {
20322085
typedef Monster Table;
20332086
::flatbuffers::FlatBufferBuilder &fbb_;

tests/cpp17/generated_cpp17/union_vector_generated.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,24 @@ struct Movie FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
595595
const ::flatbuffers::String *main_character_as_Unused() const {
596596
return main_character_type() == Character::Unused ? static_cast<const ::flatbuffers::String *>(main_character()) : nullptr;
597597
}
598+
Attacker *mutable_main_character_as_MuLan() {
599+
return main_character_type() == Character::MuLan ? static_cast<Attacker *>(mutable_main_character()) : nullptr;
600+
}
601+
Rapunzel *mutable_main_character_as_Rapunzel() {
602+
return main_character_type() == Character::Rapunzel ? static_cast<Rapunzel *>(mutable_main_character()) : nullptr;
603+
}
604+
BookReader *mutable_main_character_as_Belle() {
605+
return main_character_type() == Character::Belle ? static_cast<BookReader *>(mutable_main_character()) : nullptr;
606+
}
607+
BookReader *mutable_main_character_as_BookFan() {
608+
return main_character_type() == Character::BookFan ? static_cast<BookReader *>(mutable_main_character()) : nullptr;
609+
}
610+
::flatbuffers::String *mutable_main_character_as_Other() {
611+
return main_character_type() == Character::Other ? static_cast<::flatbuffers::String *>(mutable_main_character()) : nullptr;
612+
}
613+
::flatbuffers::String *mutable_main_character_as_Unused() {
614+
return main_character_type() == Character::Unused ? static_cast<::flatbuffers::String *>(mutable_main_character()) : nullptr;
615+
}
598616
void *mutable_main_character() {
599617
return GetPointer<void *>(VT_MAIN_CHARACTER);
600618
}

tests/monster_test_generated.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
14971497
const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const {
14981498
return test_type() == MyGame::Example::Any_MyGame_Example2_Monster ? static_cast<const MyGame::Example2::Monster *>(test()) : nullptr;
14991499
}
1500+
template<typename T> T *mutable_test_as();
1501+
MyGame::Example::Monster *mutable_test_as_Monster() {
1502+
return test_type() == MyGame::Example::Any_Monster ? static_cast<MyGame::Example::Monster *>(mutable_test()) : nullptr;
1503+
}
1504+
MyGame::Example::TestSimpleTableWithEnum *mutable_test_as_TestSimpleTableWithEnum() {
1505+
return test_type() == MyGame::Example::Any_TestSimpleTableWithEnum ? static_cast<MyGame::Example::TestSimpleTableWithEnum *>(mutable_test()) : nullptr;
1506+
}
1507+
MyGame::Example2::Monster *mutable_test_as_MyGame_Example2_Monster() {
1508+
return test_type() == MyGame::Example::Any_MyGame_Example2_Monster ? static_cast<MyGame::Example2::Monster *>(mutable_test()) : nullptr;
1509+
}
15001510
void *mutable_test() {
15011511
return GetPointer<void *>(VT_TEST);
15021512
}
@@ -1732,6 +1742,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
17321742
const MyGame::Example2::Monster *any_unique_as_M2() const {
17331743
return any_unique_type() == MyGame::Example::AnyUniqueAliases_M2 ? static_cast<const MyGame::Example2::Monster *>(any_unique()) : nullptr;
17341744
}
1745+
template<typename T> T *mutable_any_unique_as();
1746+
MyGame::Example::Monster *mutable_any_unique_as_M() {
1747+
return any_unique_type() == MyGame::Example::AnyUniqueAliases_M ? static_cast<MyGame::Example::Monster *>(mutable_any_unique()) : nullptr;
1748+
}
1749+
MyGame::Example::TestSimpleTableWithEnum *mutable_any_unique_as_TS() {
1750+
return any_unique_type() == MyGame::Example::AnyUniqueAliases_TS ? static_cast<MyGame::Example::TestSimpleTableWithEnum *>(mutable_any_unique()) : nullptr;
1751+
}
1752+
MyGame::Example2::Monster *mutable_any_unique_as_M2() {
1753+
return any_unique_type() == MyGame::Example::AnyUniqueAliases_M2 ? static_cast<MyGame::Example2::Monster *>(mutable_any_unique()) : nullptr;
1754+
}
17351755
void *mutable_any_unique() {
17361756
return GetPointer<void *>(VT_ANY_UNIQUE);
17371757
}
@@ -1750,6 +1770,15 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
17501770
const MyGame::Example::Monster *any_ambiguous_as_M3() const {
17511771
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M3 ? static_cast<const MyGame::Example::Monster *>(any_ambiguous()) : nullptr;
17521772
}
1773+
MyGame::Example::Monster *mutable_any_ambiguous_as_M1() {
1774+
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M1 ? static_cast<MyGame::Example::Monster *>(mutable_any_ambiguous()) : nullptr;
1775+
}
1776+
MyGame::Example::Monster *mutable_any_ambiguous_as_M2() {
1777+
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M2 ? static_cast<MyGame::Example::Monster *>(mutable_any_ambiguous()) : nullptr;
1778+
}
1779+
MyGame::Example::Monster *mutable_any_ambiguous_as_M3() {
1780+
return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M3 ? static_cast<MyGame::Example::Monster *>(mutable_any_ambiguous()) : nullptr;
1781+
}
17531782
void *mutable_any_ambiguous() {
17541783
return GetPointer<void *>(VT_ANY_AMBIGUOUS);
17551784
}
@@ -1959,26 +1988,50 @@ template<> inline const MyGame::Example::Monster *Monster::test_as<MyGame::Examp
19591988
return test_as_Monster();
19601989
}
19611990

1991+
template<> inline MyGame::Example::Monster *Monster::mutable_test_as<MyGame::Example::Monster>() {
1992+
return mutable_test_as_Monster();
1993+
}
1994+
19621995
template<> inline const MyGame::Example::TestSimpleTableWithEnum *Monster::test_as<MyGame::Example::TestSimpleTableWithEnum>() const {
19631996
return test_as_TestSimpleTableWithEnum();
19641997
}
19651998

1999+
template<> inline MyGame::Example::TestSimpleTableWithEnum *Monster::mutable_test_as<MyGame::Example::TestSimpleTableWithEnum>() {
2000+
return mutable_test_as_TestSimpleTableWithEnum();
2001+
}
2002+
19662003
template<> inline const MyGame::Example2::Monster *Monster::test_as<MyGame::Example2::Monster>() const {
19672004
return test_as_MyGame_Example2_Monster();
19682005
}
19692006

2007+
template<> inline MyGame::Example2::Monster *Monster::mutable_test_as<MyGame::Example2::Monster>() {
2008+
return mutable_test_as_MyGame_Example2_Monster();
2009+
}
2010+
19702011
template<> inline const MyGame::Example::Monster *Monster::any_unique_as<MyGame::Example::Monster>() const {
19712012
return any_unique_as_M();
19722013
}
19732014

2015+
template<> inline MyGame::Example::Monster *Monster::mutable_any_unique_as<MyGame::Example::Monster>() {
2016+
return mutable_any_unique_as_M();
2017+
}
2018+
19742019
template<> inline const MyGame::Example::TestSimpleTableWithEnum *Monster::any_unique_as<MyGame::Example::TestSimpleTableWithEnum>() const {
19752020
return any_unique_as_TS();
19762021
}
19772022

2023+
template<> inline MyGame::Example::TestSimpleTableWithEnum *Monster::mutable_any_unique_as<MyGame::Example::TestSimpleTableWithEnum>() {
2024+
return mutable_any_unique_as_TS();
2025+
}
2026+
19782027
template<> inline const MyGame::Example2::Monster *Monster::any_unique_as<MyGame::Example2::Monster>() const {
19792028
return any_unique_as_M2();
19802029
}
19812030

2031+
template<> inline MyGame::Example2::Monster *Monster::mutable_any_unique_as<MyGame::Example2::Monster>() {
2032+
return mutable_any_unique_as_M2();
2033+
}
2034+
19822035
struct MonsterBuilder {
19832036
typedef Monster Table;
19842037
::flatbuffers::FlatBufferBuilder &fbb_;

0 commit comments

Comments
 (0)