Skip to content

Commit 0c48ee3

Browse files
authored
[C++] Fix field precedence check issue #1031. (#1033)
There were a couple of problems here: 1. "wrapping constructors" did not initialize the codec state (for precedence checks) correctly, and 2. the methods returning a JSON encoded string would attempt to transition twice. These problems are now resolved. I have also made a technically breaking change. I have removed an unnecessary constructor that took in the codec state. I think it is highly unlikely that anyone was using this constructor; therefore, it should be okay to make the change.
1 parent daf0283 commit 0c48ee3

File tree

2 files changed

+120
-52
lines changed

2 files changed

+120
-52
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,7 @@ private void generateVarData(
12011201
lengthCppType,
12021202
accessOrderListenerCall);
12031203

1204-
generateJsonEscapedStringGetter(sb, token, indent, propertyName, accessOrderListenerCall);
1204+
generateJsonEscapedStringGetter(sb, token, indent, propertyName);
12051205

12061206
new Formatter(sb).format("\n" +
12071207
indent + " #if __cplusplus >= 201703L\n" +
@@ -2307,7 +2307,7 @@ private void generateArrayProperty(
23072307
generateStringNotPresentCondition(propertyToken.version(), indent),
23082308
accessOrderListenerCall);
23092309

2310-
generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName, accessOrderListenerCall);
2310+
generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName);
23112311

23122312
new Formatter(sb).format("\n" +
23132313
indent + " #if __cplusplus >= 201703L\n" +
@@ -2381,14 +2381,12 @@ private void generateJsonEscapedStringGetter(
23812381
final StringBuilder sb,
23822382
final Token token,
23832383
final String indent,
2384-
final String propertyName,
2385-
final CharSequence accessOrderListenerCall)
2384+
final String propertyName)
23862385
{
23872386
new Formatter(sb).format("\n" +
23882387
indent + " std::string get%1$sAsJsonEscapedString()\n" +
23892388
indent + " {\n" +
23902389
"%2$s" +
2391-
"%3$s" +
23922390
indent + " std::ostringstream oss;\n" +
23932391
indent + " std::string s = get%1$sAsString();\n\n" +
23942392
indent + " for (const auto c : s)\n" +
@@ -2417,8 +2415,7 @@ private void generateJsonEscapedStringGetter(
24172415
indent + " return oss.str();\n" +
24182416
indent + " }\n",
24192417
toUpperFirstChar(propertyName),
2420-
generateStringNotPresentCondition(token.version(), indent),
2421-
accessOrderListenerCall);
2418+
generateStringNotPresentCondition(token.version(), indent));
24222419
}
24232420

24242421
private void generateConstPropertyMethods(
@@ -2505,7 +2502,7 @@ private void generateConstPropertyMethods(
25052502
values,
25062503
constantValue.length);
25072504

2508-
generateJsonEscapedStringGetter(sb, token, indent, propertyName, "");
2505+
generateJsonEscapedStringGetter(sb, token, indent, propertyName);
25092506
}
25102507

25112508
private CharSequence generateFixedFlyweightCode(final String className, final int size)
@@ -2654,34 +2651,13 @@ private static String generateHiddenCopyConstructor(final String indent, final S
26542651
return DISABLE_IMPLICIT_COPYING ? ctorAndCopyAssignmentDeletion : "";
26552652
}
26562653

