diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index dd5065dbe..566545df2 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -536,6 +536,18 @@ private static void generateAccessOrderException( .append(fieldPrecedenceModel.generatedRepresentationClassName()).append(".\");\n"); } + private static void generateAccessOrderException( + final StringBuilder sb, + final String indent, + final String action) + { + sb.append(indent).append("throw AccessOrderError(") + .append("std::string(\"Illegal access. \") + \n") + .append(indent).append(INDENT) + .append("\"Cannot call \\\"").append(action) + .append("()\\\" in state: \" + codecStateName(codecState()));\n"); + } + private static void generateAccessOrderListenerMethodForNextGroupElement( final StringBuilder sb, final FieldPrecedenceModel fieldPrecedenceModel, @@ -3027,6 +3039,7 @@ private CharSequence generateMessageFlyweightCode( " SBE_NODISCARD std::uint64_t decodeLength() const\n" + " {\n" + + "%22$s" + " %10$s skipper(m_buffer, m_offset, m_bufferLength, m_actingBlockLength, m_actingVersion);\n" + " skipper.skip();\n" + " return skipper.encodedLength();\n" + @@ -3071,7 +3084,8 @@ private CharSequence generateMessageFlyweightCode( generateCodecStateTransitionForWrappingLatestVersion(fieldPrecedenceModel), generateOnWrappedListener(fieldPrecedenceModel), generateCodecStateTransitionForWrapping(fieldPrecedenceModel), - generateHiddenCopyConstructor(" ", className)); + generateHiddenCopyConstructor(" ", className), + generateCheckForNotWrappedState("decodeLength", fieldPrecedenceModel)); } private CharSequence generateAccessOrderErrorType(final FieldPrecedenceModel fieldPrecedenceModel) @@ -3311,6 +3325,31 @@ private CharSequence generateCodecStateTransitionForWrapping(final FieldPreceden return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapped", "actingVersion"); } + private CharSequence generateCheckForNotWrappedState( + final String action, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("#if defined(").append(precedenceChecksFlagName).append(")\n") + .append(TWO_INDENT) + .append("if (codecState() == ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(")\n") + .append(TWO_INDENT).append("{\n"); + + generateAccessOrderException(sb, THREE_INDENT, action); + + sb.append(TWO_INDENT).append("}\n") + .append("#endif\n"); + + return sb; + } + private CharSequence generateCodecStateTransitionForWrappingLatestVersion( final FieldPrecedenceModel fieldPrecedenceModel ) diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index ef59c81d0..2c0e524dc 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -5048,3 +5048,43 @@ TEST_F(FieldAccessOrderCheckTest, worksWithInsertionOperator) EXPECT_EQ(decoder.getBAsString(), "abc"); EXPECT_EQ(decoder.getCAsString(), "def"); } + +TEST_F(FieldAccessOrderCheckTest, shouldThrowExceptionWhenNotWrapped) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + + EXPECT_THROW( + { + try + { + decoder.decodeLength(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Illegal access. Cannot call \"decodeLength()\" in state: NOT_WRAPPED") + ); + throw; + } + }, + std::logic_error + ); + + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + decoder.decodeLength(); +}