@@ -49,6 +49,8 @@ public class CppGenerator implements CodeGenerator
49
49
{
50
50
private static final boolean DISABLE_IMPLICIT_COPYING = Boolean .parseBoolean (
51
51
System .getProperty ("sbe.cpp.disable.implicit.copying" , "false" ));
52
+ private static final boolean DISABLE_RAW_ARRAYS = Boolean .parseBoolean (
53
+ System .getProperty ("sbe.cpp.disable.raw.arrays" , "false" ));
52
54
private static final String BASE_INDENT = "" ;
53
55
private static final String INDENT = " " ;
54
56
private static final String TWO_INDENT = INDENT + INDENT ;
@@ -1612,6 +1614,23 @@ private static CharSequence generateArrayFieldNotPresentCondition(final int sinc
1612
1614
sinceVersion );
1613
1615
}
1614
1616
1617
+ private static CharSequence generateSpanFieldNotPresentCondition (
1618
+ final int sinceVersion , final String indent , final String cppTypeName )
1619
+ {
1620
+ if (0 == sinceVersion )
1621
+ {
1622
+ return "" ;
1623
+ }
1624
+
1625
+ return String .format (
1626
+ indent + " if (m_actingVersion < %1$d)\n " +
1627
+ indent + " {\n " +
1628
+ indent + " return std::span<const $2%s>();\n " +
1629
+ indent + " }\n \n " ,
1630
+ sinceVersion ,
1631
+ cppTypeName );
1632
+ }
1633
+
1615
1634
private static CharSequence generateStringNotPresentCondition (final int sinceVersion , final String indent )
1616
1635
{
1617
1636
if (0 == sinceVersion )
@@ -1681,10 +1700,16 @@ private CharSequence generateFileHeader(
1681
1700
"#if __cplusplus >= 201703L\n " +
1682
1701
"# include <string_view>\n " +
1683
1702
"# define SBE_NODISCARD [[nodiscard]]\n " +
1703
+ "# define SBE_USE_STRING_VIEW 1\n " +
1684
1704
"#else\n " +
1685
1705
"# define SBE_NODISCARD\n " +
1686
1706
"#endif\n \n " +
1687
1707
1708
+ "#if __cplusplus >= 202002L\n " +
1709
+ "# include <span>\n " +
1710
+ "# define SBE_USE_SPAN 1\n " +
1711
+ "#endif\n \n " +
1712
+
1688
1713
"#if !defined(__STDC_LIMIT_MACROS)\n " +
1689
1714
"# define __STDC_LIMIT_MACROS 1\n " +
1690
1715
"#endif\n \n " +
@@ -2236,12 +2261,38 @@ private void generateArrayProperty(
2236
2261
accessOrderListenerCall );
2237
2262
2238
2263
new Formatter (sb ).format ("\n " +
2239
- indent + " %1$s &put%2$s(const char *const src)%7$s\n " +
2264
+ indent + " #ifdef SBE_USE_SPAN\n " +
2265
+ indent + " SBE_NODISCARD std::span<const %5$s> get%1$sAsSpan() const%7$s\n " +
2266
+ indent + " {\n " +
2267
+ "%3$s" +
2268
+ "%6$s" +
2269
+ indent + " const char *buffer = m_buffer + m_offset + %4$d;\n " +
2270
+ indent + " return std::span<const %5$s>(reinterpret_cast<const %5$s*>(buffer), %2$d);\n " +
2271
+ indent + " }\n " +
2272
+ indent + " #endif\n " ,
2273
+ toUpperFirstChar (propertyName ),
2274
+ arrayLength ,
2275
+ generateSpanFieldNotPresentCondition (propertyToken .version (), indent , cppTypeName ),
2276
+ offset ,
2277
+ cppTypeName ,
2278
+ accessOrderListenerCall ,
2279
+ noexceptDeclaration );
2280
+
2281
+ new Formatter (sb ).format ("\n " +
2282
+ indent + " #ifdef SBE_USE_SPAN\n " +
2283
+ indent + " template <std::size_t N>\n " +
2284
+ indent + " %1$s &put%2$s(std::span<const %4$s, N> src)%7$s\n " +
2240
2285
indent + " {\n " +
2286
+ indent + " static_assert(N <= %5$d, \" array too large for put%2$s\" );\n \n " +
2241
2287
"%6$s" +
2242
- indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n " +
2288
+ indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * N);\n " +
2289
+ indent + " for (std::size_t start = N; start < %5$d; ++start)\n " +
2290
+ indent + " {\n " +
2291
+ indent + " m_buffer[m_offset + %3$d + start] = 0;\n " +
2292
+ indent + " }\n \n " +
2243
2293
indent + " return *this;\n " +
2244
- indent + " }\n " ,
2294
+ indent + " }\n " +
2295
+ indent + " #endif\n " ,
2245
2296
containingClassName ,
2246
2297
toUpperFirstChar (propertyName ),
2247
2298
offset ,
@@ -2250,6 +2301,79 @@ private void generateArrayProperty(
2250
2301
accessOrderListenerCall ,
2251
2302
noexceptDeclaration );
2252
2303
2304
+ if (encodingToken .encoding ().primitiveType () != PrimitiveType .CHAR )
2305
+ {
2306
+ new Formatter (sb ).format ("\n " +
2307
+ indent + " #ifdef SBE_USE_SPAN\n " +
2308
+ indent + " %1$s &put%2$s(std::span<const %4$s> src)\n " +
2309
+ indent + " {\n " +
2310
+ indent + " const std::size_t srcLength = src.size();\n " +
2311
+ indent + " if (srcLength > %5$d)\n " +
2312
+ indent + " {\n " +
2313
+ indent + " throw std::runtime_error(\" array too large for put%2$s [E106]\" );\n " +
2314
+ indent + " }\n \n " +
2315
+
2316
+ "%6$s" +
2317
+ indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);\n " +
2318
+ indent + " for (std::size_t start = srcLength; start < %5$d; ++start)\n " +
2319
+ indent + " {\n " +
2320
+ indent + " m_buffer[m_offset + %3$d + start] = 0;\n " +
2321
+ indent + " }\n \n " +
2322
+ indent + " return *this;\n " +
2323
+ indent + " }\n " +
2324
+ indent + " #endif\n " ,
2325
+ containingClassName ,
2326
+ toUpperFirstChar (propertyName ),
2327
+ offset ,
2328
+ cppTypeName ,
2329
+ arrayLength ,
2330
+ accessOrderListenerCall );
2331
+ }
2332
+
2333
+ if (!DISABLE_RAW_ARRAYS )
2334
+ {
2335
+ new Formatter (sb ).format ("\n " +
2336
+ indent + " #ifdef SBE_USE_SPAN\n " +
2337
+ indent + " template <typename T>\n " +
2338
+ // If std::span is available, redirect string literals to the std::span-accepting overload,
2339
+ // where we can do compile-time bounds checking.
2340
+ indent + " %1$s &put%2$s(T&& src) %7$s requires\n " +
2341
+ indent + " (std::is_pointer_v<std::remove_reference_t<T>> &&\n " +
2342
+ indent + " !std::is_array_v<std::remove_reference_t<T>>)\n " +
2343
+ indent + " #else\n " +
2344
+ indent + " %1$s &put%2$s(const char *const src)%7$s\n " +
2345
+ indent + " #endif\n " +
2346
+ indent + " {\n " +
2347
+ "%6$s" +
2348
+ indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n " +
2349
+ indent + " return *this;\n " +
2350
+ indent + " }\n " ,
2351
+ containingClassName ,
2352
+ toUpperFirstChar (propertyName ),
2353
+ offset ,
2354
+ cppTypeName ,
2355
+ arrayLength ,
2356
+ accessOrderListenerCall ,
2357
+ noexceptDeclaration );
2358
+
2359
+ }
2360
+ if (encodingToken .encoding ().primitiveType () == PrimitiveType .CHAR )
2361
+ {
2362
+ // Resolve ambiguity of string literal arguments, which match both
2363
+ // std::span<const char, N> and std::string_view overloads.
2364
+ new Formatter (sb ).format ("\n " +
2365
+ indent + " #ifdef SBE_USE_SPAN\n " +
2366
+ indent + " template <std::size_t N>\n " +
2367
+ indent + " %1$s &put%2$s(const char (&src)[N])%3$s\n " +
2368
+ indent + " {\n " +
2369
+ indent + " return put%2$s(std::span<const char, N>(src));\n " +
2370
+ indent + " }\n " +
2371
+ indent + " #endif\n " ,
2372
+ containingClassName ,
2373
+ toUpperFirstChar (propertyName ),
2374
+ noexceptDeclaration );
2375
+ }
2376
+
2253
2377
if (arrayLength > 1 && arrayLength <= 4 )
2254
2378
{
2255
2379
sb .append ("\n " ).append (indent ).append (" " )
@@ -2310,7 +2434,7 @@ private void generateArrayProperty(
2310
2434
generateJsonEscapedStringGetter (sb , encodingToken , indent , propertyName , accessOrderListenerCall );
2311
2435
2312
2436
new Formatter (sb ).format ("\n " +
2313
- indent + " #if __cplusplus >= 201703L \n " +
2437
+ indent + " #ifdef SBE_USE_STRING_VIEW \n " +
2314
2438
indent + " SBE_NODISCARD std::string_view get%1$sAsStringView() const%6$s\n " +
2315
2439
indent + " {\n " +
2316
2440
"%4$s" +
@@ -2332,7 +2456,7 @@ private void generateArrayProperty(
2332
2456
noexceptDeclaration );
2333
2457
2334
2458
new Formatter (sb ).format ("\n " +
2335
- indent + " #if __cplusplus >= 201703L \n " +
2459
+ indent + " #ifdef SBE_USE_STRING_VIEW \n " +
2336
2460
indent + " %1$s &put%2$s(const std::string_view str)\n " +
2337
2461
indent + " {\n " +
2338
2462
indent + " const std::size_t srcLength = str.length();\n " +
0 commit comments