Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-09 08:28:04

0001 //
0002 // Copyright (c) 2019-2024 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     formatter<T> fmt;
0036     const char* it = fmt.parse(spec_begin, spec_end);
0037     if (it != spec_end)
0038     {
0039         return false;
0040     }
0041     fmt.format(*static_cast<const T*>(obj), ctx);
0042     return true;
0043 }
0044 
0045 // To use with ranges
0046 template <class T>
0047 bool do_format_range(const void* obj, const char* spec_begin, const char* spec_end, format_context_base& ctx)
0048 {
0049     // Parse specifiers
0050     auto res = detail::parse_range_specifiers(spec_begin, spec_end);
0051     if (!res.first)
0052         return false;
0053     auto spec = runtime(res.second);
0054 
0055     // Retrieve the object. T here may be the actual type U or const U
0056     auto& value = *const_cast<T*>(static_cast<const T*>(obj));
0057 
0058     // Output the sequence
0059     bool is_first = true;
0060     for (auto it = std::begin(value); it != std::end(value); ++it)
0061     {
0062         if (!is_first)
0063             ctx.append_raw(", ");
0064         is_first = false;
0065         ctx.append_value(*it, spec);
0066     }
0067     return true;
0068 }
0069 
0070 // Make formattable_ref formattable
0071 inline formattable_ref_impl make_formattable_ref_custom(
0072     formattable_ref v,
0073     std::true_type  // is format ref
0074 )
0075 {
0076     return access::get_impl(v);
0077 }
0078 
0079 // Make types with custom formatters formattable
0080 template <class T>
0081 formattable_ref_impl make_formattable_ref_custom(
0082     const T& v,
0083     std::false_type  // is format ref
0084 )
0085 {
0086     // If you're getting an error here, it means that you're passing a type
0087     // that is not formattable to a SQL formatting function.
0088     static_assert(
0089         has_specialized_formatter<T>(),
0090         "T is not formattable. Please use a formattable type or specialize formatter<T> to make it "
0091         "formattable"
0092     );
0093     return {
0094         formattable_ref_impl::type_t::fn_and_ptr,
0095         formattable_ref_impl::fn_and_ptr{&v, &do_format_custom_formatter<T>}
0096     };
0097 }
0098 
0099 // Make ranges formattable
0100 template <class T>
0101 formattable_ref_impl make_formattable_ref_range(
0102     T&& v,
0103     std::true_type  // formattable range
0104 )
0105 {
0106     // Although everything is passed as const void*, do_format_range
0107     // can bypass const-ness for non-const ranges (e.g. filter_view)
0108     return {
0109         formattable_ref_impl::type_t::fn_and_ptr,
0110         formattable_ref_impl::fn_and_ptr{&v, &do_format_range<typename std::remove_reference<T>::type>}
0111     };
0112 }
0113 
0114 template <class T>
0115 formattable_ref_impl make_formattable_ref_range(
0116     const T& v,
0117     std::false_type  // formattable range
0118 )
0119 {
0120     return make_formattable_ref_custom(v, is_formattable_ref<T>());
0121 }
0122 
0123 // Used for types having is_writable_field<T>
0124 template <class T>
0125 formattable_ref_impl make_formattable_ref_writable(
0126     const T& v,
0127     std::true_type  // is_writable_field
0128 )
0129 {
0130     // Only string types (and not field_views or optionals) support the string specifiers
0131     return {
0132         std::is_convertible<T, string_view>::value ? formattable_ref_impl::type_t::field_with_specs
0133                                                    : formattable_ref_impl::type_t::field,
0134         to_field(v)
0135     };
0136 }
0137 
0138 template <class T>
0139 formattable_ref_impl make_formattable_ref_writable(
0140     T&& v,
0141     std::false_type  // is_writable_field
0142 )
0143 {
0144     return make_formattable_ref_range(std::forward<T>(v), is_formattable_range<T>());
0145 }
0146 
0147 }  // namespace detail
0148 }  // namespace mysql
0149 }  // namespace boost
0150 
0151 template <class T>
0152 boost::mysql::detail::formattable_ref_impl boost::mysql::detail::make_formattable_ref(T&& v)
0153 {
0154     // Hierarchy:
0155     //    1. writable field?
0156     //    2. formattable range?
0157     //    3. custom formatter or formattable_ref?
0158     return make_formattable_ref_writable(std::forward<T>(v), is_writable_field_ref<T>());
0159 }
0160 
0161 template <BOOST_MYSQL_FORMATTABLE... Formattable>
0162 void boost::mysql::format_sql_to(
0163     format_context_base& ctx,
0164     constant_string_view format_str,
0165     Formattable&&... args
0166 )
0167 {
0168     std::initializer_list<format_arg> args_il{
0169         {string_view(), std::forward<Formattable>(args)}
0170         ...
0171     };
0172     format_sql_to(ctx, format_str, args_il);
0173 }
0174 
0175 template <BOOST_MYSQL_FORMATTABLE... Formattable>
0176 std::string boost::mysql::format_sql(
0177     format_options opts,
0178     constant_string_view format_str,
0179     Formattable&&... args
0180 )
0181 {
0182     std::initializer_list<format_arg> args_il{
0183         {string_view(), std::forward<Formattable>(args)}
0184         ...
0185     };
0186     return format_sql(opts, format_str, args_il);
0187 }
0188 
0189 #endif