@@ -100,7 +100,9 @@ public void generate() throws IOException
100100 groups , varData , BASE_INDENT + INDENT );
101101 generateMessageEncodeInto (classBuilder , className , codecClassName , fields , groups , varData ,
102102 BASE_INDENT + INDENT );
103- generateDisplay (classBuilder , codecClassName , "wrapForEncode" , null , BASE_INDENT + INDENT );
103+ generateComputeEncodedLength (classBuilder , codecClassName , groups , varData , BASE_INDENT + INDENT );
104+ generateDisplay (classBuilder , className , codecClassName , "dto.computeEncodedLength()" ,
105+ "wrapForEncode" , null , BASE_INDENT + INDENT );
104106
105107 try (Writer out = outputManager .createOutput (className ))
106108 {
@@ -227,6 +229,8 @@ private void generateGroups(
227229 fields , groups , varData , indent + INDENT );
228230 generateMessageEncodeInto (
229231 groupClassBuilder , groupClassName , qualifiedCodecClassName , fields , groups , varData , indent + INDENT );
232+ generateComputeEncodedLength (groupClassBuilder , qualifiedCodecClassName , groups , varData ,
233+ indent + INDENT );
230234
231235 groupClassBuilder .appendTo (
232236 classBuilder .appendPublic ().append ("\n " ).append (generateDocumentation (indent , groupToken ))
@@ -266,6 +270,103 @@ private void generateGroups(
266270 }
267271 }
268272
273+ private void generateComputeEncodedLength (
274+ final ClassBuilder classBuilder ,
275+ final String qualifiedCodecClassName ,
276+ final List <Token > groupTokens ,
277+ final List <Token > varDataTokens ,
278+ final String indent )
279+ {
280+ final StringBuilder lengthBuilder = classBuilder .appendPublic ()
281+ .append ("\n " )
282+ .append (indent ).append ("[[nodiscard]] std::size_t computeEncodedLength() const\n " )
283+ .append (indent ).append ("{\n " );
284+
285+ final StringBuilder arguments = new StringBuilder ();
286+
287+ for (int i = 0 , size = groupTokens .size (); i < size ; i ++)
288+ {
289+ final Token groupToken = groupTokens .get (i );
290+ if (groupToken .signal () != Signal .BEGIN_GROUP )
291+ {
292+ throw new IllegalStateException ("tokens must begin with BEGIN_GROUP: token=" + groupToken );
293+ }
294+
295+ i ++;
296+ i += groupTokens .get (i ).componentTokenCount ();
297+
298+ final List <Token > fields = new ArrayList <>();
299+ i = collectFields (groupTokens , i , fields );
300+ final List <Token > subGroups = new ArrayList <>();
301+ i = collectGroups (groupTokens , i , subGroups );
302+ final List <Token > subVarData = new ArrayList <>();
303+ i = collectVarData (groupTokens , i , subVarData );
304+
305+ final String groupName = groupToken .name ();
306+ final String fieldName = "m_" + toLowerFirstChar (groupName );
307+
308+ final boolean isConstLength = subGroups .isEmpty () && subVarData .isEmpty ();
309+ final String argumentName = isConstLength ?
310+ toLowerFirstChar (groupName ) + "Count" :
311+ toLowerFirstChar (groupName ) + "Lengths" ;
312+
313+ if (isConstLength )
314+ {
315+ lengthBuilder
316+ .append (indent ).append (INDENT ).append ("std::size_t " ).append (argumentName )
317+ .append (" = " ).append (fieldName ).append (".size();\n " );
318+ }
319+ else
320+ {
321+ final String countName = argumentName + "Count" ;
322+
323+ lengthBuilder
324+ .append (indent ).append (INDENT ).append ("std::size_t " ).append (countName ).append (" = " )
325+ .append (fieldName ).append (".size();\n " )
326+ .append (indent ).append (INDENT ).append ("std::vector<std::tuple<std::size_t>> " )
327+ .append (argumentName ).append ("(" ).append (countName ).append (");\n " )
328+ .append (indent ).append (INDENT ).append ("for (std::size_t i = 0; i < " ).append (countName )
329+ .append ("; i++)\n " )
330+ .append (indent ).append (INDENT ).append ("{\n " )
331+ .append (indent ).append (INDENT ).append (INDENT )
332+ .append ("auto& group = " ).append (fieldName ).append ("[i];\n " )
333+ .append (indent ).append (INDENT ).append (INDENT )
334+ .append (argumentName ).append ("[i] = group.computeEncodedLength();\n " )
335+ .append (indent ).append (INDENT ).append ("}\n " )
336+ .append ("\n " );
337+ }
338+
339+ arguments .append (argumentName ).append (", " );
340+ }
341+
342+ for (int i = 0 , size = varDataTokens .size (); i < size ; i ++)
343+ {
344+ final Token token = varDataTokens .get (i );
345+ if (token .signal () == Signal .BEGIN_VAR_DATA )
346+ {
347+ final String propertyName = token .name ();
348+ final Token varDataToken = Generators .findFirst ("varData" , varDataTokens , i );
349+ final String fieldName = "m_" + toLowerFirstChar (propertyName );
350+ final String argumentName = toLowerFirstChar (propertyName ) + "Length" ;
351+
352+ lengthBuilder .append (indent ).append (INDENT ).append ("std::size_t " ).append (argumentName )
353+ .append (" = " ).append (fieldName ).append (".size() * sizeof(" )
354+ .append (cppTypeName (varDataToken .encoding ().primitiveType ())).append (");\n " );
355+
356+ arguments .append (argumentName ).append (", " );
357+ }
358+ }
359+
360+ if (arguments .length () >= 2 )
361+ {
362+ arguments .setLength (arguments .length () - 2 );
363+ }
364+
365+ lengthBuilder .append (indent ).append (INDENT ).append ("return " ).append (qualifiedCodecClassName )
366+ .append ("::computeLength(" ).append (arguments ).append (");\n " )
367+ .append (indent ).append ("}\n " );
368+ }
369+
269370 private void generateCompositeDecodeFrom (
270371 final ClassBuilder classBuilder ,
271372 final String dtoClassName ,
@@ -944,8 +1045,8 @@ private void generateGroupsEncodeInto(
9441045 .append ("Count(" ).append (formattedPropertyName ).append (".size());\n \n " )
9451046 .append (indent ).append ("for (const auto& group: " ).append (formattedPropertyName ).append (")\n " )
9461047 .append (indent ).append ("{\n " )
947- .append (indent ).append (INDENT ).append (groupDtoTypeName ). append ( "::encodeWith(" ). append ( groupCodecVarName )
948- .append (".next(), group);\n " )
1048+ .append (indent ).append (INDENT ).append (groupDtoTypeName )
1049+ .append ("::encodeWith(" ). append ( groupCodecVarName ). append ( " .next(), group);\n " )
9491050 .append (indent ).append ("}\n \n " );
9501051
9511052 i ++;
@@ -1002,32 +1103,44 @@ private void generateVarDataEncodeInto(
10021103
10031104 private void generateDisplay (
10041105 final ClassBuilder classBuilder ,
1106+ final String dtoClassName ,
10051107 final String codecClassName ,
1108+ final String lengthExpression ,
10061109 final String wrapMethod ,
10071110 final String actingVersion ,
10081111 final String indent )
10091112 {
1010- final StringBuilder toStringBuilder = classBuilder .appendPublic ()
1113+ final StringBuilder streamBuilder = classBuilder .appendPublic ()
10111114 .append ("\n " )
1012- .append (indent ).append (
1013- "std::string string(char* tempBuffer, std::uint64_t offset, std::uint64_t length) const \n " )
1115+ .append (indent ).append ("friend std::ostream& operator << (std::ostream& stream, const " )
1116+ . append ( dtoClassName ). append ( "& dto) \n " )
10141117 .append (indent ).append ("{\n " )
10151118 .append (indent ).append (INDENT ).append (codecClassName ).append (" codec;\n " )
1016- .append (indent ).append (INDENT ).append ("codec." );
1017-
1018- toStringBuilder .append (wrapMethod ).append ("(tempBuffer, offset" );
1119+ .append (indent ).append (INDENT ).append ("const std::size_t length = " )
1120+ .append (lengthExpression ).append (";\n " )
1121+ .append (indent ).append (INDENT ).append ("std::vector<char> buffer(length);\n " )
1122+ .append (indent ).append (INDENT ).append ("codec." ).append (wrapMethod )
1123+ .append ("(buffer.data(), 0" );
10191124
10201125 if (null != actingVersion )
10211126 {
1022- toStringBuilder .append (", " ).append (actingVersion );
1127+ streamBuilder .append (", " ).append (actingVersion );
10231128 }
10241129
1025- toStringBuilder .append (", " ).append ("length);\n " );
1130+ streamBuilder .append (", " ).append ("length);\n " );
1131+
1132+ streamBuilder .append (indent ).append (INDENT ).append ("encodeWith(codec, dto);\n " )
1133+ .append (indent ).append (INDENT ).append ("stream << codec;\n " )
1134+ .append (indent ).append (INDENT ).append ("return stream;\n " )
1135+ .append (indent ).append ("}\n " );
10261136
1027- toStringBuilder .append (indent ).append (INDENT ).append ("encodeWith(codec, *this);\n " )
1028- .append (indent ).append (INDENT ).append ("std::ostringstream oss;\n " )
1029- .append (indent ).append (INDENT ).append ("oss << codec;\n " )
1030- .append (indent ).append (INDENT ).append ("return oss.str();\n " )
1137+ classBuilder .appendPublic ()
1138+ .append ("\n " )
1139+ .append (indent ).append ("[[nodiscard]] std::string string() const\n " )
1140+ .append (indent ).append ("{\n " )
1141+ .append (indent ).append (INDENT ).append ("std::ostringstream stream;\n " )
1142+ .append (indent ).append (INDENT ).append ("stream << *this;\n " )
1143+ .append (indent ).append (INDENT ).append ("return stream.str();\n " )
10311144 .append (indent ).append ("}\n " );
10321145 }
10331146
@@ -1547,7 +1660,7 @@ private void generateComposite(final List<Token> tokens) throws IOException
15471660 generateCompositeDecodeFrom (classBuilder , className , codecClassName , compositeTokens ,
15481661 BASE_INDENT + INDENT );
15491662 generateCompositeEncodeInto (classBuilder , className , codecClassName , compositeTokens , BASE_INDENT + INDENT );
1550- generateDisplay (classBuilder , codecClassName , "wrap" ,
1663+ generateDisplay (classBuilder , className , codecClassName , codecClassName + "::encodedLength()" , "wrap" ,
15511664 codecClassName + "::sbeSchemaVersion()" , BASE_INDENT + INDENT );
15521665
15531666 classBuilder .appendTo (out );
0 commit comments