/** * This file is part of the builder API. It is temporarily in the ondemand directory * but we will move it to a builder directory later. */ #ifndef SIMDJSON_GENERIC_BUILDER_H #ifndef SIMDJSON_CONDITIONAL_INCLUDE #define SIMDJSON_GENERIC_STRING_BUILDER_H #include "simdjson/generic/builder/json_string_builder.h" #include "simdjson/concepts.h" #endif // SIMDJSON_CONDITIONAL_INCLUDE #if SIMDJSON_STATIC_REFLECTION #include #include #include #include #include #include #include #include // #include // for std::define_static_string - header not available yet namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace builder { // Concept that checks if a type is a container but not a string (because // strings handling must be handled differently) template concept container_but_not_string = requires(T a) { { a.size() } -> std::convertible_to; { a[std::declval()] }; // check if elements are accessible for the subscript operator } && !std::is_same_v && !std::is_same_v && !std::is_same_v; template requires(container_but_not_string) constexpr void atom(string_builder &b, const T &t) { if (t.size() == 0) { b.append_raw("[]"); return; } b.append('['); atom(b, t[0]); for (size_t i = 1; i < t.size(); ++i) { b.append(','); atom(b, t[i]); } b.append(']'); } template requires(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) constexpr void atom(string_builder &b, const T &t) { b.escape_and_append_with_quotes(t); } template constexpr void atom(string_builder &b, const T &m) { if (m.empty()) { b.append_raw("{}"); return; } b.append('{'); bool first = true; for (const auto& [key, value] : m) { if (!first) { b.append(','); } first = false; // Keys must be convertible to string_view per the concept b.escape_and_append_with_quotes(key); b.append(':'); atom(b, value); } b.append('}'); } template::value && !std::is_same_v>::type> constexpr void atom(string_builder &b, const number_type t) { b.append(t); } template requires(std::is_class_v && !container_but_not_string && !concepts::string_view_keyed_map && !concepts::optional_type && !concepts::smart_pointer && !concepts::appendable_containers && !std::is_same_v && !std::is_same_v && !std::is_same_v && !std::is_same_v) constexpr void atom(string_builder &b, const T &t) { int i = 0; b.append('{'); template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { if (i != 0) b.append(','); constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm))); b.append_raw(key); b.append(':'); atom(b, t.[:dm:]); i++; }; b.append('}'); } // Support for optional types (std::optional, etc.) template constexpr void atom(string_builder &b, const T &opt) { if (opt) { atom(b, opt.value()); } else { b.append_raw("null"); } } // Support for smart pointers (std::unique_ptr, std::shared_ptr, etc.) template constexpr void atom(string_builder &b, const T &ptr) { if (ptr) { atom(b, *ptr); } else { b.append_raw("null"); } } // Support for enums - serialize as string representation using expand approach from P2996R12 template requires(std::is_enum_v) void atom(string_builder &b, const T &e) { #if SIMDJSON_STATIC_REFLECTION constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T)); template for (constexpr auto enum_val : enumerators) { constexpr auto enum_str = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(enum_val))); if (e == [:enum_val:]) { b.append_raw(enum_str); return; } }; // Fallback to integer if enum value not found atom(b, static_cast>(e)); #else // Fallback: serialize as integer if reflection not available atom(b, static_cast>(e)); #endif } // Support for appendable containers that don't have operator[] (sets, etc.) template requires(!container_but_not_string && !concepts::string_view_keyed_map && !concepts::optional_type && !concepts::smart_pointer && !std::is_same_v && !std::is_same_v && !std::is_same_v) constexpr void atom(string_builder &b, const T &container) { if (container.empty()) { b.append_raw("[]"); return; } b.append('['); bool first = true; for (const auto& item : container) { if (!first) { b.append(','); } first = false; atom(b, item); } b.append(']'); } // append functions that delegate to atom functions for primitive types template requires(std::is_arithmetic_v && !std::is_same_v) void append(string_builder &b, const T &t) { atom(b, t); } template requires(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) void append(string_builder &b, const T &t) { atom(b, t); } template void append(string_builder &b, const T &t) { atom(b, t); } template void append(string_builder &b, const T &t) { atom(b, t); } template requires(!container_but_not_string && !concepts::string_view_keyed_map && !concepts::optional_type && !concepts::smart_pointer && !std::is_same_v && !std::is_same_v && !std::is_same_v) void append(string_builder &b, const T &t) { atom(b, t); } template void append(string_builder &b, const T &t) { atom(b, t); } // works for struct template requires(std::is_class_v && !container_but_not_string && !concepts::string_view_keyed_map && !concepts::optional_type && !concepts::smart_pointer && !concepts::appendable_containers && !std::is_same_v && !std::is_same_v && !std::is_same_v && !std::is_same_v) void append(string_builder &b, const Z &z) { int i = 0; b.append('{'); template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^Z, std::meta::access_context::unchecked()))) { if (i != 0) b.append(','); constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm))); b.append_raw(key); b.append(':'); atom(b, z.[:dm:]); i++; }; b.append('}'); } // works for container template requires(container_but_not_string) void append(string_builder &b, const Z &z) { if (z.size() == 0) { b.append_raw("[]"); return; } b.append('['); atom(b, z[0]); for (size_t i = 1; i < z.size(); ++i) { b.append(','); atom(b, z[i]); } b.append(']'); } template simdjson_result to_json_string(const Z &z, size_t initial_capacity = 1024) { string_builder b(initial_capacity); append(b, z); std::string_view s; if(auto e = b.view().get(s); e) { return e; } return std::string(s); } template simdjson_error to_json(const Z &z, std::string &s) { string_builder b; append(b, z); std::string_view view; if(auto e = b.view().get(view); e) { return e; } s.assign(view); return SUCCESS; } template string_builder& operator<<(string_builder& b, const Z& z) { append(b, z); return b; } } // namespace builder } // namespace SIMDJSON_IMPLEMENTATION // Alias the function template to 'to' in the global namespace template simdjson_result to_json(const Z &z, size_t initial_capacity = 1024) { return SIMDJSON_IMPLEMENTATION::builder::to_json_string(z, initial_capacity); } } // namespace simdjson #endif // SIMDJSON_STATIC_REFLECTION #endif