ranges.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. // Formatting library for C++ - range and tuple support
  2. //
  3. // Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
  4. // All rights reserved.
  5. //
  6. // For the license information refer to format.h.
  7. #ifndef FMT_RANGES_H_
  8. #define FMT_RANGES_H_
  9. #include <initializer_list>
  10. #include <tuple>
  11. #include <type_traits>
  12. #include "format.h"
  13. FMT_BEGIN_NAMESPACE
  14. namespace detail {
  15. template <typename Range, typename OutputIt>
  16. auto copy(const Range& range, OutputIt out) -> OutputIt {
  17. for (auto it = range.begin(), end = range.end(); it != end; ++it)
  18. *out++ = *it;
  19. return out;
  20. }
  21. template <typename OutputIt>
  22. auto copy(const char* str, OutputIt out) -> OutputIt {
  23. while (*str) *out++ = *str++;
  24. return out;
  25. }
  26. template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
  27. *out++ = ch;
  28. return out;
  29. }
  30. template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
  31. *out++ = ch;
  32. return out;
  33. }
  34. // Returns true if T has a std::string-like interface, like std::string_view.
  35. template <typename T> class is_std_string_like {
  36. template <typename U>
  37. static auto check(U* p)
  38. -> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
  39. template <typename> static void check(...);
  40. public:
  41. static constexpr const bool value =
  42. is_string<T>::value ||
  43. std::is_convertible<T, std_string_view<char>>::value ||
  44. !std::is_void<decltype(check<T>(nullptr))>::value;
  45. };
  46. template <typename Char>
  47. struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
  48. template <typename T> class is_map {
  49. template <typename U> static auto check(U*) -> typename U::mapped_type;
  50. template <typename> static void check(...);
  51. public:
  52. #ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED!
  53. static constexpr const bool value = false;
  54. #else
  55. static constexpr const bool value =
  56. !std::is_void<decltype(check<T>(nullptr))>::value;
  57. #endif
  58. };
  59. template <typename T> class is_set {
  60. template <typename U> static auto check(U*) -> typename U::key_type;
  61. template <typename> static void check(...);
  62. public:
  63. #ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED!
  64. static constexpr const bool value = false;
  65. #else
  66. static constexpr const bool value =
  67. !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
  68. #endif
  69. };
  70. template <typename... Ts> struct conditional_helper {};
  71. template <typename T, typename _ = void> struct is_range_ : std::false_type {};
  72. #if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
  73. # define FMT_DECLTYPE_RETURN(val) \
  74. ->decltype(val) { return val; } \
  75. static_assert( \
  76. true, "") // This makes it so that a semicolon is required after the
  77. // macro, which helps clang-format handle the formatting.
  78. // C array overload
  79. template <typename T, std::size_t N>
  80. auto range_begin(const T (&arr)[N]) -> const T* {
  81. return arr;
  82. }
  83. template <typename T, std::size_t N>
  84. auto range_end(const T (&arr)[N]) -> const T* {
  85. return arr + N;
  86. }
  87. template <typename T, typename Enable = void>
  88. struct has_member_fn_begin_end_t : std::false_type {};
  89. template <typename T>
  90. struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
  91. decltype(std::declval<T>().end())>>
  92. : std::true_type {};
  93. // Member function overload
  94. template <typename T>
  95. auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
  96. template <typename T>
  97. auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
  98. // ADL overload. Only participates in overload resolution if member functions
  99. // are not found.
  100. template <typename T>
  101. auto range_begin(T&& rng)
  102. -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
  103. decltype(begin(static_cast<T&&>(rng)))> {
  104. return begin(static_cast<T&&>(rng));
  105. }
  106. template <typename T>
  107. auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
  108. decltype(end(static_cast<T&&>(rng)))> {
  109. return end(static_cast<T&&>(rng));
  110. }
  111. template <typename T, typename Enable = void>
  112. struct has_const_begin_end : std::false_type {};
  113. template <typename T, typename Enable = void>
  114. struct has_mutable_begin_end : std::false_type {};
  115. template <typename T>
  116. struct has_const_begin_end<
  117. T,
  118. void_t<
  119. decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
  120. decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
  121. : std::true_type {};
  122. template <typename T>
  123. struct has_mutable_begin_end<
  124. T, void_t<decltype(detail::range_begin(std::declval<T>())),
  125. decltype(detail::range_end(std::declval<T>())),
  126. // the extra int here is because older versions of MSVC don't
  127. // SFINAE properly unless there are distinct types
  128. int>> : std::true_type {};
  129. template <typename T>
  130. struct is_range_<T, void>
  131. : std::integral_constant<bool, (has_const_begin_end<T>::value ||
  132. has_mutable_begin_end<T>::value)> {};
  133. # undef FMT_DECLTYPE_RETURN
  134. #endif
  135. // tuple_size and tuple_element check.
  136. template <typename T> class is_tuple_like_ {
  137. template <typename U>
  138. static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
  139. template <typename> static void check(...);
  140. public:
  141. static constexpr const bool value =
  142. !std::is_void<decltype(check<T>(nullptr))>::value;
  143. };
  144. // Check for integer_sequence
  145. #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
  146. template <typename T, T... N>
  147. using integer_sequence = std::integer_sequence<T, N...>;
  148. template <size_t... N> using index_sequence = std::index_sequence<N...>;
  149. template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
  150. #else
  151. template <typename T, T... N> struct integer_sequence {
  152. using value_type = T;
  153. static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
  154. };
  155. template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
  156. template <typename T, size_t N, T... Ns>
  157. struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
  158. template <typename T, T... Ns>
  159. struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
  160. template <size_t N>
  161. using make_index_sequence = make_integer_sequence<size_t, N>;
  162. #endif
  163. template <typename T>
  164. using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
  165. template <typename T, typename C, bool = is_tuple_like_<T>::value>
  166. class is_tuple_formattable_ {
  167. public:
  168. static constexpr const bool value = false;
  169. };
  170. template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
  171. template <std::size_t... Is>
  172. static auto check2(index_sequence<Is...>,
  173. integer_sequence<bool, (Is == Is)...>) -> std::true_type;
  174. static auto check2(...) -> std::false_type;
  175. template <std::size_t... Is>
  176. static auto check(index_sequence<Is...>) -> decltype(check2(
  177. index_sequence<Is...>{},
  178. integer_sequence<bool,
  179. (is_formattable<typename std::tuple_element<Is, T>::type,
  180. C>::value)...>{}));
  181. public:
  182. static constexpr const bool value =
  183. decltype(check(tuple_index_sequence<T>{}))::value;
  184. };
  185. template <typename Tuple, typename F, size_t... Is>
  186. FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
  187. using std::get;
  188. // Using a free function get<Is>(Tuple) now.
  189. const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
  190. ignore_unused(unused);
  191. }
  192. template <typename Tuple, typename F>
  193. FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
  194. for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
  195. std::forward<Tuple>(t), std::forward<F>(f));
  196. }
  197. template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
  198. void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
  199. using std::get;
  200. const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
  201. ignore_unused(unused);
  202. }
  203. template <typename Tuple1, typename Tuple2, typename F>
  204. void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
  205. for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
  206. std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
  207. std::forward<F>(f));
  208. }
  209. namespace tuple {
  210. // Workaround a bug in MSVC 2019 (v140).
  211. template <typename Char, typename... T>
  212. using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
  213. using std::get;
  214. template <typename Tuple, typename Char, std::size_t... Is>
  215. auto get_formatters(index_sequence<Is...>)
  216. -> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
  217. } // namespace tuple
  218. #if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
  219. // Older MSVC doesn't get the reference type correctly for arrays.
  220. template <typename R> struct range_reference_type_impl {
  221. using type = decltype(*detail::range_begin(std::declval<R&>()));
  222. };
  223. template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
  224. using type = T&;
  225. };
  226. template <typename T>
  227. using range_reference_type = typename range_reference_type_impl<T>::type;
  228. #else
  229. template <typename Range>
  230. using range_reference_type =
  231. decltype(*detail::range_begin(std::declval<Range&>()));
  232. #endif
  233. // We don't use the Range's value_type for anything, but we do need the Range's
  234. // reference type, with cv-ref stripped.
  235. template <typename Range>
  236. using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
  237. template <typename Formatter>
  238. FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
  239. -> decltype(f.set_debug_format(set)) {
  240. f.set_debug_format(set);
  241. }
  242. template <typename Formatter>
  243. FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
  244. // These are not generic lambdas for compatibility with C++11.
  245. template <typename ParseContext> struct parse_empty_specs {
  246. template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
  247. f.parse(ctx);
  248. detail::maybe_set_debug_format(f, true);
  249. }
  250. ParseContext& ctx;
  251. };
  252. template <typename FormatContext> struct format_tuple_element {
  253. using char_type = typename FormatContext::char_type;
  254. template <typename T>
  255. void operator()(const formatter<T, char_type>& f, const T& v) {
  256. if (i > 0)
  257. ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
  258. ctx.advance_to(f.format(v, ctx));
  259. ++i;
  260. }
  261. int i;
  262. FormatContext& ctx;
  263. basic_string_view<char_type> separator;
  264. };
  265. } // namespace detail
  266. template <typename T> struct is_tuple_like {
  267. static constexpr const bool value =
  268. detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
  269. };
  270. template <typename T, typename C> struct is_tuple_formattable {
  271. static constexpr const bool value =
  272. detail::is_tuple_formattable_<T, C>::value;
  273. };
  274. template <typename Tuple, typename Char>
  275. struct formatter<Tuple, Char,
  276. enable_if_t<fmt::is_tuple_like<Tuple>::value &&
  277. fmt::is_tuple_formattable<Tuple, Char>::value>> {
  278. private:
  279. decltype(detail::tuple::get_formatters<Tuple, Char>(
  280. detail::tuple_index_sequence<Tuple>())) formatters_;
  281. basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
  282. basic_string_view<Char> opening_bracket_ =
  283. detail::string_literal<Char, '('>{};
  284. basic_string_view<Char> closing_bracket_ =
  285. detail::string_literal<Char, ')'>{};
  286. public:
  287. FMT_CONSTEXPR formatter() {}
  288. FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
  289. separator_ = sep;
  290. }
  291. FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
  292. basic_string_view<Char> close) {
  293. opening_bracket_ = open;
  294. closing_bracket_ = close;
  295. }
  296. template <typename ParseContext>
  297. FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  298. auto it = ctx.begin();
  299. if (it != ctx.end() && *it != '}')
  300. FMT_THROW(format_error("invalid format specifier"));
  301. detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
  302. return it;
  303. }
  304. template <typename FormatContext>
  305. auto format(const Tuple& value, FormatContext& ctx) const
  306. -> decltype(ctx.out()) {
  307. ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
  308. detail::for_each2(
  309. formatters_, value,
  310. detail::format_tuple_element<FormatContext>{0, ctx, separator_});
  311. return detail::copy_str<Char>(closing_bracket_, ctx.out());
  312. }
  313. };
  314. template <typename T, typename Char> struct is_range {
  315. static constexpr const bool value =
  316. detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
  317. !std::is_convertible<T, std::basic_string<Char>>::value &&
  318. !std::is_convertible<T, detail::std_string_view<Char>>::value;
  319. };
  320. namespace detail {
  321. template <typename Context> struct range_mapper {
  322. using mapper = arg_mapper<Context>;
  323. template <typename T,
  324. FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
  325. static auto map(T&& value) -> T&& {
  326. return static_cast<T&&>(value);
  327. }
  328. template <typename T,
  329. FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
  330. static auto map(T&& value)
  331. -> decltype(mapper().map(static_cast<T&&>(value))) {
  332. return mapper().map(static_cast<T&&>(value));
  333. }
  334. };
  335. template <typename Char, typename Element>
  336. using range_formatter_type =
  337. formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
  338. std::declval<Element>()))>,
  339. Char>;
  340. template <typename R>
  341. using maybe_const_range =
  342. conditional_t<has_const_begin_end<R>::value, const R, R>;
  343. // Workaround a bug in MSVC 2015 and earlier.
  344. #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
  345. template <typename R, typename Char>
  346. struct is_formattable_delayed
  347. : is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
  348. #endif
  349. } // namespace detail
  350. template <typename...> struct conjunction : std::true_type {};
  351. template <typename P> struct conjunction<P> : P {};
  352. template <typename P1, typename... Pn>
  353. struct conjunction<P1, Pn...>
  354. : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
  355. template <typename T, typename Char, typename Enable = void>
  356. struct range_formatter;
  357. template <typename T, typename Char>
  358. struct range_formatter<
  359. T, Char,
  360. enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
  361. is_formattable<T, Char>>::value>> {
  362. private:
  363. detail::range_formatter_type<Char, T> underlying_;
  364. basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
  365. basic_string_view<Char> opening_bracket_ =
  366. detail::string_literal<Char, '['>{};
  367. basic_string_view<Char> closing_bracket_ =
  368. detail::string_literal<Char, ']'>{};
  369. public:
  370. FMT_CONSTEXPR range_formatter() {}
  371. FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
  372. return underlying_;
  373. }
  374. FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
  375. separator_ = sep;
  376. }
  377. FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
  378. basic_string_view<Char> close) {
  379. opening_bracket_ = open;
  380. closing_bracket_ = close;
  381. }
  382. template <typename ParseContext>
  383. FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  384. auto it = ctx.begin();
  385. auto end = ctx.end();
  386. if (it != end && *it == 'n') {
  387. set_brackets({}, {});
  388. ++it;
  389. }
  390. if (it != end && *it != '}') {
  391. if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
  392. ++it;
  393. } else {
  394. detail::maybe_set_debug_format(underlying_, true);
  395. }
  396. ctx.advance_to(it);
  397. return underlying_.parse(ctx);
  398. }
  399. template <typename R, typename FormatContext>
  400. auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
  401. detail::range_mapper<buffer_context<Char>> mapper;
  402. auto out = ctx.out();
  403. out = detail::copy_str<Char>(opening_bracket_, out);
  404. int i = 0;
  405. auto it = detail::range_begin(range);
  406. auto end = detail::range_end(range);
  407. for (; it != end; ++it) {
  408. if (i > 0) out = detail::copy_str<Char>(separator_, out);
  409. ctx.advance_to(out);
  410. auto&& item = *it;
  411. out = underlying_.format(mapper.map(item), ctx);
  412. ++i;
  413. }
  414. out = detail::copy_str<Char>(closing_bracket_, out);
  415. return out;
  416. }
  417. };
  418. enum class range_format { disabled, map, set, sequence, string, debug_string };
  419. namespace detail {
  420. template <typename T>
  421. struct range_format_kind_
  422. : std::integral_constant<range_format,
  423. std::is_same<uncvref_type<T>, T>::value
  424. ? range_format::disabled
  425. : is_map<T>::value ? range_format::map
  426. : is_set<T>::value ? range_format::set
  427. : range_format::sequence> {};
  428. template <range_format K, typename R, typename Char, typename Enable = void>
  429. struct range_default_formatter;
  430. template <range_format K>
  431. using range_format_constant = std::integral_constant<range_format, K>;
  432. template <range_format K, typename R, typename Char>
  433. struct range_default_formatter<
  434. K, R, Char,
  435. enable_if_t<(K == range_format::sequence || K == range_format::map ||
  436. K == range_format::set)>> {
  437. using range_type = detail::maybe_const_range<R>;
  438. range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
  439. FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
  440. FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
  441. underlying_.set_brackets(detail::string_literal<Char, '{'>{},
  442. detail::string_literal<Char, '}'>{});
  443. }
  444. FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
  445. underlying_.set_brackets(detail::string_literal<Char, '{'>{},
  446. detail::string_literal<Char, '}'>{});
  447. underlying_.underlying().set_brackets({}, {});
  448. underlying_.underlying().set_separator(
  449. detail::string_literal<Char, ':', ' '>{});
  450. }
  451. FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
  452. template <typename ParseContext>
  453. FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  454. return underlying_.parse(ctx);
  455. }
  456. template <typename FormatContext>
  457. auto format(range_type& range, FormatContext& ctx) const
  458. -> decltype(ctx.out()) {
  459. return underlying_.format(range, ctx);
  460. }
  461. };
  462. } // namespace detail
  463. template <typename T, typename Char, typename Enable = void>
  464. struct range_format_kind
  465. : conditional_t<
  466. is_range<T, Char>::value, detail::range_format_kind_<T>,
  467. std::integral_constant<range_format, range_format::disabled>> {};
  468. template <typename R, typename Char>
  469. struct formatter<
  470. R, Char,
  471. enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
  472. range_format::disabled>
  473. // Workaround a bug in MSVC 2015 and earlier.
  474. #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
  475. ,
  476. detail::is_formattable_delayed<R, Char>
  477. #endif
  478. >::value>>
  479. : detail::range_default_formatter<range_format_kind<R, Char>::value, R,
  480. Char> {
  481. };
  482. template <typename Char, typename... T> struct tuple_join_view : detail::view {
  483. const std::tuple<T...>& tuple;
  484. basic_string_view<Char> sep;
  485. tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
  486. : tuple(t), sep{s} {}
  487. };
  488. // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
  489. // support in tuple_join. It is disabled by default because of issues with
  490. // the dynamic width and precision.
  491. #ifndef FMT_TUPLE_JOIN_SPECIFIERS
  492. # define FMT_TUPLE_JOIN_SPECIFIERS 0
  493. #endif
  494. template <typename Char, typename... T>
  495. struct formatter<tuple_join_view<Char, T...>, Char> {
  496. template <typename ParseContext>
  497. FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  498. return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
  499. }
  500. template <typename FormatContext>
  501. auto format(const tuple_join_view<Char, T...>& value,
  502. FormatContext& ctx) const -> typename FormatContext::iterator {
  503. return do_format(value, ctx,
  504. std::integral_constant<size_t, sizeof...(T)>());
  505. }
  506. private:
  507. std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
  508. template <typename ParseContext>
  509. FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
  510. std::integral_constant<size_t, 0>)
  511. -> decltype(ctx.begin()) {
  512. return ctx.begin();
  513. }
  514. template <typename ParseContext, size_t N>
  515. FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
  516. std::integral_constant<size_t, N>)
  517. -> decltype(ctx.begin()) {
  518. auto end = ctx.begin();
  519. #if FMT_TUPLE_JOIN_SPECIFIERS
  520. end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
  521. if (N > 1) {
  522. auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
  523. if (end != end1)
  524. FMT_THROW(format_error("incompatible format specs for tuple elements"));
  525. }
  526. #endif
  527. return end;
  528. }
  529. template <typename FormatContext>
  530. auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
  531. std::integral_constant<size_t, 0>) const ->
  532. typename FormatContext::iterator {
  533. return ctx.out();
  534. }
  535. template <typename FormatContext, size_t N>
  536. auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
  537. std::integral_constant<size_t, N>) const ->
  538. typename FormatContext::iterator {
  539. auto out = std::get<sizeof...(T) - N>(formatters_)
  540. .format(std::get<sizeof...(T) - N>(value.tuple), ctx);
  541. if (N > 1) {
  542. out = std::copy(value.sep.begin(), value.sep.end(), out);
  543. ctx.advance_to(out);
  544. return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
  545. }
  546. return out;
  547. }
  548. };
  549. namespace detail {
  550. // Check if T has an interface like a container adaptor (e.g. std::stack,
  551. // std::queue, std::priority_queue).
  552. template <typename T> class is_container_adaptor_like {
  553. template <typename U> static auto check(U* p) -> typename U::container_type;
  554. template <typename> static void check(...);
  555. public:
  556. static constexpr const bool value =
  557. !std::is_void<decltype(check<T>(nullptr))>::value;
  558. };
  559. template <typename Container> struct all {
  560. const Container& c;
  561. auto begin() const -> typename Container::const_iterator { return c.begin(); }
  562. auto end() const -> typename Container::const_iterator { return c.end(); }
  563. };
  564. } // namespace detail
  565. template <typename T, typename Char>
  566. struct formatter<
  567. T, Char,
  568. enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
  569. bool_constant<range_format_kind<T, Char>::value ==
  570. range_format::disabled>>::value>>
  571. : formatter<detail::all<typename T::container_type>, Char> {
  572. using all = detail::all<typename T::container_type>;
  573. template <typename FormatContext>
  574. auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
  575. struct getter : T {
  576. static auto get(const T& t) -> all {
  577. return {t.*(&getter::c)}; // Access c through the derived class.
  578. }
  579. };
  580. return formatter<all>::format(getter::get(t), ctx);
  581. }
  582. };
  583. FMT_BEGIN_EXPORT
  584. /**
  585. \rst
  586. Returns an object that formats `tuple` with elements separated by `sep`.
  587. **Example**::
  588. std::tuple<int, char> t = {1, 'a'};
  589. fmt::print("{}", fmt::join(t, ", "));
  590. // Output: "1, a"
  591. \endrst
  592. */
  593. template <typename... T>
  594. FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
  595. -> tuple_join_view<char, T...> {
  596. return {tuple, sep};
  597. }
  598. template <typename... T>
  599. FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
  600. basic_string_view<wchar_t> sep)
  601. -> tuple_join_view<wchar_t, T...> {
  602. return {tuple, sep};
  603. }
  604. /**
  605. \rst
  606. Returns an object that formats `initializer_list` with elements separated by
  607. `sep`.
  608. **Example**::
  609. fmt::print("{}", fmt::join({1, 2, 3}, ", "));
  610. // Output: "1, 2, 3"
  611. \endrst
  612. */
  613. template <typename T>
  614. auto join(std::initializer_list<T> list, string_view sep)
  615. -> join_view<const T*, const T*> {
  616. return join(std::begin(list), std::end(list), sep);
  617. }
  618. FMT_END_EXPORT
  619. FMT_END_NAMESPACE
  620. #endif // FMT_RANGES_H_