format_args.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. //
  2. // Copyright (c) 2022 Alan de Freitas ([email protected])
  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_cv<
  99. typename std::remove_reference<A>::type>::type;
  100. A const& ref = *static_cast<ref_t*>(
  101. const_cast<void*>( a ) );
  102. formatter<ref_t> f;
  103. pctx.advance_to( f.parse(pctx) );
  104. mctx.advance_to( f.measure( ref, mctx, cs ) );
  105. }
  106. template <class A>
  107. void
  108. format_arg::
  109. format_impl(
  110. format_parse_context& pctx,
  111. format_context& fctx,
  112. grammar::lut_chars const& cs,
  113. void const* a )
  114. {
  115. using ref_t = typename std::remove_cv<
  116. typename std::remove_reference<A>::type>::type;
  117. A const& ref = *static_cast<ref_t*>(
  118. const_cast<void*>( a ) );
  119. formatter<ref_t> f;
  120. pctx.advance_to( f.parse(pctx) );
  121. fctx.advance_to( f.format( ref, fctx, cs ) );
  122. }
  123. // We point to formatter<ignore_format> where
  124. // the format_arg variant would store monostate
  125. template <>
  126. struct formatter<ignore_format>
  127. {
  128. public:
  129. char const*
  130. parse(format_parse_context& ctx) const
  131. {
  132. return parse_empty_spec(
  133. ctx.begin(), ctx.end());
  134. }
  135. std::size_t
  136. measure(
  137. ignore_format,
  138. measure_context& ctx,
  139. grammar::lut_chars const&) const
  140. {
  141. return ctx.out();
  142. }
  143. char*
  144. format(
  145. ignore_format,
  146. format_context& ctx,
  147. grammar::lut_chars const&) const
  148. {
  149. return ctx.out();
  150. }
  151. // We ignore the modifiers in all replacements
  152. // for now
  153. static
  154. char const*
  155. parse_empty_spec(
  156. char const* it,
  157. char const* end)
  158. {
  159. // [it, end] -> "} suffix"
  160. BOOST_ASSERT(it != end);
  161. ignore_unused(end);
  162. // Should be always empty/valid as an
  163. // implementation detail
  164. BOOST_ASSERT(*it == '}');
  165. /*
  166. if (*it != '}')
  167. urls::detail::throw_invalid_argument();
  168. */
  169. return it;
  170. }
  171. };
  172. inline
  173. std::size_t
  174. measure_one(
  175. char c,
  176. grammar::lut_chars const& unreserved)
  177. {
  178. // '%' must be reserved
  179. BOOST_ASSERT(! unreserved('%'));
  180. return 1 + !unreserved(c) * 2;
  181. }
  182. inline
  183. void
  184. encode_one(
  185. char*& out,
  186. char c,
  187. grammar::lut_chars const& unreserved)
  188. {
  189. // '%' must be reserved
  190. BOOST_ASSERT(! unreserved('%'));
  191. if(unreserved(c))
  192. {
  193. *out++ = c;
  194. return;
  195. }
  196. *out++ = '%';
  197. *out++ = urls::detail::hexdigs[0][c>>4];
  198. *out++ = urls::detail::hexdigs[0][c&0xf];
  199. }
  200. // get an unsigned value from format_args
  201. BOOST_URL_DECL
  202. void
  203. get_width_from_args(
  204. std::size_t arg_idx,
  205. core::string_view arg_name,
  206. format_args args,
  207. std::size_t& w);
  208. // formatter for string view
  209. template <>
  210. struct formatter<core::string_view>
  211. {
  212. private:
  213. char fill = ' ';
  214. char align = '\0';
  215. std::size_t width = 0;
  216. std::size_t width_idx = std::size_t(-1);
  217. core::string_view width_name;
  218. public:
  219. BOOST_URL_DECL
  220. char const*
  221. parse(format_parse_context& ctx);
  222. BOOST_URL_DECL
  223. std::size_t
  224. measure(
  225. core::string_view str,
  226. measure_context& ctx,
  227. grammar::lut_chars const& cs) const;
  228. BOOST_URL_DECL
  229. char*
  230. format(
  231. core::string_view str,
  232. format_context& ctx,
  233. grammar::lut_chars const& cs) const;
  234. };
  235. // formatter for anything convertible to a
  236. // string view
  237. template <class T>
  238. struct formatter<
  239. T, typename std::enable_if<
  240. std::is_convertible<
  241. T, core::string_view>::value>::type>
  242. {
  243. formatter<core::string_view> impl_;
  244. public:
  245. char const*
  246. parse(format_parse_context& ctx)
  247. {
  248. return impl_.parse(ctx);
  249. }
  250. std::size_t
  251. measure(
  252. core::string_view str,
  253. measure_context& ctx,
  254. grammar::lut_chars const& cs) const
  255. {
  256. return impl_.measure(str, ctx, cs);
  257. }
  258. char*
  259. format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
  260. {
  261. return impl_.format(str, ctx, cs);
  262. }
  263. };
  264. template <>
  265. struct formatter<char>
  266. {
  267. formatter<core::string_view> impl_;
  268. public:
  269. char const*
  270. parse(format_parse_context& ctx)
  271. {
  272. return impl_.parse(ctx);
  273. }
  274. std::size_t
  275. measure(
  276. char c,
  277. measure_context& ctx,
  278. grammar::lut_chars const& cs) const
  279. {
  280. return impl_.measure({&c, 1}, ctx, cs);
  281. }
  282. char*
  283. format(
  284. char c,
  285. format_context& ctx,
  286. grammar::lut_chars const& cs) const
  287. {
  288. return impl_.format({&c, 1}, ctx, cs);
  289. }
  290. };
  291. // formatters for a single integer
  292. class integer_formatter_impl
  293. {
  294. char fill = ' ';
  295. char align = '\0';
  296. char sign = '-';
  297. bool zeros = false;
  298. std::size_t width = 0;
  299. std::size_t width_idx = std::size_t(-1);
  300. core::string_view width_name;
  301. public:
  302. BOOST_URL_DECL
  303. char const*
  304. parse(format_parse_context& ctx);
  305. BOOST_URL_DECL
  306. std::size_t
  307. measure(
  308. unsigned long long int v,
  309. measure_context& ctx,
  310. grammar::lut_chars const& cs) const;
  311. BOOST_URL_DECL
  312. std::size_t
  313. measure(
  314. long long int v,
  315. measure_context& ctx,
  316. grammar::lut_chars const& cs) const;
  317. BOOST_URL_DECL
  318. char*
  319. format(
  320. unsigned long long int v,
  321. format_context& ctx,
  322. grammar::lut_chars const& cs) const;
  323. BOOST_URL_DECL
  324. char*
  325. format(
  326. long long int v,
  327. format_context& ctx,
  328. grammar::lut_chars const& cs) const;
  329. };
  330. template <class T>
  331. struct formatter<
  332. T, typename std::enable_if<
  333. mp11::mp_contains<mp11::mp_list<
  334. short int,
  335. int,
  336. long int,
  337. long long int,
  338. unsigned short int,
  339. unsigned int,
  340. unsigned long int,
  341. unsigned long long int>, T>::value>::type>
  342. {
  343. private:
  344. integer_formatter_impl impl_;
  345. using base_value_type = typename std::conditional<
  346. std::is_unsigned<T>::value,
  347. unsigned long long int,
  348. long long int
  349. >::type;
  350. public:
  351. char const*
  352. parse(format_parse_context& ctx)
  353. {
  354. return impl_.parse(ctx);
  355. }
  356. std::size_t
  357. measure(
  358. T v,
  359. measure_context& ctx,
  360. grammar::lut_chars const& cs) const
  361. {
  362. return impl_.measure(
  363. static_cast<base_value_type>(v), ctx, cs);
  364. }
  365. char*
  366. format(T v, format_context& ctx, grammar::lut_chars const& cs) const
  367. {
  368. return impl_.format(
  369. static_cast<base_value_type>(v), ctx, cs);
  370. }
  371. };
  372. } // detail
  373. } // url
  374. } // boost
  375. #endif