| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- //
- // 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 <boost/mysql/detail/sequence.hpp>
- #ifdef BOOST_MYSQL_HAS_CONCEPTS
- #include <concepts>
- #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<const FormatFn&>(fn)(* std::begin(range), ctx)`
- * should be well formed, with `ctx` begin a `format_context_base&`.
- */
- template <class Range, class FormatFn>
- #if defined(BOOST_MYSQL_HAS_CONCEPTS)
- requires detail::format_fn_for_range<FormatFn, 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<std::remove_cv_t<U>, N>`.
- * - If `T` is a `std::reference_wrapper<U>` object, or a reference to one,
- * yields `U&`.
- * - Otherwise, yields `std::remove_cvref_t<T>`.
- *
- * Examples:
- *
- * - `sequence_range_t<const std::vector<int>&>` is `std::vector<int>`.
- * - `sequence_range_t<std::reference_wrapper<std::vector<int>>>` is `std::vector<int>&`.
- * - `sequence_range_t<std::reference_wrapper<const std::vector<int>>>` is `const std::vector<int>&`.
- * - `sequence_range_t<int(&)[4]>` is `std::array<int, 4>`.
- */
- template <class T>
- using sequence_range_t =
- #ifdef BOOST_MYSQL_DOXYGEN
- __see_below__
- #else
- typename detail::sequence_range_type<T>::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<Range>`),
- * and the array has `N` elements of type `U`, the output range type is
- * `std::array<std::remove_cv< U >, 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<Range>`, 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<FormatFn>` 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 <class Range, class FormatFn>
- #if defined(BOOST_MYSQL_HAS_CONCEPTS)
- requires std::constructible_from<typename std::decay<FormatFn>::type, FormatFn&&>
- #endif
- format_sequence<sequence_range_t<Range>, typename std::decay<FormatFn>::type> sequence(
- Range&& range,
- FormatFn&& fn,
- constant_string_view glue = ", "
- )
- {
- return {detail::cast_range(std::forward<Range>(range)), std::forward<FormatFn>(fn), glue};
- }
- template <class Range, class FormatFn>
- struct formatter<format_sequence<Range, FormatFn>>
- {
- const char* parse(const char* begin, const char*) { return begin; }
- void format(format_sequence<Range, FormatFn>& value, format_context_base& ctx) const
- {
- detail::do_format_sequence(value.range, value.format_function, value.glue, ctx);
- }
- void format(const format_sequence<Range, FormatFn>& value, format_context_base& ctx) const
- {
- detail::do_format_sequence(value.range, value.format_function, value.glue, ctx);
- }
- };
- } // namespace mysql
- } // namespace boost
- #endif
|