Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:58:24

0001 //
0002 // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_IMPL_FORMAT_SQL_HPP
0009 #define BOOST_MYSQL_IMPL_FORMAT_SQL_HPP
0010 
0011 #pragma once
0012 
0013 #include <boost/mysql/format_sql.hpp>
0014 
0015 #include <boost/mysql/detail/format_sql.hpp>
0016 
0017 #include <type_traits>
0018 
0019 namespace boost {
0020 namespace mysql {
0021 namespace detail {
0022 
0023 BOOST_MYSQL_DECL
0024 std::pair<bool, string_view> parse_range_specifiers(const char* spec_begin, const char* spec_end);
0025 
0026 // To use with arguments with a custom formatter
0027 template <class T>
0028 bool do_format_custom_formatter(
0029     const void* obj,
0030     const char* spec_begin,
0031     const char* spec_end,
0032     format_context_base& ctx
0033 )
0034 {
0035     // T here may be the actual type U or const U
0036     using U = typename std::remove_const<T>::type;
0037 
0038     formatter<U> fmt;
0039 
0040     // Parse the spec
0041     const char* it = fmt.parse(spec_begin, spec_end);
0042     if (it != spec_end)
0043     {
0044         return false;
0045     }
0046 
0047     // Retrieve the object
0048     auto& value = *const_cast<T*>(static_cast<const T*>(obj));
0049 
0050     // Format
0051     fmt.format(value, ctx);
0052 
0053     // Done
0054     return true;
0055 }
0056 
0057 // To use with ranges
0058 template <class T>
0059 bool do_format_range(const void* obj, const char* spec_begin, const char* spec_end, format_context_base& ctx)
0060 {
0061     // Parse specifiers
0062     auto res = detail::parse_range_specifiers(spec_begin, spec_end);
0063     if (!res.first)
0064         return false;
0065     auto spec = runtime(res.second);
0066 
0067     // Retrieve the object. T here may be the actual type U or const U
0068     auto& value = *const_cast<T*>(static_cast<const T*>(obj));
0069 
0070     // Output the sequence
0071     bool is_first = true;
0072     for (auto it = std::begin(value); it != std::end(value); ++it)
0073     {
0074         if (!is_first)
0075             ctx.append_raw(", ");
0076         is_first = false;
0077         ctx.append_value(*it, spec);
0078     }
0079     return true;
0080 }
0081 
0082 // Make formattable_ref formattable
0083 inline formattable_ref_impl make_formattable_ref_custom(
0084     formattable_ref v,
0085     std::true_type  // is format ref
0086 )
0087 {
0088     return access::get_impl(v);
0089 }
0090 
0091 // Make types with custom formatters formattable
0092 template <class T>
0093 formattable_ref_impl make_formattable_ref_custom(
0094     T&& v,
0095     std::false_type  // is format ref
0096 )
0097 {
0098     // If you're getting an error here, it means that you're passing a type
0099     // that is not formattable to a SQL formatting function.
0100     static_assert(
0101         has_specialized_formatter<T>(),
0102         "T is not formattable. Please use a formattable type or specialize formatter<T> to make it "
0103         "formattable"
0104     );
0105 
0106     // Although everything is passed as const void*, do_format_custom_formatter
0107     // can bypass const-ness for non-const values. This helps with non-const ranges (e.g. filter_view)
0108     return {
0109         formattable_ref_impl::type_t::fn_and_ptr,
0110         formattable_ref_impl::
0111             fn_and_ptr{&v, &do_format_custom_formatter<typename std::remove_reference<T>::type>}
0112     };
0113 }
0114 
0115 // Make ranges formattable
0116 template <class T>
0117 formattable_ref_impl make_formattable_ref_range(
0118     T&& v,
0119     std::true_type  // formattable range
0120 )
0121 {
0122     // Although everything is passed as const void*, do_format_range
0123     // can bypass const-ness for non-const ranges (e.g. filter_view)
0124     return {
0125         formattable_ref_impl::type_t::fn_and_ptr,
0126         formattable_ref_impl::fn_and_ptr{&v, &do_format_range<typename std::remove_reference<T>::type>}
0127     };
0128 }
0129 
0130 template <class T>
0131 formattable_ref_impl make_formattable_ref_range(
0132     T&& v,
0133     std::false_type  // formattable range
0134 )
0135 {
0136     return make_formattable_ref_custom(std::forward<T>(v), is_formattable_ref<T>());
0137 }
0138 
0139 // Used for types having is_writable_field<T>
0140 template <class T>
0141 formattable_ref_impl make_formattable_ref_writable(
0142     const T& v,
0143     std::true_type  // is_writable_field
0144 )
0145 {
0146     // Only string types (and not field_views or optionals) support the string specifiers
0147     return {
0148         std::is_convertible<T, string_view>::value ? formattable_ref_impl::type_t::field_with_specs
0149                                                    : formattable_ref_impl::type_t::field,
0150         to_field(v)
0151     };
0152 }
0153 
0154 template <class T>
0155 formattable_ref_impl make_formattable_ref_writable(
0156     T&& v,
0157     std::false_type  // is_writable_field
0158 )
0159 {
0160     return make_formattable_ref_range(std::forward<T>(v), is_formattable_range<T>());
0161 }
0162 
0163 }  // namespace detail
0164 }  // namespace mysql
0165 }  // namespace boost
0166 
0167 template <class T>
0168 boost::mysql::detail::formattable_ref_impl boost::mysql::detail::make_formattable_ref(T&& v)
0169 {
0170     // Hierarchy:
0171     //    1. writable field?
0172     //    2. formattable range?
0173     //    3. custom formatter or formattable_ref?
0174     return make_formattable_ref_writable(std::forward<T>(v), is_writable_field_ref<T>());
0175 }
0176 
0177 template <BOOST_MYSQL_FORMATTABLE... Formattable>
0178 std::string boost::mysql::format_sql(
0179     format_options opts,
0180     constant_string_view format_str,
0181     Formattable&&... args
0182 )
0183 {
0184     std::initializer_list<format_arg> args_il{
0185         {string_view(), std::forward<Formattable>(args)}
0186         ...
0187     };
0188     return format_sql(opts, format_str, args_il);
0189 }
0190 
0191 #endif