sequence.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //
  2. // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_SEQUENCE_HPP
  8. #define BOOST_MYSQL_SEQUENCE_HPP
  9. #include <boost/mysql/detail/sequence.hpp>
  10. #ifdef BOOST_MYSQL_HAS_CONCEPTS
  11. #include <concepts>
  12. #endif
  13. namespace boost {
  14. namespace mysql {
  15. /**
  16. * \brief The return type of \ref sequence.
  17. * \details
  18. * Contains a range, a formatter function, and a glue string.
  19. * This type satisfies the `Formattable` concept.
  20. *
  21. * When formatted, \ref format_function is invoked for each element
  22. * in \ref range. The string \ref glue is output raw (as per \ref format_context_base::append_raw)
  23. * between consecutive invocations of the formatter function, generating an effect
  24. * similar to `std::ranges::views::join`.
  25. *
  26. * Don't instantiate this struct directly - use \ref sequence, instead.
  27. *
  28. * \par Type requirements
  29. *
  30. * - Expressions `std::begin(range)` and `std::end(range)` should return an input iterator/sentinel
  31. * pair that can be compared for (in)equality.
  32. * - The expression `static_cast<const FormatFn&>(fn)(* std::begin(range), ctx)`
  33. * should be well formed, with `ctx` begin a `format_context_base&`.
  34. */
  35. template <class Range, class FormatFn>
  36. #if defined(BOOST_MYSQL_HAS_CONCEPTS)
  37. requires detail::format_fn_for_range<FormatFn, Range>
  38. #endif
  39. struct format_sequence
  40. {
  41. /// The range to format.
  42. Range range;
  43. /// The format function to apply to each element in the range.
  44. FormatFn format_function;
  45. /// The string to output between range elements.
  46. constant_string_view glue;
  47. };
  48. /**
  49. * \brief The type of range produced by \ref sequence.
  50. * \details
  51. * This type trait can be used to obtain the range type produced
  52. * by calling \ref sequence. This type is used as the `Range` template
  53. * parameter in \ref format_sequence.
  54. *
  55. * By default, \ref sequence copies its input range, unless
  56. * using `std::ref`. C arrays are copied into `std::array` objects.
  57. * This type trait accounts these transformations.
  58. *
  59. * Formally, given the input range type `T` (which can be a reference with cv-qualifiers):
  60. *
  61. * - If `T` is a C array or a reference to one (as per `std::is_array`),
  62. * and the array elements' type is `U`, yields `std::array<std::remove_cv_t<U>, N>`.
  63. * - If `T` is a `std::reference_wrapper<U>` object, or a reference to one,
  64. * yields `U&`.
  65. * - Otherwise, yields `std::remove_cvref_t<T>`.
  66. *
  67. * Examples:
  68. *
  69. * - `sequence_range_t<const std::vector<int>&>` is `std::vector<int>`.
  70. * - `sequence_range_t<std::reference_wrapper<std::vector<int>>>` is `std::vector<int>&`.
  71. * - `sequence_range_t<std::reference_wrapper<const std::vector<int>>>` is `const std::vector<int>&`.
  72. * - `sequence_range_t<int(&)[4]>` is `std::array<int, 4>`.
  73. */
  74. template <class T>
  75. using sequence_range_t =
  76. #ifdef BOOST_MYSQL_DOXYGEN
  77. __see_below__
  78. #else
  79. typename detail::sequence_range_type<T>::type;
  80. #endif
  81. ;
  82. /**
  83. * \brief Creates an object that, when formatted, applies a per-element function to a range.
  84. * \details
  85. * Objects returned by this function satisfy `Formattable`.
  86. * Formatting such objects invokes `fn` for each element
  87. * in `range`, outputting `glue` between invocations.
  88. * This generates an effect similar to `std::ranges::views::join`.
  89. *
  90. * By default, this function creates an owning object by decay-copying `range` into it.
  91. * C arrays are copied into `std::array` objects. This behavior can be disabled
  92. * by passing `std::reference_wrapper` objects, which are converted to references
  93. * (as `std::make_tuple` does). The \ref sequence_range_t
  94. * type trait accounts for these transformations.
  95. *
  96. * Formally:
  97. *
  98. * - If `Range` is a (possibly cv-qualified) C array reference (as per `std::is_array<Range>`),
  99. * and the array has `N` elements of type `U`, the output range type is
  100. * `std::array<std::remove_cv< U >, N>`, and the range is created as if `std::to_array` was called.
  101. * - If `Range` is a `std::reference_wrapper< U >` object, or a reference to one,
  102. * the output range type is `U&`. This effectively disables copying the input range.
  103. * The resulting object will be a view type, and the caller is responsible for lifetime management.
  104. * - Otherwise, the output range type is `std::remove_cvref_t<Range>`, and it will be
  105. * created by forwarding the passed `range`.
  106. *
  107. * `FormatFn` is always decay-copied into the resulting object.
  108. *
  109. * The glue string is always stored as a view, as it should usually point to a compile-time constant.
  110. *
  111. * \par Type requirements
  112. *
  113. * The resulting range and format function should be compatible, and any required
  114. * copy/move operations should be well defined. Formally:
  115. *
  116. * - `std::decay_t<FormatFn>` should be a formatter function compatible with
  117. * the elements of the output range. See \ref format_sequence for the formal requirements.
  118. * - If `Range` is a `std::reference_wrapper< U >`, or a reference to one,
  119. * no further requirements are placed on `U`.
  120. * - If `Range` is a lvalue reference to a C array, its elements should be copy-constructible
  121. * (as per `std::to_array` requirements).
  122. * - If `Range` is a rvalue reference to a C array, its elements should be move-constructible
  123. * (as per `std::to_array` requirements).
  124. * - Performing a decay-copy of `FormatFn` should be well defined.
  125. *
  126. * \par Exception safety
  127. * Basic guarantee. Propagates any exception thrown when constructing the output
  128. * range and format function.
  129. */
  130. template <class Range, class FormatFn>
  131. #if defined(BOOST_MYSQL_HAS_CONCEPTS)
  132. requires std::constructible_from<typename std::decay<FormatFn>::type, FormatFn&&>
  133. #endif
  134. format_sequence<sequence_range_t<Range>, typename std::decay<FormatFn>::type> sequence(
  135. Range&& range,
  136. FormatFn&& fn,
  137. constant_string_view glue = ", "
  138. )
  139. {
  140. return {detail::cast_range(std::forward<Range>(range)), std::forward<FormatFn>(fn), glue};
  141. }
  142. template <class Range, class FormatFn>
  143. struct formatter<format_sequence<Range, FormatFn>>
  144. {
  145. const char* parse(const char* begin, const char*) { return begin; }
  146. void format(format_sequence<Range, FormatFn>& value, format_context_base& ctx) const
  147. {
  148. detail::do_format_sequence(value.range, value.format_function, value.glue, ctx);
  149. }
  150. void format(const format_sequence<Range, FormatFn>& value, format_context_base& ctx) const
  151. {
  152. detail::do_format_sequence(value.range, value.format_function, value.glue, ctx);
  153. }
  154. };
  155. } // namespace mysql
  156. } // namespace boost
  157. #endif