format_args.hpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. //
  2. // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.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. // Official repository: https://github.com/boostorg/url
  8. //
  9. #ifndef BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
  10. #define BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
  11. namespace boost {
  12. namespace urls {
  13. namespace detail {
  14. template<
  15. class A,
  16. typename std::enable_if<
  17. !std::is_integral<
  18. typename std::decay<A>::type>::value,
  19. int>::type = 0>
  20. std::size_t
  21. get_uvalue( A&& )
  22. {
  23. return 0;
  24. }
  25. template<
  26. class A,
  27. typename std::enable_if<
  28. std::is_integral<
  29. typename std::decay<A>::type>::value &&
  30. std::is_signed<
  31. typename std::decay<A>::type>::value,
  32. int>::type = 0>
  33. std::size_t
  34. get_uvalue( A&& a )
  35. {
  36. if (a > 0)
  37. return static_cast<std::size_t>(a);
  38. return 0;
  39. }
  40. template<
  41. class A,
  42. typename std::enable_if<
  43. std::is_integral<
  44. typename std::decay<A>::type>::value &&
  45. std::is_unsigned<
  46. typename std::decay<A>::type>::value,
  47. int>::type = 0>
  48. std::size_t
  49. get_uvalue( A&& a )
  50. {
  51. return static_cast<std::size_t>(a);
  52. }
  53. BOOST_URL_DECL
  54. std::size_t
  55. get_uvalue( core::string_view a );
  56. BOOST_URL_DECL
  57. std::size_t
  58. get_uvalue( char a );
  59. template<class A>
  60. format_arg::
  61. format_arg( A&& a )
  62. : arg_( &a )
  63. , measure_( &measure_impl<A> )
  64. , fmt_( &format_impl<A> )
  65. , value_( get_uvalue(std::forward<A>(a) ))
  66. , ignore_( std::is_same<A, ignore_format>::value )
  67. {}
  68. template<class A>
  69. format_arg::
  70. format_arg( named_arg<A>&& a )
  71. : arg_( &a.value )
  72. , measure_( &measure_impl<A> )
  73. , fmt_( &format_impl<A> )
  74. , name_( a.name )
  75. , value_( get_uvalue(a.value))
  76. {}
  77. template<class A>
  78. format_arg::
  79. format_arg( core::string_view name, A&& a )
  80. : arg_( &a )
  81. , measure_( &measure_impl<A> )
  82. , fmt_( &format_impl<A> )
  83. , name_( name )
  84. , value_( get_uvalue(a) )
  85. {}
  86. // define the type-erased implementations that
  87. // depends on everything: the context types,
  88. // formatters, and type erased args
  89. template <class A>
  90. void
  91. format_arg::
  92. measure_impl(
  93. format_parse_context& pctx,
  94. measure_context& mctx,
  95. grammar::lut_chars const& cs,
  96. void const* a )
  97. {
  98. using ref_t = typename std::remove_reference<A>::type;
  99. A const& ref = *static_cast<ref_t*>(
  100. const_cast<void*>( a ) );
  101. formatter<ref_t> f;
  102. pctx.advance_to( f.parse(pctx) );
  103. mctx.advance_to( f.measure( ref, mctx, cs ) );
  104. }
  105. template <class A>
  106. void
  107. format_arg::
  108. format_impl(
  109. format_parse_context& pctx,
  110. format_context& fctx,
  111. grammar::lut_chars const& cs,
  112. void const* a )
  113. {
  114. using ref_t = typename std::remove_reference<A>::type;
  115. A const& ref = *static_cast<ref_t*>(
  116. const_cast<void*>( a ) );
  117. formatter<ref_t> f;
  118. pctx.advance_to( f.parse(pctx) );
  119. fctx.advance_to( f.format( ref, fctx, cs ) );
  120. }
  121. // We point to formatter<ignore_format> where
  122. // the format_arg variant would store monostate
  123. template <>
  124. struct formatter<ignore_format>
  125. {
  126. public:
  127. char const*
  128. parse(format_parse_context& ctx) const
  129. {
  130. return parse_empty_spec(
  131. ctx.begin(), ctx.end());
  132. }
  133. std::size_t
  134. measure(
  135. ignore_format,
  136. measure_context& ctx,
  137. grammar::lut_chars const&) const
  138. {
  139. return ctx.out();
  140. }
  141. char*
  142. format(
  143. ignore_format,
  144. format_context& ctx,
  145. grammar::lut_chars const&) const
  146. {
  147. return ctx.out();
  148. }
  149. // We ignore the modifiers in all replacements
  150. // for now
  151. static
  152. char const*
  153. parse_empty_spec(
  154. char const* it,
  155. char const* end)
  156. {
  157. // [it, end] -> "} suffix"
  158. BOOST_ASSERT(it != end);
  159. ignore_unused(end);
  160. // Should be always empty/valid as an
  161. // implementation detail
  162. BOOST_ASSERT(*it == '}');
  163. /*
  164. if (*it != '}')
  165. urls::detail::throw_invalid_argument();
  166. */
  167. return it;
  168. }
  169. };
  170. inline
  171. std::size_t
  172. measure_one(
  173. char c,
  174. grammar::lut_chars const& unreserved)
  175. {
  176. // '%' must be reserved
  177. BOOST_ASSERT(! unreserved('%'));
  178. return 1 + !unreserved(c) * 2;
  179. }
  180. inline
  181. void
  182. encode_one(
  183. char*& out,
  184. char c,
  185. grammar::lut_chars const& unreserved)
  186. {
  187. // '%' must be reserved
  188. BOOST_ASSERT(! unreserved('%'));
  189. if(unreserved(c))
  190. {
  191. *out++ = c;
  192. return;
  193. }
  194. *out++ = '%';
  195. *out++ = urls::detail::hexdigs[0][c>>4];
  196. *out++ = urls::detail::hexdigs[0][c&0xf];
  197. }
  198. // get an unsigned value from format_args
  199. BOOST_URL_DECL
  200. void
  201. get_width_from_args(
  202. std::size_t arg_idx,
  203. core::string_view arg_name,
  204. format_args args,
  205. std::size_t& w);
  206. // formatter for string view
  207. template <>
  208. struct formatter<core::string_view>
  209. {
  210. private:
  211. char fill = ' ';
  212. char align = '\0';
  213. std::size_t width = 0;
  214. std::size_t width_idx = std::size_t(-1);
  215. core::string_view width_name;
  216. public:
  217. BOOST_URL_DECL
  218. char const*
  219. parse(format_parse_context& ctx);
  220. BOOST_URL_DECL
  221. std::size_t
  222. measure(
  223. core::string_view str,
  224. measure_context& ctx,
  225. grammar::lut_chars const& cs) const;
  226. BOOST_URL_DECL
  227. char*
  228. format(
  229. core::string_view str,
  230. format_context& ctx,
  231. grammar::lut_chars const& cs) const;
  232. };
  233. // formatter for anything convertible to a
  234. // string view
  235. template <class T>
  236. struct formatter<
  237. T, typename std::enable_if<
  238. std::is_convertible<
  239. T, core::string_view>::value>::type>
  240. {
  241. formatter<core::string_view> impl_;
  242. public:
  243. char const*
  244. parse(format_parse_context& ctx)
  245. {
  246. return impl_.parse(ctx);
  247. }
  248. std::size_t
  249. measure(
  250. core::string_view str,
  251. measure_context& ctx,
  252. grammar::lut_chars const& cs) const
  253. {
  254. return impl_.measure(str, ctx, cs);
  255. }
  256. char*
  257. format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
  258. {
  259. return impl_.format(str, ctx, cs);
  260. }
  261. };
  262. template <>
  263. struct formatter<char>
  264. {
  265. formatter<core::string_view> impl_;
  266. public:
  267. char const*
  268. parse(format_parse_context& ctx)
  269. {
  270. return impl_.parse(ctx);
  271. }
  272. std::size_t
  273. measure(
  274. char c,
  275. measure_context& ctx,
  276. grammar::lut_chars const& cs) const
  277. {
  278. return impl_.measure({&c, 1}, ctx, cs);
  279. }
  280. char*
  281. format(
  282. char c,
  283. format_context& ctx,
  284. grammar::lut_chars const& cs) const
  285. {
  286. return impl_.format({&c, 1}, ctx, cs);
  287. }
  288. };
  289. // formatters for a single integer
  290. class integer_formatter_impl
  291. {
  292. char fill = ' ';
  293. char align = '\0';
  294. char sign = '-';
  295. bool zeros = false;
  296. std::size_t width = 0;
  297. std::size_t width_idx = std::size_t(-1);
  298. core::string_view width_name;
  299. public:
  300. BOOST_URL_DECL
  301. char const*
  302. parse(format_parse_context& ctx);
  303. BOOST_URL_DECL
  304. std::size_t
  305. measure(
  306. unsigned long long int v,
  307. measure_context& ctx,
  308. grammar::lut_chars const& cs) const;
  309. BOOST_URL_DECL
  310. std::size_t
  311. measure(
  312. long long int v,
  313. measure_context& ctx,
  314. grammar::lut_chars const& cs) const;
  315. BOOST_URL_DECL
  316. char*
  317. format(
  318. unsigned long long int v,
  319. format_context& ctx,
  320. grammar::lut_chars const& cs) const;
  321. BOOST_URL_DECL
  322. char*
  323. format(
  324. long long int v,
  325. format_context& ctx,
  326. grammar::lut_chars const& cs) const;
  327. };
  328. template <class T>
  329. struct formatter<
  330. T, typename std::enable_if<
  331. mp11::mp_contains<mp11::mp_list<
  332. short int,
  333. int,
  334. long int,
  335. long long int,
  336. unsigned short int,
  337. unsigned int,
  338. unsigned long int,
  339. unsigned long long int>, T>::value>::type>
  340. {
  341. private:
  342. integer_formatter_impl impl_;
  343. using base_value_type = typename std::conditional<
  344. std::is_unsigned<T>::value,
  345. unsigned long long int,
  346. long long int
  347. >::type;
  348. public:
  349. char const*
  350. parse(format_parse_context& ctx)
  351. {
  352. return impl_.parse(ctx);
  353. }
  354. std::size_t
  355. measure(
  356. T v,
  357. measure_context& ctx,
  358. grammar::lut_chars const& cs) const
  359. {
  360. return impl_.measure(
  361. static_cast<base_value_type>(v), ctx, cs);
  362. }
  363. char*
  364. format(T v, format_context& ctx, grammar::lut_chars const& cs) const
  365. {
  366. return impl_.format(
  367. static_cast<base_value_type>(v), ctx, cs);
  368. }
  369. };
  370. } // detail
  371. } // url
  372. } // boost
  373. #endif