// // Copyright (c) 2019-2024 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_DETAIL_FORMAT_SQL_HPP #define BOOST_MYSQL_DETAIL_FORMAT_SQL_HPP #include #include #include #include #include #include #ifdef BOOST_MYSQL_HAS_CONCEPTS #include #endif namespace boost { namespace mysql { // Forward decls template struct formatter; class format_context_base; class formattable_ref; namespace detail { class format_state; struct formatter_is_unspecialized { }; template constexpr bool has_specialized_formatter() { return !std::is_base_of::type>>::value; } template struct is_writable_field_ref : is_writable_field::type> { }; template struct is_formattable_ref : std::is_same::type, formattable_ref> { }; // Is T suitable for being the element type of a formattable range? template constexpr bool is_formattable_range_elm_type() { return is_writable_field_ref::value || has_specialized_formatter() || is_formattable_ref::value; } template struct is_formattable_range : std::false_type { }; // Note: T might be a reference. // Using T& + reference collapsing gets the right semantics for non-const ranges template struct is_formattable_range< T, typename std::enable_if< // std::begin and std::end can be called on it, and we can compare values std::is_convertible()) != std::end(std::declval())), bool>:: value && // value_type is either a writable field or a type with a specialized formatter. // We don't support sequences of sequences out of the box (no known use case) is_formattable_range_elm_type()))>() // end of conditions >::type> : std::true_type { }; template constexpr bool is_formattable_type() { return is_formattable_range_elm_type() || is_formattable_range::value; } #ifdef BOOST_MYSQL_HAS_CONCEPTS // If you're getting an error referencing this concept, // it means that you are attempting to format a type that doesn't support it. template concept formattable = // This covers basic types and optionals is_writable_field_ref::value || // This covers custom types that specialized boost::mysql::formatter has_specialized_formatter() || // This covers ranges of formattable types is_formattable_range::value || // This covers passing formattable_ref as a format argument is_formattable_ref::value; template concept format_fn_for_range = requires(const FormatFn& format_fn, Range&& range, format_context_base& ctx) { { std::begin(range) != std::end(range) } -> std::convertible_to; format_fn(*std::begin(range), ctx); std::end(range); }; #define BOOST_MYSQL_FORMATTABLE ::boost::mysql::detail::formattable #else #define BOOST_MYSQL_FORMATTABLE class #endif // A type-erased argument passed to format. Built-in types are passed // directly in the struct (as a field_view), instead of by pointer, // to reduce the number of do_format instantiations struct formattable_ref_impl { enum class type_t { field, field_with_specs, fn_and_ptr }; struct fn_and_ptr { const void* obj; bool (*format_fn)(const void*, const char*, const char*, format_context_base&); }; union data_t { field_view fv; fn_and_ptr custom; data_t(field_view fv) noexcept : fv(fv) {} data_t(fn_and_ptr v) noexcept : custom(v) {} }; type_t type; data_t data; }; // Create a type-erased formattable_ref_impl from a formattable value template formattable_ref_impl make_formattable_ref(T&& v); } // namespace detail } // namespace mysql } // namespace boost #endif