format_args.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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_FORMAT_ARGS_HPP
  10. #define BOOST_URL_DETAIL_FORMAT_ARGS_HPP
  11. #include <boost/url/detail/encode.hpp>
  12. #include <boost/url/grammar/lut_chars.hpp>
  13. #include <boost/core/ignore_unused.hpp>
  14. #include <array>
  15. // This file implements functions and classes to
  16. // type-erase format arguments.
  17. namespace boost {
  18. namespace urls {
  19. namespace detail {
  20. // state of the format string. It basically keeps
  21. // track of where we are in the format string.
  22. class format_parse_context
  23. {
  24. char const* begin_;
  25. char const* end_;
  26. std::size_t arg_id_ = 0;
  27. public:
  28. constexpr
  29. format_parse_context(
  30. char const* first,
  31. char const* last,
  32. std::size_t arg_id = 0)
  33. : begin_( first )
  34. , end_( last )
  35. , arg_id_( arg_id )
  36. {}
  37. constexpr
  38. format_parse_context(
  39. core::string_view fmt,
  40. std::size_t arg_id = 0)
  41. : format_parse_context(
  42. fmt.data(),
  43. fmt.data() + fmt.size(),
  44. arg_id )
  45. {}
  46. constexpr
  47. char const*
  48. begin() const noexcept
  49. {
  50. return begin_;
  51. }
  52. constexpr
  53. char const*
  54. end() const noexcept
  55. {
  56. return end_;
  57. }
  58. BOOST_CXX14_CONSTEXPR
  59. void
  60. advance_to( char const* it )
  61. {
  62. begin_ = it;
  63. }
  64. std::size_t
  65. next_arg_id()
  66. {
  67. return arg_id_++;
  68. }
  69. };
  70. // State of the destination string
  71. class format_context;
  72. class measure_context;
  73. struct ignore_format {};
  74. template <class T>
  75. struct named_arg
  76. {
  77. core::string_view name;
  78. T const& value;
  79. named_arg(core::string_view n, T const& v)
  80. : name(n)
  81. , value(v)
  82. {}
  83. };
  84. // A type erased format argument
  85. class format_arg
  86. {
  87. void const* arg_;
  88. void (*measure_)(
  89. format_parse_context&,
  90. measure_context&,
  91. grammar::lut_chars const&,
  92. void const* );
  93. void (*fmt_)(
  94. format_parse_context&,
  95. format_context&,
  96. grammar::lut_chars const&,
  97. void const* );
  98. core::string_view name_;
  99. std::size_t value_ = 0;
  100. bool ignore_ = false;
  101. template <class A>
  102. static
  103. void
  104. measure_impl(
  105. format_parse_context& pctx,
  106. measure_context& mctx,
  107. grammar::lut_chars const& cs,
  108. void const* a );
  109. template <class A>
  110. static
  111. void
  112. format_impl(
  113. format_parse_context& pctx,
  114. format_context& fctx,
  115. grammar::lut_chars const& cs,
  116. void const* a );
  117. public:
  118. template<class A>
  119. format_arg( A&& a );
  120. template<class A>
  121. format_arg( named_arg<A>&& a );
  122. template<class A>
  123. format_arg( core::string_view name, A&& a );
  124. format_arg()
  125. : format_arg(ignore_format{})
  126. {}
  127. explicit
  128. operator bool() const noexcept
  129. {
  130. return !ignore_;
  131. }
  132. void
  133. measure(
  134. format_parse_context& pctx,
  135. measure_context& mctx,
  136. grammar::lut_chars const& cs)
  137. {
  138. measure_( pctx, mctx, cs, arg_ );
  139. }
  140. void
  141. format(
  142. format_parse_context& pctx,
  143. format_context& fctx,
  144. grammar::lut_chars const& cs )
  145. {
  146. fmt_( pctx, fctx, cs, arg_ );
  147. }
  148. core::string_view
  149. name() const
  150. {
  151. return name_;
  152. }
  153. std::size_t
  154. value() const
  155. {
  156. return value_;
  157. }
  158. };
  159. // create temp stack storage for type erased args
  160. template< class... Args >
  161. std::array<format_arg, sizeof...(Args)>
  162. make_format_args( Args&&... args )
  163. {
  164. return {{ std::forward<Args>(args)... }};
  165. }
  166. // reference to an array of format_args
  167. class format_args
  168. {
  169. format_arg const* p_{nullptr};
  170. std::size_t n_{0};
  171. public:
  172. format_args(
  173. detail::format_arg const* first,
  174. detail::format_arg const* last ) noexcept
  175. : p_(first)
  176. , n_(static_cast<std::size_t>(last - first))
  177. {}
  178. template < std::size_t N >
  179. format_args( std::array<format_arg, N> const& store ) noexcept
  180. : p_(store.data())
  181. , n_(store.size())
  182. {}
  183. format_arg
  184. get( std::size_t i ) const noexcept
  185. {
  186. if (i < n_)
  187. return p_[i];
  188. return {};
  189. }
  190. format_arg
  191. get( core::string_view name ) const noexcept
  192. {
  193. for (std::size_t i = 0; i < n_; ++i)
  194. {
  195. if (p_[i].name() == name)
  196. return p_[i];
  197. }
  198. return {};
  199. }
  200. };
  201. // define the format_context after format_args
  202. class format_context
  203. {
  204. format_args args_;
  205. char* out_;
  206. public:
  207. format_context(
  208. char* out,
  209. format_args args )
  210. : args_( args )
  211. , out_( out )
  212. {}
  213. format_args
  214. args() const noexcept
  215. {
  216. return args_;
  217. }
  218. format_arg
  219. arg( std::size_t id ) const noexcept
  220. {
  221. return args_.get( id );
  222. }
  223. format_arg
  224. arg( core::string_view name ) const noexcept
  225. {
  226. return args_.get( name );
  227. }
  228. char*
  229. out()
  230. {
  231. return out_;
  232. }
  233. void
  234. advance_to( char* it )
  235. {
  236. out_ = it;
  237. }
  238. };
  239. // define the measure_context after format_args
  240. class measure_context
  241. {
  242. format_args args_;
  243. std::size_t out_;
  244. public:
  245. measure_context(
  246. format_args args )
  247. : measure_context(0, args)
  248. {}
  249. measure_context(
  250. std::size_t out,
  251. format_args args )
  252. : args_( args )
  253. , out_( out )
  254. {}
  255. format_args
  256. args() const noexcept
  257. {
  258. return args_;
  259. }
  260. format_arg
  261. arg( std::size_t id ) const noexcept
  262. {
  263. return args_.get( id );
  264. }
  265. format_arg
  266. arg( core::string_view name ) const noexcept
  267. {
  268. return args_.get( name );
  269. }
  270. std::size_t
  271. out()
  272. {
  273. return out_;
  274. }
  275. void
  276. advance_to( std::size_t n )
  277. {
  278. out_ = n;
  279. }
  280. };
  281. // fwd declare the formatter
  282. template <class T, class = void>
  283. struct formatter;
  284. } // detail
  285. } // url
  286. } // boost
  287. #include <boost/url/detail/impl/format_args.hpp>
  288. #endif