@@ -138,6 +138,7 @@ public void generate() throws IOException
138
138
generateGroups (sb , groups , BASE_INDENT );
139
139
generateVarData (sb , className , varData , BASE_INDENT );
140
140
generateDisplay (sb , msgToken .name (), fields , groups , varData , BASE_INDENT + INDENT );
141
+ sb .append (generateMessageLength (fields , groups , varData , BASE_INDENT + INDENT ));
141
142
sb .append ("};\n " );
142
143
sb .append (CppUtil .closingBraces (ir .namespaces ().length )).append ("#endif\n " );
143
144
out .append (sb );
@@ -178,6 +179,7 @@ private void generateGroups(final StringBuilder sb, final List<Token> tokens, fi
178
179
generateVarData (sb , formatClassName (groupName ), varData , indent + INDENT );
179
180
180
181
sb .append (generateGroupDisplay (groupName , fields , groups , varData , indent + INDENT + INDENT ));
182
+ sb .append (generateMessageLength (fields , groups , varData , indent + INDENT + INDENT ));
181
183
182
184
sb .append (indent ).append (" };\n " );
183
185
generateGroupProperty (sb , groupName , groupToken , cppTypeForNumInGroup , indent );
@@ -1034,12 +1036,6 @@ private static CharSequence generateFileHeader(
1034
1036
"# define SBE_DOUBLE_NAN NAN\n " +
1035
1037
"#endif\n \n " +
1036
1038
1037
- "#if __cplusplus >= 201103L\n " +
1038
- "# include <cstdint>\n " +
1039
- "# include <string>\n " +
1040
- "# include <cstring>\n " +
1041
- "#endif\n \n " +
1042
-
1043
1039
"#if __cplusplus >= 201103L\n " +
1044
1040
"# define SBE_CONSTEXPR constexpr\n " +
1045
1041
"# define SBE_NOEXCEPT noexcept\n " +
@@ -1048,22 +1044,33 @@ private static CharSequence generateFileHeader(
1048
1044
"# define SBE_NOEXCEPT\n " +
1049
1045
"#endif\n \n " +
1050
1046
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
+
1051
1053
"#if __cplusplus >= 201703L\n " +
1054
+ "# include <string_view>\n " +
1052
1055
"# define SBE_NODISCARD [[nodiscard]]\n " +
1053
1056
"#else\n " +
1054
1057
"# define SBE_NODISCARD\n " +
1055
1058
"#endif\n \n " +
1056
1059
1057
1060
"#if !defined(__STDC_LIMIT_MACROS)\n " +
1058
1061
"# define __STDC_LIMIT_MACROS 1\n " +
1059
- "#endif\n " +
1062
+ "#endif\n \n " +
1063
+
1060
1064
"#include <cstdint>\n " +
1061
1065
"#include <cstring>\n " +
1066
+ "#include <iomanip>\n " +
1062
1067
"#include <limits>\n " +
1063
- "#include <stdexcept>\n \n " +
1064
1068
"#include <ostream>\n " +
1069
+ "#include <stdexcept>\n " +
1065
1070
"#include <sstream>\n " +
1066
- "#include <iomanip>\n \n " +
1071
+ "#include <string>\n " +
1072
+ "#include <vector>\n " +
1073
+ "\n " +
1067
1074
1068
1075
"#if defined(WIN32) || defined(_WIN32)\n " +
1069
1076
"# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)\n " +
@@ -1934,6 +1941,11 @@ private CharSequence generateMessageFlyweightCode(final String className, final
1934
1941
" return %2$s;\n " +
1935
1942
" }\n \n " +
1936
1943
1944
+ " SBE_NODISCARD static SBE_CONSTEXPR %1$s sbeBlockAndHeaderLength() SBE_NOEXCEPT\n " +
1945
+ " {\n " +
1946
+ " return MessageHeader::encodedLength() + sbeBlockLength();\n " +
1947
+ " }\n \n " +
1948
+
1937
1949
" SBE_NODISCARD static SBE_CONSTEXPR %3$s sbeTemplateId() SBE_NOEXCEPT\n " +
1938
1950
" {\n " +
1939
1951
" return %4$s;\n " +
@@ -2018,6 +2030,14 @@ private CharSequence generateMessageFlyweightCode(final String className, final
2018
2030
" return sbePosition() - m_offset;\n " +
2019
2031
" }\n \n " +
2020
2032
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
+
2021
2041
" SBE_NODISCARD const char * buffer() const SBE_NOEXCEPT\n " +
2022
2042
" {\n " +
2023
2043
" return m_buffer;\n " +
@@ -2756,4 +2776,289 @@ private CharSequence generateEnumDisplay(final List<Token> tokens, final Token e
2756
2776
2757
2777
return sb ;
2758
2778
}
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
+ }
2759
3064
}
0 commit comments