pfr.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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_IMPL_PFR_HPP
  8. #define BOOST_MYSQL_IMPL_PFR_HPP
  9. #pragma once
  10. #include <boost/config.hpp>
  11. // Silence MSVC 14.1 warnings caused by https://github.com/boostorg/pfr/issues/167
  12. #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
  13. #pragma warning(push)
  14. #pragma warning(disable : 4100)
  15. #endif
  16. #include <boost/mysql/pfr.hpp>
  17. #include <boost/mysql/string_view.hpp>
  18. #include <boost/mysql/detail/typing/row_traits.hpp>
  19. #include <boost/pfr/core.hpp>
  20. #include <boost/pfr/core_name.hpp>
  21. #include <boost/pfr/traits.hpp>
  22. #include <type_traits>
  23. #include <utility>
  24. #if BOOST_PFR_CORE_NAME_ENABLED
  25. #include <array>
  26. #include <cstddef>
  27. #include <string_view>
  28. #endif
  29. namespace boost {
  30. namespace mysql {
  31. namespace detail {
  32. // Not all types reflected by PFR are acceptable for us - this function performs this checking
  33. template <class T>
  34. constexpr bool is_pfr_reflectable() noexcept
  35. {
  36. return std::is_class<T>::value && !std::is_const<T>::value
  37. // is_implicitly_reflectable_v returns always false when implicit reflection
  38. // (which requires structured bindings and C++17) is not available
  39. #if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
  40. && pfr::is_implicitly_reflectable_v<T, struct mysql_tag>
  41. #endif
  42. ;
  43. }
  44. template <class T>
  45. using pfr_fields_t = decltype(pfr::structure_to_tuple(std::declval<const T&>()));
  46. #if BOOST_PFR_CORE_NAME_ENABLED
  47. // PFR field names use std::string_view
  48. template <std::size_t N>
  49. constexpr std::array<string_view, N> to_name_table_storage(std::array<std::string_view, N> input) noexcept
  50. {
  51. std::array<string_view, N> res{};
  52. for (std::size_t i = 0; i < N; ++i)
  53. res[i] = input[i];
  54. return res;
  55. }
  56. template <class T>
  57. constexpr inline std::size_t pfr_row_size_v = mp11::mp_size<pfr_fields_t<T>>::value;
  58. template <class T>
  59. constexpr std::array<string_view, pfr_row_size_v<T>> create_pfr_name_table() noexcept
  60. {
  61. // Some MSVC compilers have trouble with pfr::names_as_array<T>() when
  62. // the row type is empty
  63. if constexpr (pfr_row_size_v<T> == 0u)
  64. {
  65. return {};
  66. }
  67. else
  68. {
  69. return to_name_table_storage(pfr::names_as_array<T>());
  70. }
  71. }
  72. template <class T>
  73. constexpr inline auto pfr_names_storage = create_pfr_name_table<T>();
  74. template <class T>
  75. class row_traits<pfr_by_name<T>, false>
  76. {
  77. static_assert(
  78. is_pfr_reflectable<T>(),
  79. "T needs to be a non-const object type that supports PFR reflection"
  80. );
  81. public:
  82. using underlying_row_type = T;
  83. using field_types = pfr_fields_t<T>;
  84. static constexpr name_table_t name_table() noexcept { return pfr_names_storage<T>; }
  85. template <class F>
  86. static void for_each_member(T& to, F&& function)
  87. {
  88. pfr::for_each_field(to, std::forward<F>(function));
  89. }
  90. };
  91. #endif
  92. template <class T>
  93. class row_traits<pfr_by_position<T>, false>
  94. {
  95. static_assert(
  96. is_pfr_reflectable<T>(),
  97. "T needs to be a non-const object type that supports PFR reflection"
  98. );
  99. public:
  100. using underlying_row_type = T;
  101. using field_types = pfr_fields_t<T>;
  102. static constexpr name_table_t name_table() noexcept { return {}; }
  103. template <class F>
  104. static void for_each_member(T& to, F&& function)
  105. {
  106. pfr::for_each_field(to, std::forward<F>(function));
  107. }
  108. };
  109. } // namespace detail
  110. } // namespace mysql
  111. } // namespace boost
  112. #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
  113. #pragma warning(pop)
  114. #endif
  115. #endif