2657-
private static CharSequence generateConstructorsAndOperators(
2654+
private CharSequence generateConstructorsAndOperators(
26582655
final String className,
26592656
final FieldPrecedenceModel fieldPrecedenceModel)
26602657
{
2661-
final String constructorWithCodecState = null == fieldPrecedenceModel ? "" : String.format(
2662-
" %1$s(\n" +
2663-
" char *buffer,\n" +
2664-
" const std::uint64_t offset,\n" +
2665-
" const std::uint64_t bufferLength,\n" +
2666-
" const std::uint64_t actingBlockLength,\n" +
2667-
" const std::uint64_t actingVersion,\n" +
2668-
" CodecState codecState) :\n" +
2669-
" m_buffer(buffer),\n" +
2670-
" m_bufferLength(bufferLength),\n" +
2671-
" m_offset(offset),\n" +
2672-
" m_position(sbeCheckPosition(offset + actingBlockLength)),\n" +
2673-
" m_actingBlockLength(actingBlockLength),\n" +
2674-
" m_actingVersion(actingVersion),\n" +
2675-
" m_codecState(codecState)\n" +
2676-
" {\n" +
2677-
" }\n\n",
2678-
className);
2679-
26802658
return String.format(
26812659
" %1$s() = default;\n\n" +
26822660

2683-
"%2$s" +
2684-
26852661
" %1$s(\n" +
26862662
" char *buffer,\n" +
26872663
" const std::uint64_t offset,\n" +
@@ -2695,6 +2671,7 @@ private static CharSequence generateConstructorsAndOperators(
26952671
" m_actingBlockLength(actingBlockLength),\n" +
26962672
" m_actingVersion(actingVersion)\n" +
26972673
" {\n" +
2674+
"%2$s" +
26982675
" }\n\n" +
26992676

27002677
" %1$s(char *buffer, const std::uint64_t bufferLength) :\n" +
@@ -2711,7 +2688,7 @@ private static CharSequence generateConstructorsAndOperators(
27112688
" {\n" +
27122689
" }\n\n",
27132690
className,
2714-
constructorWithCodecState);
2691+
generateCodecStateTransitionForWrapping(fieldPrecedenceModel));
27152692
}
27162693

27172694
private CharSequence generateMessageFlyweightCode(
@@ -2728,26 +2705,25 @@ private CharSequence generateMessageFlyweightCode(
27282705
final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion();
27292706

27302707

2731-
final String codecStateArgument = null == fieldPrecedenceModel ? "" : ", m_codecState";
2732-
27332708
return String.format(
27342709
"private:\n" +
2710+
"%14$s" +
27352711
"%15$s" +
2736-
"%16$s" +
27372712
" char *m_buffer = nullptr;\n" +
27382713
" std::uint64_t m_bufferLength = 0;\n" +
27392714
" std::uint64_t m_offset = 0;\n" +
27402715
" std::uint64_t m_position = 0;\n" +
27412716
" std::uint64_t m_actingBlockLength = 0;\n" +
27422717
" std::uint64_t m_actingVersion = 0;\n" +
2743-
"%17$s" +
2718+
"%16$s" +
27442719

27452720
" inline std::uint64_t *sbePositionPtr() SBE_NOEXCEPT\n" +
27462721
" {\n" +
27472722
" return &m_position;\n" +
27482723
" }\n\n" +
27492724

2750-
"%22$s" +
2725+
"%19$s" +
2726+
"%21$s" +
27512727

27522728
"public:\n" +
27532729
" static constexpr %1$s SBE_BLOCK_LENGTH = %2$s;\n" +
@@ -2775,7 +2751,7 @@ private CharSequence generateMessageFlyweightCode(
27752751

27762752
" using messageHeader = %12$s;\n\n" +
27772753

2778-
"%18$s" +
2754+
"%17$s" +
27792755
"%11$s" +
27802756

27812757
" SBE_NODISCARD static SBE_CONSTEXPR %1$s sbeBlockLength() SBE_NOEXCEPT\n" +
@@ -2826,7 +2802,7 @@ private CharSequence generateMessageFlyweightCode(
28262802
" m_actingBlockLength = sbeBlockLength();\n" +
28272803
" m_actingVersion = sbeSchemaVersion();\n" +
28282804
" m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" +
2829-
"%19$s" +
2805+
"%18$s" +
28302806
" return *this;\n" +
28312807
" }\n\n" +
28322808

@@ -2847,12 +2823,10 @@ private CharSequence generateMessageFlyweightCode(
28472823
" m_actingBlockLength = sbeBlockLength();\n" +
28482824
" m_actingVersion = sbeSchemaVersion();\n" +
28492825
" m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" +
2850-
"%19$s" +
2826+
"%18$s" +
28512827
" return *this;\n" +
28522828
" }\n\n" +
28532829

2854-
"%20$s" +
2855-
28562830
" %10$s &wrapForDecode(\n" +
28572831
" char *buffer,\n" +
28582832
" const std::uint64_t offset,\n" +
@@ -2866,7 +2840,7 @@ private CharSequence generateMessageFlyweightCode(
28662840
" m_actingBlockLength = actingBlockLength;\n" +
28672841
" m_actingVersion = actingVersion;\n" +
28682842
" m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" +
2869-
"%21$s" +
2843+
"%20$s" +
28702844
" return *this;\n" +
28712845
" }\n\n" +
28722846

@@ -2903,7 +2877,7 @@ private CharSequence generateMessageFlyweightCode(
29032877

29042878
" SBE_NODISCARD std::uint64_t decodeLength() const\n" +
29052879
" {\n" +
2906-
" %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion%14$s);\n" +
2880+
" %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion);\n" +
29072881
" skipper.skip();\n" +
29082882
" return skipper.encodedLength();\n" +
29092883
" }\n\n" +
@@ -2940,14 +2914,13 @@ private CharSequence generateMessageFlyweightCode(
29402914
generateConstructorsAndOperators(className, fieldPrecedenceModel),
29412915
formatClassName(headerType),
29422916
semanticVersion,
2943-
codecStateArgument,
29442917
generateFieldOrderStateEnum(fieldPrecedenceModel),
29452918
generateLookupTableDeclarations(fieldPrecedenceModel),
29462919
generateFieldOrderStateMember(fieldPrecedenceModel),
29472920
generateAccessOrderErrorType(fieldPrecedenceModel),
2948-
generateEncoderWrapListener(fieldPrecedenceModel),
2949-
generateDecoderWrapListener(fieldPrecedenceModel),
2950-
generateDecoderWrapListenerCall(fieldPrecedenceModel),
2921+
generateCodecStateTransitionForWrappingLatestVersion(fieldPrecedenceModel),
2922+
generateOnWrappedListener(fieldPrecedenceModel),
2923+
generateCodecStateTransitionForWrapping(fieldPrecedenceModel),
29512924
generateHiddenCopyConstructor(" ", className));
29522925
}
29532926

@@ -3118,7 +3091,7 @@ private static CharSequence generateFieldOrderStateMember(final FieldPrecedenceM
31183091
return sb;
31193092
}
31203093

3121-
private static CharSequence generateDecoderWrapListener(final FieldPrecedenceModel fieldPrecedenceModel)
3094+
private static CharSequence generateOnWrappedListener(final FieldPrecedenceModel fieldPrecedenceModel)
31223095
{
31233096
if (null == fieldPrecedenceModel)
31243097
{
@@ -3131,7 +3104,7 @@ private static CharSequence generateDecoderWrapListener(final FieldPrecedenceMod
31313104
}
31323105

31333106
final StringBuilder sb = new StringBuilder();
3134-
sb.append(INDENT).append("void onWrapForDecode(std::uint64_t actingVersion)\n")
3107+
sb.append(INDENT).append("void onWrapped(std::uint64_t actingVersion)\n")
31353108
.append(INDENT).append("{\n");
31363109

31373110
final MutableBoolean actingVersionCanBeTooLowToBeValid = new MutableBoolean(true);
@@ -3168,7 +3141,7 @@ private static CharSequence generateDecoderWrapListener(final FieldPrecedenceMod
31683141
}
31693142

31703143

3171-
private CharSequence generateDecoderWrapListenerCall(final FieldPrecedenceModel fieldPrecedenceModel)
3144+
private CharSequence generateCodecStateTransitionForWrapping(final FieldPrecedenceModel fieldPrecedenceModel)
31723145
{
31733146
if (null == fieldPrecedenceModel)
31743147
{
@@ -3185,10 +3158,12 @@ private CharSequence generateDecoderWrapListenerCall(final FieldPrecedenceModel
31853158
return sb;
31863159
}
31873160

3188-
return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapForDecode", "actingVersion");
3161+
return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapped", "actingVersion");
31893162
}
31903163

3191-
private CharSequence generateEncoderWrapListener(final FieldPrecedenceModel fieldPrecedenceModel)
3164+
private CharSequence generateCodecStateTransitionForWrappingLatestVersion(
3165+
final FieldPrecedenceModel fieldPrecedenceModel
3166+
)
31923167
{
31933168
if (null == fieldPrecedenceModel)
31943169
{

sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include <sstream>
1718
#include "gtest/gtest.h"
1819
#include "gmock/gmock.h"
1920
#include "order_check/MultipleVarLength.h"
@@ -4955,3 +4956,95 @@ TEST_F(FieldAccessOrderCheckTest, allowsSkippingFutureGroupWhenDecodingFromVersi
49554956
EXPECT_EQ(decoder.a(), 42);
49564957
EXPECT_EQ(decoder.getBAsString(), "abc");
49574958
}
4959+
4960+
TEST_F(FieldAccessOrderCheckTest, worksWithWrappingConstructors1)
4961+
{
4962+
MultipleVarLength encoder(m_buffer, BUFFER_LEN);
4963+
encoder.a(42);
4964+
encoder.putB("abc");
4965+
encoder.putC("def");
4966+
encoder.checkEncodingIsComplete();
4967+
4968+
MultipleVarLength decoder(m_buffer, BUFFER_LEN);
4969+
EXPECT_EQ(decoder.a(), 42);
4970+
EXPECT_EQ(decoder.getBAsString(), "abc");
4971+
EXPECT_EQ(decoder.getCAsString(), "def");
4972+
}
4973+
4974+
TEST_F(FieldAccessOrderCheckTest, worksWithWrappingConstructors2)
4975+
{
4976+
MultipleVarLength encoder(
4977+
m_buffer,
4978+
BUFFER_LEN,
4979+
MultipleVarLength::sbeBlockLength(),
4980+
MultipleVarLength::sbeSchemaVersion()
4981+
);
4982+
encoder.a(42);
4983+
encoder.putB("abc");
4984+
encoder.putC("def");
4985+
encoder.checkEncodingIsComplete();
4986+
4987+
MultipleVarLength decoder(
4988+
m_buffer,
4989+
BUFFER_LEN,
4990+
MultipleVarLength::sbeBlockLength(),
4991+
MultipleVarLength::sbeSchemaVersion()
4992+
);
4993+
EXPECT_EQ(decoder.a(), 42);
4994+
EXPECT_EQ(decoder.getBAsString(), "abc");
4995+
EXPECT_EQ(decoder.getCAsString(), "def");
4996+
}
4997+
4998+
TEST_F(FieldAccessOrderCheckTest, worksWithWrappingConstructors3)
4999+
{
5000+
MultipleVarLength encoder(
5001+
m_buffer,
5002+
OFFSET,
5003+
BUFFER_LEN,
5004+
MultipleVarLength::sbeBlockLength(),
5005+
MultipleVarLength::sbeSchemaVersion()
5006+
);
5007+
encoder.a(42);
5008+
encoder.putB("abc");
5009+
encoder.putC("def");
5010+
encoder.checkEncodingIsComplete();
5011+
5012+
MultipleVarLength decoder(
5013+
m_buffer,
5014+
OFFSET,
5015+
BUFFER_LEN,
5016+
MultipleVarLength::sbeBlockLength(),
5017+
MultipleVarLength::sbeSchemaVersion()
5018+
);
5019+
EXPECT_EQ(decoder.a(), 42);
5020+
EXPECT_EQ(decoder.getBAsString(), "abc");
5021+
EXPECT_EQ(decoder.getCAsString(), "def");
5022+
}
5023+
5024+
TEST_F(FieldAccessOrderCheckTest, worksWithInsertionOperator)
5025+
{
5026+
MultipleVarLength encoder(
5027+
m_buffer,
5028+
OFFSET,
5029+
BUFFER_LEN,
5030+
MultipleVarLength::sbeBlockLength(),
5031+
MultipleVarLength::sbeSchemaVersion()
5032+
);
5033+
encoder.a(42);
5034+
encoder.putB("abc");
5035+
encoder.putC("def");
5036+
encoder.checkEncodingIsComplete();
5037+
5038+
MultipleVarLength decoder(
5039+
m_buffer,
5040+
BUFFER_LEN
5041+
);
5042+
std::stringstream stream;
5043+
stream << decoder;
5044+
5045+
const std::string expected = "\"a\": 42, \"b\": \"abc\", \"c\": \"def\"";
5046+
EXPECT_THAT(stream.str(), HasSubstr(expected));
5047+
EXPECT_EQ(decoder.a(), 42);
5048+
EXPECT_EQ(decoder.getBAsString(), "abc");
5049+
EXPECT_EQ(decoder.getCAsString(), "def");
5050+
}

0 commit comments

Comments
 (0)