123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- //
- // 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 <boost/mysql/field_view.hpp>
- #include <boost/mysql/string_view.hpp>
- #include <boost/mysql/detail/writable_field_traits.hpp>
- #include <iterator>
- #include <type_traits>
- #include <utility>
- #ifdef BOOST_MYSQL_HAS_CONCEPTS
- #include <concepts>
- #endif
- namespace boost {
- namespace mysql {
- // Forward decls
- template <class T>
- struct formatter;
- class format_context_base;
- class formattable_ref;
- namespace detail {
- class format_state;
- struct formatter_is_unspecialized
- {
- };
- template <class T>
- constexpr bool has_specialized_formatter()
- {
- return !std::is_base_of<formatter_is_unspecialized, formatter<typename std::decay<T>::type>>::value;
- }
- template <class T>
- struct is_writable_field_ref : is_writable_field<typename std::decay<T>::type>
- {
- };
- template <class T>
- struct is_formattable_ref : std::is_same<typename std::decay<T>::type, formattable_ref>
- {
- };
- // Is T suitable for being the element type of a formattable range?
- template <class T>
- constexpr bool is_formattable_range_elm_type()
- {
- return is_writable_field_ref<T>::value || has_specialized_formatter<T>() || is_formattable_ref<T>::value;
- }
- template <class T, class = void>
- 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 <class T>
- 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<decltype(std::begin(std::declval<T&>()) != std::end(std::declval<T&>())), 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<decltype(*std::begin(std::declval<T&>()))>()
- // end of conditions
- >::type> : std::true_type
- {
- };
- template <class T>
- constexpr bool is_formattable_type()
- {
- return is_formattable_range_elm_type<T>() || is_formattable_range<T>::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 <class T>
- concept formattable =
- // This covers basic types and optionals
- is_writable_field_ref<T>::value ||
- // This covers custom types that specialized boost::mysql::formatter
- has_specialized_formatter<T>() ||
- // This covers ranges of formattable types
- is_formattable_range<T>::value ||
- // This covers passing formattable_ref as a format argument
- is_formattable_ref<T>::value;
- template <class FormatFn, class Range>
- 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<bool>;
- 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 <class T>
- formattable_ref_impl make_formattable_ref(T&& v);
- } // namespace detail
- } // namespace mysql
- } // namespace boost
- #endif
|