@@ -138,6 +138,7 @@ public void generate() throws IOException
138138 generateGroups (sb , groups , BASE_INDENT );
139139 generateVarData (sb , className , varData , BASE_INDENT );
140140 generateDisplay (sb , msgToken .name (), fields , groups , varData , BASE_INDENT + INDENT );
141+ sb .append (generateMessageLength (fields , groups , varData , BASE_INDENT + INDENT ));
141142 sb .append ("};\n " );
142143 sb .append (CppUtil .closingBraces (ir .namespaces ().length )).append ("#endif\n " );
143144 out .append (sb );
@@ -178,6 +179,7 @@ private void generateGroups(final StringBuilder sb, final List<Token> tokens, fi
178179 generateVarData (sb , formatClassName (groupName ), varData , indent + INDENT );
179180
180181 sb .append (generateGroupDisplay (groupName , fields , groups , varData , indent + INDENT + INDENT ));
182+ sb .append (generateMessageLength (fields , groups , varData , indent + INDENT + INDENT ));
181183
182184 sb .append (indent ).append (" };\n " );
183185 generateGroupProperty (sb , groupName , groupToken , cppTypeForNumInGroup , indent );
@@ -1034,12 +1036,6 @@ private static CharSequence generateFileHeader(
10341036 "# define SBE_DOUBLE_NAN NAN\n " +
10351037 "#endif\n \n " +
10361038
1037- "#if __cplusplus >= 201103L\n " +
1038- "# include <cstdint>\n " +
1039- "# include <string>\n " +
1040- "# include <cstring>\n " +
1041- "#endif\n \n " +
1042-
10431039 "#if __cplusplus >= 201103L\n " +
10441040 "# define SBE_CONSTEXPR constexpr\n " +
10451041 "# define SBE_NOEXCEPT noexcept\n " +
@@ -1048,22 +1044,33 @@ private static CharSequence generateFileHeader(
10481044 "# define SBE_NOEXCEPT\n " +
10491045 "#endif\n \n " +
10501046
1047+ "#if __cplusplus >= 201402L\n " +
1048+ "# define SBE_CONSTEXPR_14 constexpr\n " +
1049+ "#else\n " +
1050+ "# define SBE_CONSTEXPR_14\n " +
1051+ "#endif\n \n " +
1052+
10511053 "#if __cplusplus >= 201703L\n " +
1054+ "# include <string_view>\n " +
10521055 "# define SBE_NODISCARD [[nodiscard]]\n " +
10531056 "#else\n " +
10541057 "# define SBE_NODISCARD\n " +
10551058 "#endif\n \n " +
10561059
10571060 "#if !defined(__STDC_LIMIT_MACROS)\n " +
10581061 "# define __STDC_LIMIT_MACROS 1\n " +
1059- "#endif\n " +
1062+ "#endif\n \n " +
1063+
10601064 "#include <cstdint>\n " +
10611065 "#include <cstring>\n " +
1066+ "#include <iomanip>\n " +
10621067 "#include <limits>\n " +
1063- "#include <stdexcept>\n \n " +
10641068 "#include <ostream>\n " +
1069+ "#include <stdexcept>\n " +
10651070 "#include <sstream>\n " +
1066- "#include <iomanip>\n \n " +
1071+ "#include <string>\n " +
1072+ "#include <vector>\n " +
1073+ "\n " +
10671074
10681075 "#if defined(WIN32) || defined(_WIN32)\n " +
10691076 "# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)\n " +
@@ -1934,6 +1941,11 @@ private CharSequence generateMessageFlyweightCode(final String className, final
19341941 " return %2$s;\n " +
19351942 " }\n \n " +
19361943
1944+ " SBE_NODISCARD static SBE_CONSTEXPR %1$s sbeBlockAndHeaderLength() SBE_NOEXCEPT\n " +
1945+ " {\n " +
1946+ " return MessageHeader::encodedLength() + sbeBlockLength();\n " +
1947+ " }\n \n " +
1948+
19371949 " SBE_NODISCARD static SBE_CONSTEXPR %3$s sbeTemplateId() SBE_NOEXCEPT\n " +
19381950 " {\n " +
19391951 " return %4$s;\n " +
@@ -2018,6 +2030,14 @@ private CharSequence generateMessageFlyweightCode(final String className, final
20182030 " return sbePosition() - m_offset;\n " +
20192031 " }\n \n " +
20202032
2033+ " SBE_NODISCARD std::uint64_t decodeLength() const\n " +
2034+ " {\n " +
2035+ " %10$s skipper(m_buffer, m_offset,\n " +
2036+ " m_bufferLength, sbeBlockLength(), m_actingVersion);\n " +
2037+ " skipper.skip();\n " +
2038+ " return skipper.encodedLength();\n " +
2039+ " }\n \n " +
2040+
20212041 " SBE_NODISCARD const char * buffer() const SBE_NOEXCEPT\n " +
20222042 " {\n " +
20232043 " return m_buffer;\n " +
@@ -2756,4 +2776,289 @@ private CharSequence generateEnumDisplay(final List<Token> tokens, final Token e
27562776
27572777 return sb ;
27582778 }
2779+
2780+ private Object [] generateMessageLengthArgs (
2781+ final List <Token > fields ,
2782+ final List <Token > groups ,
2783+ final List <Token > varData ,
2784+ final String indent ,
2785+ final boolean withName )
2786+ {
2787+ final StringBuilder sb = new StringBuilder ();
2788+ int count = 0 ;
2789+
2790+ for (int i = 0 , size = groups .size (); i < size ; i ++)
2791+ {
2792+ final Token groupToken = groups .get (i );
2793+ if (groupToken .signal () != Signal .BEGIN_GROUP )
2794+ {
2795+ throw new IllegalStateException ("tokens must begin with BEGIN_GROUP: token=" + groupToken );
2796+ }
2797+
2798+ final int endSignal = findEndSignal (groups , i , Signal .END_GROUP , groupToken .name ());
2799+
2800+ if (count > 0 )
2801+ {
2802+ sb .append (",\n " + indent );
2803+ }
2804+
2805+ final List <Token > thisGroup = groups .subList (i , endSignal + 1 );
2806+
2807+ if (isMessageConstLength (thisGroup ))
2808+ {
2809+ sb .append ("std::size_t" );
2810+ if (withName )
2811+ {
2812+ sb .append (" " + groupToken .name () + "Length = 0" );
2813+ }
2814+ }
2815+ else
2816+ {
2817+ sb .append ("const std::vector<std::tuple<" );
2818+ sb .append (generateMessageLengthArgs (thisGroup , indent + INDENT , false )[0 ]);
2819+ sb .append (">>&" );
2820+
2821+ if (withName )
2822+ {
2823+ sb .append (" " + groupToken .name () + "ItemLengths = {}" );
2824+ }
2825+ }
2826+
2827+ count += 1 ;
2828+
2829+ i = endSignal ;
2830+ }
2831+
2832+ for (int i = 0 , size = varData .size (); i < size ;)
2833+ {
2834+ final Token varDataToken = varData .get (i );
2835+ if (varDataToken .signal () != Signal .BEGIN_VAR_DATA )
2836+ {
2837+ throw new IllegalStateException ("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken );
2838+ }
2839+
2840+ if (count > 0 )
2841+ {
2842+ sb .append (",\n " + indent );
2843+ }
2844+
2845+ sb .append ("std::size_t" );
2846+ if (withName )
2847+ {
2848+ sb .append (" " + varDataToken .name () + "Length = 0" );
2849+ }
2850+
2851+ count += 1 ;
2852+
2853+ i += varDataToken .componentTokenCount ();
2854+ }
2855+
2856+ CharSequence result = sb ;
2857+ if (count > 1 )
2858+ {
2859+ result = "\n " + indent + result ;
2860+ }
2861+
2862+ return new Object []{result , count };
2863+ }
2864+
2865+ private Object [] generateMessageLengthArgs (
2866+ final List <Token > tokens ,
2867+ final String indent ,
2868+ final boolean withName )
2869+ {
2870+ int i = 0 ;
2871+
2872+ final Token groupToken = tokens .get (i );
2873+ if (groupToken .signal () != Signal .BEGIN_GROUP )
2874+ {
2875+ throw new IllegalStateException ("tokens must begin with BEGIN_GROUP: token=" + groupToken );
2876+ }
2877+
2878+ ++i ;
2879+ final int groupHeaderTokenCount = tokens .get (i ).componentTokenCount ();
2880+ i += groupHeaderTokenCount ;
2881+
2882+ final List <Token > fields = new ArrayList <>();
2883+ i = collectFields (tokens , i , fields );
2884+
2885+ final List <Token > groups = new ArrayList <>();
2886+ i = collectGroups (tokens , i , groups );
2887+
2888+ final List <Token > varData = new ArrayList <>();
2889+ i = collectVarData (tokens , i , varData );
2890+
2891+ return generateMessageLengthArgs (fields , groups , varData , indent , withName );
2892+ }
2893+
2894+ private boolean isMessageConstLength (final List <Token > tokens )
2895+ {
2896+ final Integer count = (Integer )generateMessageLengthArgs (tokens , "" , false )[1 ];
2897+
2898+ return (count == 0 );
2899+ }
2900+
2901+ private CharSequence generateMessageLengthCallPre17Helper (final List <Token > tokens )
2902+ {
2903+ final StringBuilder sb = new StringBuilder ();
2904+
2905+ final Integer count = (Integer )generateMessageLengthArgs (tokens , "" , false )[1 ];
2906+
2907+ for (int i = 0 ; i < count ; i ++)
2908+ {
2909+ if (i > 0 )
2910+ {
2911+ sb .append (", " );
2912+ }
2913+ new Formatter (sb ).format ("std::get<%1$d>(e)" , i );
2914+ }
2915+
2916+ return sb ;
2917+ }
2918+
2919+ private CharSequence generateMessageLength (
2920+ final List <Token > fields ,
2921+ final List <Token > groups ,
2922+ final List <Token > varData ,
2923+ final String indent )
2924+ {
2925+ final StringBuilder sbEncode = new StringBuilder ();
2926+ final StringBuilder sbSkip = new StringBuilder ();
2927+
2928+ for (int i = 0 , size = groups .size (); i < size ; i ++)
2929+ {
2930+ final Token groupToken = groups .get (i );
2931+
2932+ if (groupToken .signal () != Signal .BEGIN_GROUP )
2933+ {
2934+ throw new IllegalStateException ("tokens must begin with BEGIN_GROUP: token=" + groupToken );
2935+ }
2936+
2937+ final int endSignal = findEndSignal (groups , i , Signal .END_GROUP , groupToken .name ());
2938+ final List <Token > thisGroup = groups .subList (i , endSignal + 1 );
2939+
2940+ final Token numInGroupToken = Generators .findFirst ("numInGroup" , groups , i );
2941+ final long minCount = numInGroupToken .encoding ().applicableMinValue ().longValue ();
2942+ final long maxCount = numInGroupToken .encoding ().applicableMaxValue ().longValue ();
2943+
2944+ final String countName = groupToken .name () +
2945+ (isMessageConstLength (thisGroup ) ? "Length" : "ItemLengths.size()" );
2946+
2947+ final String minCheck = minCount > 0 ? countName + " < " + minCount + " || " : "" ;
2948+ final String maxCheck = countName + " > " + maxCount ;
2949+
2950+ new Formatter (sbEncode ).format ("\n " +
2951+ indent + " length += %1$s::sbeHeaderSize();\n " ,
2952+ formatClassName (groupToken .name ()));
2953+
2954+ if (isMessageConstLength (thisGroup ))
2955+ {
2956+ new Formatter (sbEncode ).format (
2957+ indent + " if (%3$s%4$s)\n " +
2958+ indent + " {\n " +
2959+ indent + " throw std::runtime_error(\" %5$s outside of allowed range [E110]\" );\n " +
2960+ indent + " }\n " +
2961+ indent + " length += %1$sLength * %2$s::sbeBlockLength();\n " ,
2962+ groupToken .name (),
2963+ formatClassName (groupToken .name ()),
2964+ minCheck ,
2965+ maxCheck ,
2966+ countName );
2967+ }
2968+ else
2969+ {
2970+ new Formatter (sbEncode ).format (
2971+ indent + " if (%3$s%4$s)\n " +
2972+ indent + " {\n " +
2973+ indent + " throw std::runtime_error(\" %5$s outside of allowed range [E110]\" );\n " +
2974+ indent + " }\n " +
2975+ indent + " for (const auto& e: %1$sItemLengths)\n " +
2976+ indent + " {\n " +
2977+ indent + " #if __cpluplus >= 201703L\n " +
2978+ indent + " length += std::apply(%2$s::computeLength, e);\n " +
2979+ indent + " #else\n " +
2980+ indent + " length += %2$s::computeLength(%6$s);\n " +
2981+ indent + " #endif\n " +
2982+ indent + " }\n " ,
2983+ groupToken .name (),
2984+ formatClassName (groupToken .name ()),
2985+ minCheck ,
2986+ maxCheck ,
2987+ countName ,
2988+ generateMessageLengthCallPre17Helper (thisGroup ));
2989+ }
2990+
2991+ new Formatter (sbSkip ).format (
2992+ indent + " %2$s().forEach([](%1$s e)" +
2993+ indent + " {\n " +
2994+ indent + " e.skip();\n " +
2995+ indent + " });\n " ,
2996+ formatClassName (groupToken .name ()),
2997+ formatPropertyName (groupToken .name ()),
2998+ groupToken .name ());
2999+
3000+ i = endSignal ;
3001+ }
3002+
3003+ for (int i = 0 , size = varData .size (); i < size ;)
3004+ {
3005+ final Token varDataToken = varData .get (i );
3006+
3007+ if (varDataToken .signal () != Signal .BEGIN_VAR_DATA )
3008+ {
3009+ throw new IllegalStateException ("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken );
3010+ }
3011+
3012+ final String propertyName = toUpperFirstChar (varDataToken .name ());
3013+ final Token lengthToken = Generators .findFirst ("length" , varData , i );
3014+
3015+ new Formatter (sbEncode ).format ("\n " +
3016+ indent + " length += %1$sHeaderLength();\n " +
3017+ indent + " if (%1$sLength > %2$d)\n " +
3018+ indent + " {\n " +
3019+ indent + " throw std::runtime_error(\" %1$sLength too long for length type [E109]\" );\n " +
3020+ indent + " }\n " +
3021+ indent + " length += %1$sLength;\n " ,
3022+ varDataToken .name (),
3023+ lengthToken .encoding ().applicableMaxValue ().longValue ());
3024+
3025+ new Formatter (sbSkip ).format (
3026+ indent + " skip%1$s();\n " ,
3027+ propertyName );
3028+
3029+ i += varDataToken .componentTokenCount ();
3030+ }
3031+
3032+ final StringBuilder sb = new StringBuilder ();
3033+
3034+ new Formatter (sb ).format ("\n " +
3035+ indent + "void skip()\n " +
3036+ indent + "{\n " +
3037+ "%3$s" +
3038+ indent + "}\n \n " +
3039+
3040+ indent + "SBE_NODISCARD static SBE_CONSTEXPR bool isConstLength() SBE_NOEXCEPT\n " +
3041+ indent + "{\n " +
3042+ indent + " return " + ((groups .isEmpty () && varData .isEmpty ()) ? "true" : "false" ) + ";\n " +
3043+ indent + "}\n \n " +
3044+
3045+ indent + "SBE_NODISCARD static SBE_CONSTEXPR_14 size_t computeLength(%1$s)\n " +
3046+ indent + "{\n " +
3047+ "#if defined(__GNUG__) && !defined(__clang__)\n " +
3048+ "#pragma GCC diagnostic push\n " +
3049+ "#pragma GCC diagnostic ignored \" -Wtype-limits\" \n " +
3050+ "#endif\n " +
3051+ indent + " size_t length = sbeBlockLength();\n \n " +
3052+ "%2$s" +
3053+ indent + " return length;\n " +
3054+ "#if defined(__GNUG__) && !defined(__clang__)\n " +
3055+ "#pragma GCC diagnostic pop\n " +
3056+ "#endif\n " +
3057+ indent + "}\n " ,
3058+ generateMessageLengthArgs (fields , groups , varData , indent + INDENT , true )[0 ],
3059+ sbEncode .toString (),
3060+ sbSkip .toString ());
3061+
3062+ return sb ;
3063+ }
27593064}
0 commit comments