@@ -49,6 +49,8 @@ public class CppGenerator implements CodeGenerator
4949{
5050 private static final boolean DISABLE_IMPLICIT_COPYING = Boolean .parseBoolean (
5151 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" ));
5254 private static final String BASE_INDENT = "" ;
5355 private static final String INDENT = " " ;
5456 private static final String TWO_INDENT = INDENT + INDENT ;
@@ -1634,6 +1636,23 @@ private static CharSequence generateArrayFieldNotPresentCondition(final int sinc
16341636 sinceVersion );
16351637 }
16361638
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+
16371656 private static CharSequence generateStringNotPresentCondition (final int sinceVersion , final String indent )
16381657 {
16391658 if (0 == sinceVersion )
@@ -1703,10 +1722,20 @@ private CharSequence generateFileHeader(
17031722 "#if __cplusplus >= 201703L\n " +
17041723 "# include <string_view>\n " +
17051724 "# define SBE_NODISCARD [[nodiscard]]\n " +
1725+ "# if !defined(SBE_USE_STRING_VIEW)\n " +
1726+ "# define SBE_USE_STRING_VIEW 1\n " +
1727+ "# endif\n " +
17061728 "#else\n " +
17071729 "# define SBE_NODISCARD\n " +
17081730 "#endif\n \n " +
17091731
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+
17101739 "#if !defined(__STDC_LIMIT_MACROS)\n " +
17111740 "# define __STDC_LIMIT_MACROS 1\n " +
17121741 "#endif\n \n " +
@@ -2258,12 +2287,38 @@ private void generateArrayProperty(
22582287 accessOrderListenerCall );
22592288
22602289 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 " +
22622311 indent + " {\n " +
2312+ indent + " static_assert(N <= %5$d, \" array too large for put%2$s\" );\n \n " +
22632313 "%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 " +
22652319 indent + " return *this;\n " +
2266- indent + " }\n " ,
2320+ indent + " }\n " +
2321+ indent + " #endif\n " ,
22672322 containingClassName ,
22682323 toUpperFirstChar (propertyName ),
22692324 offset ,
@@ -2272,6 +2327,79 @@ private void generateArrayProperty(
22722327 accessOrderListenerCall ,
22732328 noexceptDeclaration );
22742329
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+
22752403 if (arrayLength > 1 && arrayLength <= 4 )
22762404 {
22772405 sb .append ("\n " ).append (indent ).append (" " )
@@ -2332,7 +2460,7 @@ private void generateArrayProperty(
23322460 generateJsonEscapedStringGetter (sb , encodingToken , indent , propertyName );
23332461
23342462 new Formatter (sb ).format ("\n " +
2335- indent + " #if __cplusplus >= 201703L \n " +
2463+ indent + " #ifdef SBE_USE_STRING_VIEW \n " +
23362464 indent + " SBE_NODISCARD std::string_view get%1$sAsStringView() const%6$s\n " +
23372465 indent + " {\n " +
23382466 "%4$s" +
@@ -2354,7 +2482,7 @@ private void generateArrayProperty(
23542482 noexceptDeclaration );
23552483
23562484 new Formatter (sb ).format ("\n " +
2357- indent + " #if __cplusplus >= 201703L \n " +
2485+ indent + " #ifdef SBE_USE_STRING_VIEW \n " +
23582486 indent + " %1$s &put%2$s(const std::string_view str)\n " +
23592487 indent + " {\n " +
23602488 indent + " const std::size_t srcLength = str.length();\n " +
0 commit comments