Format.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #pragma once
  27. #include <AK/Array.h>
  28. #include <AK/GenericLexer.h>
  29. #include <AK/StringView.h>
  30. // FIXME: I would really love to merge the format_value and make_type_erased_parameters functions,
  31. // but the compiler creates weird error messages when I do that. Here is a small snippet that
  32. // reproduces the issue: https://godbolt.org/z/o55crs
  33. namespace AK {
  34. class TypeErasedFormatParams;
  35. class FormatParser;
  36. class FormatBuilder;
  37. template<typename T, typename = void>
  38. struct Formatter;
  39. constexpr size_t max_format_arguments = 256;
  40. struct TypeErasedParameter {
  41. enum class Type {
  42. UInt8,
  43. UInt16,
  44. UInt32,
  45. UInt64,
  46. Int8,
  47. Int16,
  48. Int32,
  49. Int64,
  50. Custom
  51. };
  52. template<typename T>
  53. static Type get_type()
  54. {
  55. if (IsSame<T, u8>::value)
  56. return Type::UInt8;
  57. if (IsSame<T, u16>::value)
  58. return Type::UInt16;
  59. if (IsSame<T, u32>::value)
  60. return Type::UInt32;
  61. if (IsSame<T, u64>::value)
  62. return Type::UInt64;
  63. if (IsSame<T, i8>::value)
  64. return Type::Int8;
  65. if (IsSame<T, i16>::value)
  66. return Type::Int16;
  67. if (IsSame<T, i32>::value)
  68. return Type::Int32;
  69. if (IsSame<T, i64>::value)
  70. return Type::Int64;
  71. return Type::Custom;
  72. }
  73. const void* value;
  74. Type type;
  75. void (*formatter)(TypeErasedFormatParams&, FormatBuilder&, FormatParser&, const void* value);
  76. };
  77. class FormatParser : public GenericLexer {
  78. public:
  79. struct FormatSpecifier {
  80. StringView flags;
  81. size_t index;
  82. };
  83. explicit FormatParser(StringView input);
  84. StringView consume_literal();
  85. bool consume_number(size_t& value);
  86. bool consume_specifier(FormatSpecifier& specifier);
  87. bool consume_replacement_field(size_t& index);
  88. };
  89. class FormatBuilder {
  90. public:
  91. enum class Align {
  92. Default,
  93. Left,
  94. Center,
  95. Right,
  96. };
  97. enum class SignMode {
  98. OnlyIfNeeded,
  99. Always,
  100. Reserved,
  101. Default = OnlyIfNeeded,
  102. };
  103. explicit FormatBuilder(StringBuilder& builder)
  104. : m_builder(builder)
  105. {
  106. }
  107. void put_padding(char fill, size_t amount);
  108. void put_literal(StringView value);
  109. void put_string(
  110. StringView value,
  111. Align align = Align::Left,
  112. size_t min_width = 0,
  113. size_t max_width = NumericLimits<size_t>::max(),
  114. char fill = ' ');
  115. void put_u64(
  116. u64 value,
  117. u8 base = 10,
  118. bool prefix = false,
  119. bool upper_case = false,
  120. bool zero_pad = false,
  121. Align align = Align::Right,
  122. size_t min_width = 0,
  123. char fill = ' ',
  124. SignMode sign_mode = SignMode::OnlyIfNeeded,
  125. bool is_negative = false);
  126. void put_i64(
  127. i64 value,
  128. u8 base = 10,
  129. bool prefix = false,
  130. bool upper_case = false,
  131. bool zero_pad = false,
  132. Align align = Align::Right,
  133. size_t min_width = 0,
  134. char fill = ' ',
  135. SignMode sign_mode = SignMode::OnlyIfNeeded);
  136. const StringBuilder& builder() const { return m_builder; }
  137. StringBuilder& builder() { return m_builder; }
  138. private:
  139. StringBuilder& m_builder;
  140. };
  141. class TypeErasedFormatParams {
  142. public:
  143. explicit TypeErasedFormatParams(Span<const TypeErasedParameter> parameters)
  144. : m_parameters(parameters)
  145. {
  146. }
  147. Span<const TypeErasedParameter> parameters() const { return m_parameters; }
  148. size_t take_next_index() { return m_next_index++; }
  149. size_t decode(size_t value, size_t default_value = 0);
  150. private:
  151. Span<const TypeErasedParameter> m_parameters;
  152. size_t m_next_index { 0 };
  153. };
  154. template<typename T>
  155. void __format_value(TypeErasedFormatParams& params, FormatBuilder& builder, FormatParser& parser, const void* value)
  156. {
  157. Formatter<T> formatter;
  158. formatter.parse(params, parser);
  159. formatter.format(params, builder, *static_cast<const T*>(value));
  160. }
  161. template<typename... Parameters>
  162. class VariadicFormatParams : public TypeErasedFormatParams {
  163. public:
  164. static_assert(sizeof...(Parameters) <= max_format_arguments);
  165. explicit VariadicFormatParams(const Parameters&... parameters)
  166. : TypeErasedFormatParams(m_data)
  167. , m_data({ TypeErasedParameter { &parameters, TypeErasedParameter::get_type<Parameters>(), __format_value<Parameters> }... })
  168. {
  169. }
  170. private:
  171. Array<TypeErasedParameter, sizeof...(Parameters)> m_data;
  172. };
  173. // We use the same format for most types for consistency. This is taken directly from std::format.
  174. // Not all valid options do anything yet.
  175. // https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification
  176. struct StandardFormatter {
  177. enum class Mode {
  178. Default,
  179. Binary,
  180. BinaryUppercase,
  181. Decimal,
  182. Octal,
  183. Hexadecimal,
  184. HexadecimalUppercase,
  185. Character,
  186. String,
  187. Pointer,
  188. };
  189. static constexpr size_t value_not_set = NumericLimits<size_t>::max();
  190. static constexpr size_t value_from_next_arg = NumericLimits<size_t>::max() - 1;
  191. static constexpr size_t value_from_arg = NumericLimits<size_t>::max() - max_format_arguments - 2;
  192. FormatBuilder::Align m_align = FormatBuilder::Align::Default;
  193. FormatBuilder::SignMode m_sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
  194. Mode m_mode = Mode::Default;
  195. bool m_alternative_form = false;
  196. char m_fill = ' ';
  197. bool m_zero_pad = false;
  198. size_t m_width = value_not_set;
  199. size_t m_precision = value_not_set;
  200. void parse(TypeErasedFormatParams&, FormatParser&);
  201. };
  202. template<>
  203. struct Formatter<StringView> : StandardFormatter {
  204. Formatter() { }
  205. explicit Formatter(StandardFormatter formatter)
  206. : StandardFormatter(formatter)
  207. {
  208. }
  209. void format(TypeErasedFormatParams&, FormatBuilder&, StringView value);
  210. };
  211. template<>
  212. struct Formatter<const char*> : Formatter<StringView> {
  213. };
  214. template<>
  215. struct Formatter<char*> : Formatter<StringView> {
  216. };
  217. template<size_t Size>
  218. struct Formatter<char[Size]> : Formatter<StringView> {
  219. };
  220. template<>
  221. struct Formatter<String> : Formatter<StringView> {
  222. };
  223. template<>
  224. struct Formatter<FlyString> : Formatter<StringView> {
  225. };
  226. template<typename T>
  227. struct Formatter<T, typename EnableIf<IsIntegral<T>::value>::Type> : StandardFormatter {
  228. Formatter() { }
  229. explicit Formatter(StandardFormatter formatter)
  230. : StandardFormatter(formatter)
  231. {
  232. }
  233. void format(TypeErasedFormatParams&, FormatBuilder&, T value);
  234. };
  235. template<typename T>
  236. struct Formatter<T*> : StandardFormatter {
  237. void format(TypeErasedFormatParams& params, FormatBuilder& builder, T* value)
  238. {
  239. Formatter<FlatPtr> formatter { *this };
  240. formatter.format(params, builder, reinterpret_cast<FlatPtr>(value));
  241. }
  242. };
  243. template<>
  244. struct Formatter<char> : Formatter<StringView> {
  245. void format(TypeErasedFormatParams& params, FormatBuilder& builder, char value)
  246. {
  247. Formatter<StringView>::format(params, builder, { &value, 1 });
  248. }
  249. };
  250. template<>
  251. struct Formatter<bool> : StandardFormatter {
  252. void format(TypeErasedFormatParams&, FormatBuilder&, bool value);
  253. };
  254. void vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams);
  255. void vformat(const LogStream& stream, StringView fmtstr, TypeErasedFormatParams);
  256. #ifndef KERNEL
  257. void vout(StringView fmtstr, TypeErasedFormatParams, bool newline = false);
  258. void raw_out(StringView string);
  259. // FIXME: Rename this function to 'out' when that name becomes avaliable.
  260. template<typename... Parameters>
  261. void new_out(StringView fmtstr, const Parameters&... parameters) { vout(fmtstr, VariadicFormatParams { parameters... }); }
  262. template<typename... Parameters>
  263. void outln(StringView fmtstr, const Parameters&... parameters) { vout(fmtstr, VariadicFormatParams { parameters... }, true); }
  264. void vwarn(StringView fmtstr, TypeErasedFormatParams, bool newline = false);
  265. void raw_warn(StringView string);
  266. // FIXME: Rename this function to 'warn' when that name becomes avaliable.
  267. template<typename... Parameters>
  268. void new_warn(StringView fmtstr, const Parameters&... parameters) { vwarn(fmtstr, VariadicFormatParams { parameters... }); }
  269. template<typename... Parameters>
  270. void warnln(StringView fmtstr, const Parameters&... parameters) { vwarn(fmtstr, VariadicFormatParams { parameters... }, true); }
  271. #endif
  272. void vdbg(StringView fmtstr, TypeErasedFormatParams, bool newline = false);
  273. void raw_dbg(StringView string);
  274. // FIXME: Rename this function to 'dbg' when that name becomes avaliable.
  275. template<typename... Parameters>
  276. void new_dbg(StringView fmtstr, const Parameters&... parameters) { vdbg(fmtstr, VariadicFormatParams { parameters... }); }
  277. template<typename... Parameters>
  278. void dbgln(StringView fmtstr, const Parameters&... parameters) { vdbg(fmtstr, VariadicFormatParams { parameters... }, true); }
  279. } // namespace AK
  280. #ifndef KERNEL
  281. using AK::new_out;
  282. using AK::outln;
  283. using AK::raw_out;
  284. using AK::new_warn;
  285. using AK::raw_warn;
  286. using AK::warnln;
  287. #endif
  288. using AK::dbgln;
  289. using AK::new_dbg;
  290. using AK::raw_dbg;