#ifndef SIMDJSON_GENERIC_STRING_BUILDER_H #ifndef SIMDJSON_CONDITIONAL_INCLUDE #define SIMDJSON_GENERIC_STRING_BUILDER_H #include "simdjson/generic/implementation_simdjson_result_base.h" #endif // SIMDJSON_CONDITIONAL_INCLUDE namespace simdjson { #if SIMDJSON_SUPPORTS_CONCEPTS namespace SIMDJSON_IMPLEMENTATION { namespace builder { class string_builder; }} template struct has_custom_serialization : std::false_type {}; inline constexpr struct serialize_tag { template constexpr void operator()(SIMDJSON_IMPLEMENTATION::builder::string_builder& b, T&& obj) const{ return tag_invoke(*this, b, std::forward(obj)); } } serialize{}; template struct has_custom_serialization(), std::declval())) >> : std::true_type {}; template constexpr bool require_custom_serialization = has_custom_serialization::value; #else struct has_custom_serialization : std::false_type {}; #endif // SIMDJSON_SUPPORTS_CONCEPTS namespace SIMDJSON_IMPLEMENTATION { namespace builder { /** * A builder for JSON strings representing documents. This is a low-level * builder that is not meant to be used directly by end-users. Though it * supports atomic types (Booleans, strings), it does not support composed * types (arrays and objects). * * Ultimately, this class can support kernel-specific optimizations. E.g., * it may make use of SIMD instructions to escape strings faster. */ class string_builder { public: simdjson_inline string_builder(size_t initial_capacity = DEFAULT_INITIAL_CAPACITY); static constexpr size_t DEFAULT_INITIAL_CAPACITY = 1024; /** * Append number (includes Booleans). Booleans are mapped to the strings * false and true. Numbers are converted to strings abiding by the JSON standard. * Floating-point numbers are converted to the shortest string that 'correctly' * represents the number. */ template::value>::type> simdjson_inline void append(number_type v) noexcept; /** * Append character c. */ simdjson_inline void append(char c) noexcept; /** * Append the string 'null'. */ simdjson_inline void append_null() noexcept; /** * Clear the content. */ simdjson_inline void clear() noexcept; /** * Append the std::string_view, after escaping it. * There is no UTF-8 validation. */ simdjson_inline void escape_and_append(std::string_view input) noexcept; /** * Append the std::string_view surrounded by double quotes, after escaping it. * There is no UTF-8 validation. */ simdjson_inline void escape_and_append_with_quotes(std::string_view input) noexcept; #if SIMDJSON_SUPPORTS_CONCEPTS template simdjson_inline void escape_and_append_with_quotes() noexcept; #endif /** * Append the character surrounded by double quotes, after escaping it. * There is no UTF-8 validation. */ simdjson_inline void escape_and_append_with_quotes(char input) noexcept; /** * Append the character surrounded by double quotes, after escaping it. * There is no UTF-8 validation. */ simdjson_inline void escape_and_append_with_quotes(const char* input) noexcept; /** * Append the C string directly, without escaping. * There is no UTF-8 validation. */ simdjson_inline void append_raw(const char *c) noexcept; /** * Append "{" to the buffer. */ simdjson_inline void start_object() noexcept; /** * Append "}" to the buffer. */ simdjson_inline void end_object() noexcept; /** * Append "[" to the buffer. */ simdjson_inline void start_array() noexcept; /** * Append "]" to the buffer. */ simdjson_inline void end_array() noexcept; /** * Append "," to the buffer. */ simdjson_inline void append_comma() noexcept; /** * Append ":" to the buffer. */ simdjson_inline void append_colon() noexcept; /** * Append a key-value pair to the buffer. * The key is escaped and surrounded by double quotes. * The value is escaped if it is a string. */ template simdjson_inline void append_key_value(key_type key, value_type value) noexcept; #if SIMDJSON_SUPPORTS_CONCEPTS template simdjson_inline void append_key_value(value_type value) noexcept; // Support for optional types (std::optional, etc.) template requires(!require_custom_serialization) simdjson_inline void append(const T &opt); template requires(require_custom_serialization) simdjson_inline void append(T &&val); // Support for string-like types template requires(std::is_convertible::value || std::is_same::value ) simdjson_inline void append(const T &value); #endif #if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS // Support for range-based appending (std::ranges::view, etc.) template requires (!std::is_convertible::value && !concepts::optional_type && !require_custom_serialization) simdjson_inline void append(const R &range) noexcept; #endif /** * Append the std::string_view directly, without escaping. * There is no UTF-8 validation. */ simdjson_inline void append_raw(std::string_view input) noexcept; /** * Append len characters from str. * There is no UTF-8 validation. */ simdjson_inline void append_raw(const char *str, size_t len) noexcept; /** * Append exactly N characters from str. The length is a template parameter * so the compiler can fully inline the memcpy with a compile-time-constant * size, avoiding the libc call. Used for compile-time-constant keys in the * reflection struct atom. */ template simdjson_inline void append_raw_n(const char *str) noexcept; #if SIMDJSON_EXCEPTIONS /** * Creates an std::string from the written JSON buffer. * Throws if memory allocation failed * * The result may not be valid UTF-8 if some of your content was not valid UTF-8. * Use validate_unicode() to check the content if needed. */ simdjson_inline operator std::string() const noexcept(false); /** * Creates an std::string_view from the written JSON buffer. * Throws if memory allocation failed. * * The result may not be valid UTF-8 if some of your content was not valid UTF-8. * Use validate_unicode() to check the content if needed. */ simdjson_inline operator std::string_view() const noexcept(false) simdjson_lifetime_bound; #endif /** * Returns a view on the written JSON buffer. Returns an error * if memory allocation failed. * * The result may not be valid UTF-8 if some of your content was not valid UTF-8. * Use validate_unicode() to check the content. */ simdjson_inline simdjson_result view() const noexcept; /** * Appends the null character to the buffer and returns * a pointer to the beginning of the written JSON buffer. * Returns an error if memory allocation failed. * The result is null-terminated. * * The result may not be valid UTF-8 if some of your content was not valid UTF-8. * Use validate_unicode() to check the content. */ simdjson_inline simdjson_result c_str() noexcept; /** * Return true if the content is valid UTF-8. */ simdjson_inline bool validate_unicode() const noexcept; /** * Returns the current size of the written JSON buffer. * If an error occurred, returns 0. */ simdjson_inline size_t size() const noexcept; // ============================================================ // Internal hooks for the position-as-local writer in json_builder.h. // These exist so the reflection atom code can hold buffer pointer, // position and capacity in registers across long write chains rather // than reloading them after every char* write (strict aliasing // forces those reloads when accessed via members of *this). User // code should NOT call these directly. // ============================================================ simdjson_inline char *unsafe_data() noexcept { return buffer.get(); } simdjson_inline size_t unsafe_position() const noexcept { return position; } simdjson_inline size_t unsafe_capacity() const noexcept { return capacity; } simdjson_inline void unsafe_set_position(size_t p) noexcept { position = p; } /// Make capacity available for at least `n` more bytes after the current /// position. Returns false if the allocation failed. simdjson_inline bool unsafe_grow(size_t needed_total_capacity) noexcept { grow_buffer(needed_total_capacity); return is_valid; } simdjson_inline bool unsafe_is_valid() const noexcept { return is_valid; } private: /** * Returns true if we can write at least upcoming_bytes bytes. * The underlying buffer is reallocated if needed. It is designed * to be called before writing to the buffer. It should be fast. */ simdjson_inline bool capacity_check(size_t upcoming_bytes); /** * Grow the buffer to at least desired_capacity bytes. * If the allocation fails, is_valid is set to false. We expect * that this function would not be repeatedly called. */ inline void grow_buffer(size_t desired_capacity); /** * We use this helper function to make sure that is_valid is kept consistent. */ simdjson_inline void set_valid(bool valid) noexcept; std::unique_ptr buffer{}; size_t position{0}; size_t capacity{0}; bool is_valid{true}; }; } } #if !SIMDJSON_STATIC_REFLECTION // fallback implementation until we have static reflection template simdjson_warn_unused simdjson_result to_json(const Z &z, size_t initial_capacity = simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder b(initial_capacity); b.append(z); std::string_view s; auto e = b.view().get(s); if(e) { return e; } return std::string(s); } template simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; auto e = b.view().get(sv); if(e) { return e; } s.assign(sv.data(), sv.size()); return simdjson::SUCCESS; } #endif #if SIMDJSON_SUPPORTS_CONCEPTS #endif // SIMDJSON_SUPPORTS_CONCEPTS } // namespace simdjson #endif // SIMDJSON_GENERIC_STRING_BUILDER_H