// // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_MYSQL_SEQUENCE_HPP #define BOOST_MYSQL_SEQUENCE_HPP #include #ifdef BOOST_MYSQL_HAS_CONCEPTS #include #endif namespace boost { namespace mysql { /** * \brief The return type of \ref sequence. * \details * Contains a range, a formatter function, and a glue string. * This type satisfies the `Formattable` concept. * * When formatted, \ref format_function is invoked for each element * in \ref range. The string \ref glue is output raw (as per \ref format_context_base::append_raw) * between consecutive invocations of the formatter function, generating an effect * similar to `std::ranges::views::join`. * * Don't instantiate this struct directly - use \ref sequence, instead. * * \par Type requirements * * - Expressions `std::begin(range)` and `std::end(range)` should return an input iterator/sentinel * pair that can be compared for (in)equality. * - The expression `static_cast(fn)(* std::begin(range), ctx)` * should be well formed, with `ctx` begin a `format_context_base&`. */ template #if defined(BOOST_MYSQL_HAS_CONCEPTS) requires detail::format_fn_for_range #endif struct format_sequence { /// The range to format. Range range; /// The format function to apply to each element in the range. FormatFn format_function; /// The string to output between range elements. constant_string_view glue; }; /** * \brief The type of range produced by \ref sequence. * \details * This type trait can be used to obtain the range type produced * by calling \ref sequence. This type is used as the `Range` template * parameter in \ref format_sequence. * * By default, \ref sequence copies its input range, unless * using `std::ref`. C arrays are copied into `std::array` objects. * This type trait accounts these transformations. * * Formally, given the input range type `T` (which can be a reference with cv-qualifiers): * * - If `T` is a C array or a reference to one (as per `std::is_array`), * and the array elements' type is `U`, yields `std::array, N>`. * - If `T` is a `std::reference_wrapper` object, or a reference to one, * yields `U&`. * - Otherwise, yields `std::remove_cvref_t`. * * Examples: * * - `sequence_range_t&>` is `std::vector`. * - `sequence_range_t>>` is `std::vector&`. * - `sequence_range_t>>` is `const std::vector&`. * - `sequence_range_t` is `std::array`. */ template using sequence_range_t = #ifdef BOOST_MYSQL_DOXYGEN __see_below__ #else typename detail::sequence_range_type::type; #endif ; /** * \brief Creates an object that, when formatted, applies a per-element function to a range. * \details * Objects returned by this function satisfy `Formattable`. * Formatting such objects invokes `fn` for each element * in `range`, outputting `glue` between invocations. * This generates an effect similar to `std::ranges::views::join`. * * By default, this function creates an owning object by decay-copying `range` into it. * C arrays are copied into `std::array` objects. This behavior can be disabled * by passing `std::reference_wrapper` objects, which are converted to references * (as `std::make_tuple` does). The \ref sequence_range_t * type trait accounts for these transformations. * * Formally: * * - If `Range` is a (possibly cv-qualified) C array reference (as per `std::is_array`), * and the array has `N` elements of type `U`, the output range type is * `std::array, N>`, and the range is created as if `std::to_array` was called. * - If `Range` is a `std::reference_wrapper< U >` object, or a reference to one, * the output range type is `U&`. This effectively disables copying the input range. * The resulting object will be a view type, and the caller is responsible for lifetime management. * - Otherwise, the output range type is `std::remove_cvref_t`, and it will be * created by forwarding the passed `range`. * * `FormatFn` is always decay-copied into the resulting object. * * The glue string is always stored as a view, as it should usually point to a compile-time constant. * * \par Type requirements * * The resulting range and format function should be compatible, and any required * copy/move operations should be well defined. Formally: * * - `std::decay_t` should be a formatter function compatible with * the elements of the output range. See \ref format_sequence for the formal requirements. * - If `Range` is a `std::reference_wrapper< U >`, or a reference to one, * no further requirements are placed on `U`. * - If `Range` is a lvalue reference to a C array, its elements should be copy-constructible * (as per `std::to_array` requirements). * - If `Range` is a rvalue reference to a C array, its elements should be move-constructible * (as per `std::to_array` requirements). * - Performing a decay-copy of `FormatFn` should be well defined. * * \par Exception safety * Basic guarantee. Propagates any exception thrown when constructing the output * range and format function. */ template #if defined(BOOST_MYSQL_HAS_CONCEPTS) requires std::constructible_from::type, FormatFn&&> #endif format_sequence, typename std::decay::type> sequence( Range&& range, FormatFn&& fn, constant_string_view glue = ", " ) { return {detail::cast_range(std::forward(range)), std::forward(fn), glue}; } template struct formatter> { const char* parse(const char* begin, const char*) { return begin; } void format(format_sequence& value, format_context_base& ctx) const { detail::do_format_sequence(value.range, value.format_function, value.glue, ctx); } void format(const format_sequence& value, format_context_base& ctx) const { detail::do_format_sequence(value.range, value.format_function, value.glue, ctx); } }; } // namespace mysql } // namespace boost #endif