Skip to content

Commit 7709a7e

Browse files
author
Egor Seredin
committed
[C++] add computeLength() to compute message length including variable items
1 parent 4d75b0b commit 7709a7e

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed

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

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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);
@@ -1067,6 +1069,7 @@ private static CharSequence generateFileHeader(
10671069
"#include <stdexcept>\n" +
10681070
"#include <sstream>\n" +
10691071
"#include <string>\n" +
1072+
"#include <vector>\n" +
10701073
"\n" +
10711074

10721075
"#if defined(WIN32) || defined(_WIN32)\n" +
@@ -2765,4 +2768,263 @@ private CharSequence generateEnumDisplay(final List<Token> tokens, final Token e
27652768

27662769
return sb;
27672770
}
2771+
2772+
private Object[] generateMessageLengthArgs(
2773+
final List<Token> fields,
2774+
final List<Token> groups,
2775+
final List<Token> varData,
2776+
final String indent,
2777+
final boolean withName)
2778+
{
2779+
final StringBuilder sb = new StringBuilder();
2780+
int count = 0;
2781+
2782+
for (int i = 0, size = groups.size(); i < size; i++)
2783+
{
2784+
final Token groupToken = groups.get(i);
2785+
if (groupToken.signal() != Signal.BEGIN_GROUP)
2786+
{
2787+
throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken);
2788+
}
2789+
2790+
final int endSignal = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name());
2791+
2792+
if (count > 0)
2793+
{
2794+
sb.append(",\n" + indent);
2795+
}
2796+
2797+
final List<Token> thisGroup = groups.subList(i, endSignal + 1);
2798+
2799+
if (isMessageConstLength(thisGroup))
2800+
{
2801+
sb.append("std::size_t");
2802+
if (withName)
2803+
{
2804+
sb.append(" " + groupToken.name() + "Length = 0");
2805+
}
2806+
}
2807+
else
2808+
{
2809+
sb.append("const std::vector<std::tuple<");
2810+
sb.append(generateMessageLengthArgs(thisGroup, indent + INDENT, false)[0]);
2811+
sb.append(">>&");
2812+
2813+
if (withName)
2814+
{
2815+
sb.append(" " + groupToken.name() + "ItemLengths = {}");
2816+
}
2817+
}
2818+
2819+
count += 1;
2820+
2821+
i = endSignal;
2822+
}
2823+
2824+
for (int i = 0, size = varData.size(); i < size;)
2825+
{
2826+
final Token varDataToken = varData.get(i);
2827+
if (varDataToken.signal() != Signal.BEGIN_VAR_DATA)
2828+
{
2829+
throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken);
2830+
}
2831+
2832+
if (count > 0)
2833+
{
2834+
sb.append(",\n" + indent);
2835+
}
2836+
2837+
sb.append("std::size_t");
2838+
if (withName)
2839+
{
2840+
sb.append(" " + varDataToken.name() + "Length = 0");
2841+
}
2842+
2843+
count += 1;
2844+
2845+
i += varDataToken.componentTokenCount();
2846+
}
2847+
2848+
CharSequence result = sb;
2849+
if (count > 1)
2850+
{
2851+
result = "\n" + indent + result;
2852+
}
2853+
2854+
return new Object[]{result, count};
2855+
}
2856+
2857+
private Object[] generateMessageLengthArgs(
2858+
final List<Token> tokens,
2859+
final String indent,
2860+
final boolean withName)
2861+
{
2862+
int i = 0;
2863+
2864+
final Token groupToken = tokens.get(i);
2865+
if (groupToken.signal() != Signal.BEGIN_GROUP)
2866+
{
2867+
throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken);
2868+
}
2869+
2870+
++i;
2871+
final int groupHeaderTokenCount = tokens.get(i).componentTokenCount();
2872+
i += groupHeaderTokenCount;
2873+
2874+
final List<Token> fields = new ArrayList<>();
2875+
i = collectFields(tokens, i, fields);
2876+
2877+
final List<Token> groups = new ArrayList<>();
2878+
i = collectGroups(tokens, i, groups);
2879+
2880+
final List<Token> varData = new ArrayList<>();
2881+
i = collectVarData(tokens, i, varData);
2882+
2883+
return generateMessageLengthArgs(fields, groups, varData, indent, withName);
2884+
}
2885+
2886+
private boolean isMessageConstLength(final List<Token> tokens)
2887+
{
2888+
final Integer count = (Integer)generateMessageLengthArgs(tokens, "", false)[1];
2889+
2890+
return (count == 0);
2891+
}
2892+
2893+
private CharSequence generateMessageLengthCallPre17Helper(final List<Token> tokens)
2894+
{
2895+
final StringBuilder sb = new StringBuilder();
2896+
2897+
final Integer count = (Integer)generateMessageLengthArgs(tokens, "", false)[1];
2898+
2899+
for (int i = 0; i < count; i++)
2900+
{
2901+
if (i > 0)
2902+
{
2903+
sb.append(", ");
2904+
}
2905+
new Formatter(sb).format("std::get<%1$d>(e)", i);
2906+
}
2907+
2908+
return sb;
2909+
}
2910+
2911+
private CharSequence generateMessageLength(
2912+
final List<Token> fields,
2913+
final List<Token> groups,
2914+
final List<Token> varData,
2915+
final String indent)
2916+
{
2917+
final StringBuilder sbEncode = new StringBuilder();
2918+
2919+
for (int i = 0, size = groups.size(); i < size; i++)
2920+
{
2921+
final Token groupToken = groups.get(i);
2922+
2923+
if (groupToken.signal() != Signal.BEGIN_GROUP)
2924+
{
2925+
throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken);
2926+
}
2927+
2928+
final int endSignal = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name());
2929+
final List<Token> thisGroup = groups.subList(i, endSignal + 1);
2930+
2931+
final Token numInGroupToken = Generators.findFirst("numInGroup", groups, i);
2932+
final long minCount = numInGroupToken.encoding().applicableMinValue().longValue();
2933+
final long maxCount = numInGroupToken.encoding().applicableMaxValue().longValue();
2934+
2935+
final String countName = groupToken.name() +
2936+
(isMessageConstLength(thisGroup) ? "Length" : "ItemLengths.size()");
2937+
2938+
final String minCheck = minCount > 0 ? countName + " < " + minCount + " || " : "";
2939+
final String maxCheck = countName + " > " + maxCount;
2940+
2941+
new Formatter(sbEncode).format("\n" +
2942+
indent + " length += %1$s::sbeHeaderSize();\n",
2943+
formatClassName(groupToken.name()));
2944+
2945+
if (isMessageConstLength(thisGroup))
2946+
{
2947+
new Formatter(sbEncode).format(
2948+
indent + " if (%3$s%4$s)\n" +
2949+
indent + " {\n" +
2950+
indent + " throw std::runtime_error(\"%5$s outside of allowed range [E110]\");\n" +
2951+
indent + " }\n" +
2952+
indent + " length += %1$sLength * %2$s::sbeBlockLength();\n",
2953+
groupToken.name(),
2954+
formatClassName(groupToken.name()),
2955+
minCheck,
2956+
maxCheck,
2957+
countName);
2958+
}
2959+
else
2960+
{
2961+
new Formatter(sbEncode).format(
2962+
indent + " if (%3$s%4$s)\n" +
2963+
indent + " {\n" +
2964+
indent + " throw std::runtime_error(\"%5$s outside of allowed range [E110]\");\n" +
2965+
indent + " }\n" +
2966+
indent + " for (const auto& e: %1$sItemLengths)\n" +
2967+
indent + " {\n" +
2968+
indent + " #if __cpluplus >= 201703L\n" +
2969+
indent + " length += std::apply(%2$s::computeLength, e);\n" +
2970+
indent + " #else\n" +
2971+
indent + " length += %2$s::computeLength(%6$s);\n" +
2972+
indent + " #endif\n" +
2973+
indent + " }\n",
2974+
groupToken.name(),
2975+
formatClassName(groupToken.name()),
2976+
minCheck,
2977+
maxCheck,
2978+
countName,
2979+
generateMessageLengthCallPre17Helper(thisGroup));
2980+
}
2981+
2982+
i = endSignal;
2983+
}
2984+
2985+
for (int i = 0, size = varData.size(); i < size;)
2986+
{
2987+
final Token varDataToken = varData.get(i);
2988+
2989+
if (varDataToken.signal() != Signal.BEGIN_VAR_DATA)
2990+
{
2991+
throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken);
2992+
}
2993+
2994+
final Token lengthToken = Generators.findFirst("length", varData, i);
2995+
2996+
new Formatter(sbEncode).format("\n" +
2997+
indent + " length += %1$sHeaderLength();\n" +
2998+
indent + " if (%1$sLength > %2$d)\n" +
2999+
indent + " {\n" +
3000+
indent + " throw std::runtime_error(\"%1$sLength too long for length type [E109]\");\n" +
3001+
indent + " }\n" +
3002+
indent + " length += %1$sLength;\n",
3003+
varDataToken.name(),
3004+
lengthToken.encoding().applicableMaxValue().longValue());
3005+
3006+
i += varDataToken.componentTokenCount();
3007+
}
3008+
3009+
final StringBuilder sb = new StringBuilder();
3010+
3011+
new Formatter(sb).format("\n" +
3012+
indent + "SBE_NODISCARD static SBE_CONSTEXPR_14 size_t computeLength(%1$s)\n" +
3013+
indent + "{\n" +
3014+
"#if defined(__GNUG__) && !defined(__clang__)\n" +
3015+
"#pragma GCC diagnostic push\n" +
3016+
"#pragma GCC diagnostic ignored \"-Wtype-limits\"\n" +
3017+
"#endif\n" +
3018+
indent + " size_t length = sbeBlockLength();\n\n" +
3019+
"%2$s" +
3020+
indent + " return length;\n" +
3021+
"#if defined(__GNUG__) && !defined(__clang__)\n" +
3022+
"#pragma GCC diagnostic pop\n" +
3023+
"#endif\n" +
3024+
indent + "}\n",
3025+
generateMessageLengthArgs(fields, groups, varData, indent + INDENT, true)[0],
3026+
sbEncode.toString());
3027+
3028+
return sb;
3029+
}
27683030
}

0 commit comments

Comments
 (0)