|
7 | 7 |
|
8 | 8 | #include <deque> |
9 | 9 | #include <fstream> |
| 10 | +#include <functional> |
10 | 11 | #include <list> |
11 | 12 | #include <memory> |
12 | 13 | #include <vector> |
@@ -54,6 +55,122 @@ namespace ceph { |
54 | 55 | } |
55 | 56 | }; |
56 | 57 |
|
| 58 | + /// Helper to check if a type is a map for our purpose |
| 59 | + /// (based on fmt code) |
| 60 | + template <typename T> class is_map { |
| 61 | + template <typename U> static auto check(U*) -> typename U::mapped_type; |
| 62 | + template <typename> static void check(...); |
| 63 | + public: |
| 64 | + static constexpr const bool value = |
| 65 | + !std::is_void<decltype(check<T>(nullptr))>::value; |
| 66 | + }; |
| 67 | + |
| 68 | + /** |
| 69 | + * with_array_section() |
| 70 | + * Opens an array section and calls 'fn' on each element in the container. |
| 71 | + * Two overloads are provided: |
| 72 | + * 1. for maps, where the function takes a key and a value, and |
| 73 | + * 2. for other types of containers, where the function takes just an |
| 74 | + * element. |
| 75 | + */ |
| 76 | + |
| 77 | + // for maps |
| 78 | + template < |
| 79 | + typename M, //!< a map<K, V> |
| 80 | + typename FN, //!< a callable to be applied to each element |
| 81 | + typename K = std::remove_cvref_t<M>::key_type, |
| 82 | + typename V = std::remove_cvref_t<M>::mapped_type> |
| 83 | + requires( |
| 84 | + is_map<M>::value && ( |
| 85 | + std::is_invocable_v<FN, Formatter&, const K&, const V&, std::string_view> || |
| 86 | + std::is_invocable_v<FN, Formatter&, const K&, const V&>)) |
| 87 | + void with_array_section(std::string_view txt, const M& m, FN&& fn) { |
| 88 | + Formatter::ArraySection as(*this, txt); |
| 89 | + for (const auto& [k, v] : m) { |
| 90 | + if constexpr (std::is_invocable_v<FN, Formatter&, const K&, const V&, std::string_view>) { |
| 91 | + std::invoke(std::forward<FN>(fn), *this, k, v, txt); |
| 92 | + } else { |
| 93 | + std::invoke(std::forward<FN>(fn), *this, k, v); |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + // for other types of containers |
| 99 | + template < |
| 100 | + typename M, |
| 101 | + typename FN, |
| 102 | + typename V = std::remove_cvref_t<M>::value_type> |
| 103 | + requires( |
| 104 | + !is_map<M>::value && ( |
| 105 | + std::is_invocable_r_v<void, FN, Formatter&, const V&, |
| 106 | + std::string_view> || |
| 107 | + std::is_invocable_r_v<void, FN, Formatter&, const V&>)) |
| 108 | + void with_array_section(std::string_view txt, const M& m, FN&& fn) { |
| 109 | + Formatter::ArraySection as(*this, txt); |
| 110 | + for (const auto& v : m) { |
| 111 | + if constexpr (std::is_invocable_v< |
| 112 | + FN, Formatter&, const V&, std::string_view>) { |
| 113 | + std::invoke(std::forward<FN>(fn), *this, v, txt); |
| 114 | + } else { |
| 115 | + std::invoke(std::forward<FN>(fn), *this, v); |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * with_obj_array_section() |
| 122 | + * Opens an array section, then - iterates over the container |
| 123 | + * (which can be a map or a vector) and creates an object section |
| 124 | + * for each element in the container. The provided function 'fn' is |
| 125 | + * called on each element in the container. |
| 126 | + * |
| 127 | + * Two overloads are provided: |
| 128 | + * 1. for maps, where the function takes a key and a value, and |
| 129 | + * 2. for other types of containers, where the function is only |
| 130 | + * handed the object (value) in the container. |
| 131 | + */ |
| 132 | + |
| 133 | + template < |
| 134 | + typename M, //!< a map<K, V> |
| 135 | + typename FN, //!< a callable to be applied to each element |
| 136 | + typename K = std::remove_cvref_t<M>::key_type, |
| 137 | + typename V = std::remove_cvref_t<M>::mapped_type> |
| 138 | + requires( |
| 139 | + is_map<M>::value && ( |
| 140 | + std::is_invocable_v<FN, Formatter&, const K&, const V&, std::string_view> || |
| 141 | + std::is_invocable_v<FN, Formatter&, const K&, const V&>)) |
| 142 | + void with_obj_array_section(std::string_view txt, const M& m, FN&& fn) { |
| 143 | + Formatter::ArraySection as(*this, txt); |
| 144 | + for (const auto& [k, v] : m) { |
| 145 | + Formatter::ObjectSection os(*this, txt); |
| 146 | + if constexpr (std::is_invocable_v<FN, Formatter&, const K&, const V&, std::string_view>) { |
| 147 | + std::invoke(std::forward<FN>(fn), *this, k, v, txt); |
| 148 | + } else { |
| 149 | + std::invoke(std::forward<FN>(fn), *this, k, v); |
| 150 | + } |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + template < |
| 155 | + typename M, //!< a container (which is not a map) of 'V's |
| 156 | + typename FN, |
| 157 | + typename V = std::remove_cvref_t<M>::value_type> |
| 158 | + requires( |
| 159 | + (!is_map<M>::value) && ( |
| 160 | + std::is_invocable_v<FN, Formatter&, const V&, std::string_view> || |
| 161 | + std::is_invocable_v<FN, Formatter&, const V&>)) |
| 162 | + void with_obj_array_section(std::string_view txt, const M& m, FN&& fn) { |
| 163 | + Formatter::ArraySection as(*this, txt); |
| 164 | + for (const auto& v : m) { |
| 165 | + Formatter::ObjectSection os(*this, txt); |
| 166 | + if constexpr (std::is_invocable_v<FN, Formatter&, const V&, std::string_view>) { |
| 167 | + std::invoke(std::forward<FN>(fn), *this, v, txt); |
| 168 | + } else { |
| 169 | + std::invoke(std::forward<FN>(fn), *this, v); |
| 170 | + } |
| 171 | + } |
| 172 | + } |
| 173 | + |
57 | 174 | static Formatter *create(std::string_view type, |
58 | 175 | std::string_view default_type, |
59 | 176 | std::string_view fallback); |
|
0 commit comments