@@ -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 ;
@@ -1634,6 +1636,23 @@ private static CharSequence generateArrayFieldNotPresentCondition(final int sinc
1634
1636
sinceVersion );
1635
1637
}
1636
1638
1639
+ private static CharSequence generateSpanFieldNotPresentCondition (
1640
+ final int sinceVersion , final String indent , final String cppTypeName )
1641
+ {
1642
+ if (0 == sinceVersion )
1643
+ {
1644
+ return "" ;
1645
+ }
1646
+
1647
+ return String .format (
1648
+ indent + " if (m_actingVersion < %1$d)\n " +
1649
+ indent + " {\n " +
1650
+ indent + " return std::span<const %2$s>();\n " +
1651
+ indent + " }\n \n " ,
1652
+ sinceVersion ,
1653
+ cppTypeName );
1654
+ }
1655
+
1637
1656
private static CharSequence generateStringNotPresentCondition (final int sinceVersion , final String indent )
1638
1657
{
1639
1658
if (0 == sinceVersion )
@@ -1703,10 +1722,20 @@ private CharSequence generateFileHeader(
1703
1722
"#if __cplusplus >= 201703L\n " +
1704
1723
"# include <string_view>\n " +
1705
1724
"# define SBE_NODISCARD [[nodiscard]]\n " +
1725
+ "# if !defined(SBE_USE_STRING_VIEW)\n " +
1726
+ "# define SBE_USE_STRING_VIEW 1\n " +
1727
+ "# endif\n " +
1706
1728
"#else\n " +
1707
1729
"# define SBE_NODISCARD\n " +
1708
1730
"#endif\n \n " +
1709
1731
1732
+ "#if __cplusplus >= 202002L\n " +
1733
+ "# include <span>\n " +
1734
+ "# if !defined(SBE_USE_SPAN)\n " +
1735
+ "# define SBE_USE_SPAN 1\n " +
1736
+ "# endif\n " +
1737
+ "#endif\n \n " +
1738
+
1710
1739
"#if !defined(__STDC_LIMIT_MACROS)\n " +
1711
1740
"# define __STDC_LIMIT_MACROS 1\n " +
1712
1741
"#endif\n \n " +
@@ -2258,12 +2287,38 @@ private void generateArrayProperty(
2258
2287
accessOrderListenerCall );
2259
2288
2260
2289
new Formatter (sb ).format ("\n " +
2261
- indent + " %1$s &put%2$s(const char *const src)%7$s\n " +
2290
+ indent + " #ifdef SBE_USE_SPAN\n " +
2291
+ indent + " SBE_NODISCARD std::span<const %5$s> get%1$sAsSpan() const%7$s\n " +
2292
+ indent + " {\n " +
2293
+ "%3$s" +
2294
+ "%6$s" +
2295
+ indent + " const char *buffer = m_buffer + m_offset + %4$d;\n " +
2296
+ indent + " return std::span<const %5$s>(reinterpret_cast<const %5$s*>(buffer), %2$d);\n " +
2297
+ indent + " }\n " +
2298
+ indent + " #endif\n " ,
2299
+ toUpperFirstChar (propertyName ),
2300
+ arrayLength ,
2301
+ generateSpanFieldNotPresentCondition (propertyToken .version (), indent , cppTypeName ),
2302
+ offset ,
2303
+ cppTypeName ,
2304
+ accessOrderListenerCall ,
2305
+ noexceptDeclaration );
2306
+
2307
+ new Formatter (sb ).format ("\n " +
2308
+ indent + " #ifdef SBE_USE_SPAN\n " +
2309
+ indent + " template <std::size_t N>\n " +
2310
+ indent + " %1$s &put%2$s(std::span<const %4$s, N> src)%7$s\n " +
2262
2311
indent + " {\n " +
2312
+ indent + " static_assert(N <= %5$d, \" array too large for put%2$s\" );\n \n " +
2263
2313
"%6$s" +
2264
- indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n " +
2314
+ indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * N);\n " +
2315
+ indent + " for (std::size_t start = N; start < %5$d; ++start)\n " +
2316
+ indent + " {\n " +
2317
+ indent + " m_buffer[m_offset + %3$d + start] = 0;\n " +
2318
+ indent + " }\n \n " +
2265
2319
indent + " return *this;\n " +
2266
- indent + " }\n " ,
2320
+ indent + " }\n " +
2321
+ indent + " #endif\n " ,
2267
2322
containingClassName ,
2268
2323
toUpperFirstChar (propertyName ),
2269
2324
offset ,
@@ -2272,6 +2327,79 @@ private void generateArrayProperty(
2272
2327
accessOrderListenerCall ,
2273
2328
noexceptDeclaration );
2274
2329
2330
+ if (encodingToken .encoding ().primitiveType () != PrimitiveType .CHAR )
2331
+ {
2332
+ new Formatter (sb ).format ("\n " +
2333
+ indent + " #ifdef SBE_USE_SPAN\n " +
2334
+ indent + " %1$s &put%2$s(std::span<const %4$s> src)\n " +
2335
+ indent + " {\n " +
2336
+ indent + " const std::size_t srcLength = src.size();\n " +
2337
+ indent + " if (srcLength > %5$d)\n " +
2338
+ indent + " {\n " +
2339
+ indent + " throw std::runtime_error(\" array too large for put%2$s [E106]\" );\n " +
2340
+ indent + " }\n \n " +
2341
+
2342
+ "%6$s" +
2343
+ indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);\n " +
2344
+ indent + " for (std::size_t start = srcLength; start < %5$d; ++start)\n " +
2345
+ indent + " {\n " +
2346
+ indent + " m_buffer[m_offset + %3$d + start] = 0;\n " +
2347
+ indent + " }\n \n " +
2348
+ indent + " return *this;\n " +
2349
+ indent + " }\n " +
2350
+ indent + " #endif\n " ,
2351
+ containingClassName ,
2352
+ toUpperFirstChar (propertyName ),
2353
+ offset ,
2354
+ cppTypeName ,
2355
+ arrayLength ,
2356
+ accessOrderListenerCall );
2357
+ }
2358
+
2359
+ if (!DISABLE_RAW_ARRAYS )
2360
+ {
2361
+ new Formatter (sb ).format ("\n " +
2362
+ indent + " #ifdef SBE_USE_SPAN\n " +
2363
+ indent + " template <typename T>\n " +
2364
+ // If std::span is available, redirect string literals to the std::span-accepting overload,
2365
+ // where we can do compile-time bounds checking.
2366
+ indent + " %1$s &put%2$s(T&& src) %7$s requires\n " +
2367
+ indent + " (std::is_pointer_v<std::remove_reference_t<T>> &&\n " +
2368
+ indent + " !std::is_array_v<std::remove_reference_t<T>>)\n " +
2369
+ indent + " #else\n " +
2370
+ indent + " %1$s &put%2$s(const char *const src)%7$s\n " +
2371
+ indent + " #endif\n " +
2372
+ indent + " {\n " +
2373
+ "%6$s" +
2374
+ indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n " +
2375
+ indent + " return *this;\n " +
2376
+ indent + " }\n " ,
2377
+ containingClassName ,
2378
+ toUpperFirstChar (propertyName ),
2379
+ offset ,
2380
+ cppTypeName ,
2381
+ arrayLength ,
2382
+ accessOrderListenerCall ,
2383
+ noexceptDeclaration );
2384
+
2385
+ }
2386
+ if (encodingToken .encoding ().primitiveType () == PrimitiveType .CHAR )
2387
+ {
2388
+ // Resolve ambiguity of string literal arguments, which match both
2389
+ // std::span<const char, N> and std::string_view overloads.
2390
+ new Formatter (sb ).format ("\n " +
2391
+ indent + " #ifdef SBE_USE_SPAN\n " +
2392
+ indent + " template <std::size_t N>\n " +
2393
+ indent + " %1$s &put%2$s(const char (&src)[N])%3$s\n " +
2394
+ indent + " {\n " +
2395
+ indent + " return put%2$s(std::span<const char, N>(src));\n " +
2396
+ indent + " }\n " +
2397
+ indent + " #endif\n " ,
2398
+ containingClassName ,
2399
+ toUpperFirstChar (propertyName ),
2400
+ noexceptDeclaration );
2401
+ }
2402
+
2275
2403
if (arrayLength > 1 && arrayLength <= 4 )
2276
2404
{
2277
2405
sb .append ("\n " ).append (indent ).append (" " )
@@ -2332,7 +2460,7 @@ private void generateArrayProperty(
2332
2460
generateJsonEscapedStringGetter (sb , encodingToken , indent , propertyName );
2333
2461
2334
2462
new Formatter (sb ).format ("\n " +
2335
- indent + " #if __cplusplus >= 201703L \n " +
2463
+ indent + " #ifdef SBE_USE_STRING_VIEW \n " +
2336
2464
indent + " SBE_NODISCARD std::string_view get%1$sAsStringView() const%6$s\n " +
2337
2465
indent + " {\n " +
2338
2466
"%4$s" +
@@ -2354,7 +2482,7 @@ private void generateArrayProperty(
2354
2482
noexceptDeclaration );
2355
2483
2356
2484
new Formatter (sb ).format ("\n " +
2357
- indent + " #if __cplusplus >= 201703L \n " +
2485
+ indent + " #ifdef SBE_USE_STRING_VIEW \n " +
2358
2486
indent + " %1$s &put%2$s(const std::string_view str)\n " +
2359
2487
indent + " {\n " +
2360
2488
indent + " const std::size_t srcLength = str.length();\n " +
0 commit comments