31#ifndef ETL_FORMAT_INCLUDED
32#define ETL_FORMAT_INCLUDED
51#if ETL_USING_FORMAT_FLOATING_POINT
59 class format_exception :
public etl::exception
63 format_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
64 : exception(reason_, file_name_, line_number_)
69 class bad_format_string_exception :
public etl::format_exception
73 bad_format_string_exception(string_type file_name_, numeric_type line_number_)
74 : etl::format_exception(ETL_ERROR_TEXT(
"format:bad", ETL_FORMAT_FILE_ID
"A"), file_name_, line_number_)
80 namespace private_format_check
83 enum class type_category
96 constexpr type_category get_type_category()
98 using U =
typename etl::remove_cv<typename etl::remove_reference<T>::type>::type;
101 if (etl::is_same<U, bool>::value)
102 return type_category::BOOLEAN;
103 if (etl::is_same<U, char>::value)
104 return type_category::CHAR;
105 if (etl::is_same<U, signed char>::value)
106 return type_category::CHAR;
107 if (etl::is_same<U, unsigned char>::value)
108 return type_category::CHAR;
109 if (etl::is_integral<U>::value)
110 return type_category::INTEGER;
111 if (etl::is_same<U, float>::value)
112 return type_category::FLOAT;
113 if (etl::is_same<U, double>::value)
114 return type_category::FLOAT;
115 if (etl::is_same<U, long double>::value)
116 return type_category::FLOAT;
117 if (etl::is_same<U, const char*>::value)
118 return type_category::STRING;
119 if (etl::is_same<U, char*>::value)
120 return type_category::STRING;
121 if (etl::is_same<U, etl::string_view>::value)
122 return type_category::STRING;
123 if (etl::is_base_of<etl::istring, U>::value)
124 return type_category::STRING;
125 if (etl::is_pointer<U>::value)
126 return type_category::POINTER;
127 if (etl::is_same<U, const void*>::value)
128 return type_category::POINTER;
129 if (etl::is_same<U, void*>::value)
130 return type_category::POINTER;
131 return type_category::NONE;
136 inline constexpr bool ct_check_type_spec(type_category cat,
char type_char)
138 if (type_char ==
'\0')
145 case type_category::BOOLEAN:
147 return type_char ==
's' || type_char ==
'b' || type_char ==
'B' || type_char ==
'c' || type_char ==
'd' || type_char ==
'o'
148 || type_char ==
'x' || type_char ==
'X';
150 case type_category::CHAR:
152 return type_char ==
'c' || type_char ==
'?' || type_char ==
'b' || type_char ==
'B' || type_char ==
'd' || type_char ==
'o'
153 || type_char ==
'x' || type_char ==
'X' || type_char ==
's';
155 case type_category::INTEGER:
157 return type_char ==
'b' || type_char ==
'B' || type_char ==
'c' || type_char ==
'd' || type_char ==
'o' || type_char ==
'x'
160 case type_category::FLOAT:
162 return type_char ==
'a' || type_char ==
'A' || type_char ==
'e' || type_char ==
'E' || type_char ==
'f' || type_char ==
'F'
163 || type_char ==
'g' || type_char ==
'G';
165 case type_category::STRING:
167 return type_char ==
's' || type_char ==
'?';
169 case type_category::POINTER:
171 return type_char ==
'p' || type_char ==
'P';
173 case type_category::NONE:
174 default:
return true;
178 inline constexpr bool ct_is_digit(
char c)
180 return c >=
'0' && c <=
'9';
185 inline constexpr int ct_parse_num(
const char* fmt,
int& pos)
187 if (!ct_is_digit(fmt[pos]))
192 while (ct_is_digit(fmt[pos]))
194 int new_result = result * 10 + (fmt[pos] -
'0');
195 if (new_result < result)
206 inline constexpr bool ct_is_align(
char c)
208 return c ==
'<' || c ==
'>' || c ==
'^';
211 inline constexpr bool ct_is_sign(
char c)
213 return c ==
'+' || c ==
'-' || c ==
' ';
216 inline constexpr bool ct_is_type(
char c)
219 return (c ==
's') || (c ==
'?') || (c ==
'b') || (c ==
'B') || (c ==
'c') || (c ==
'd') || (c ==
'o') || (c ==
'x') || (c ==
'X') || (c ==
'a')
220 || (c ==
'A') || (c ==
'e') || (c ==
'E') || (c ==
'f') || (c ==
'F') || (c ==
'g') || (c ==
'G') || (c ==
'p') || (c ==
'P');
226 inline constexpr bool ct_parse_nested_replacement(
const char* fmt,
int& pos,
int n_args,
int& auto_count,
bool& has_auto,
bool& has_manual)
232 int num = ct_parse_num(fmt, pos);
250 if (auto_count >= n_args)
265 inline constexpr bool ct_skip_format_spec(
const char* fmt,
int& pos,
int n_args,
int& auto_count,
bool& has_auto,
bool& has_manual,
266 char& parsed_type,
bool& parsed_has_precision)
269 parsed_has_precision =
false;
271 if (fmt[pos] ==
'\0' || fmt[pos] ==
'}')
278 if (fmt[pos + 1] !=
'\0' && ct_is_align(fmt[pos + 1]))
280 char fill = fmt[pos];
281 if (fill ==
'{' || fill ==
'}')
285 else if (ct_is_align(fmt[pos]))
291 if (ct_is_sign(fmt[pos]))
309 if (ct_is_digit(fmt[pos]))
311 if (ct_parse_num(fmt, pos) == -2)
314 else if (fmt[pos] ==
'{')
316 if (!ct_parse_nested_replacement(fmt, pos, n_args, auto_count, has_auto, has_manual))
323 bool has_precision =
false;
326 has_precision =
true;
328 if (ct_is_digit(fmt[pos]))
330 if (ct_parse_num(fmt, pos) == -2)
333 else if (fmt[pos] ==
'{')
335 if (!ct_parse_nested_replacement(fmt, pos, n_args, auto_count, has_auto, has_manual))
350 if (ct_is_type(fmt[pos]))
352 parsed_type = fmt[pos];
363 parsed_has_precision = has_precision;
369 template <
class... Args>
370 constexpr bool check_format(
const char* fmt)
372 const int n_args =
static_cast<int>(
sizeof...(Args));
375 bool has_auto =
false;
376 bool has_manual =
false;
379 const private_format_check::type_category arg_categories[] = {
380 private_format_check::get_type_category<Args>()...,
381 private_format_check::type_category::NONE
384 while (fmt[pos] !=
'\0')
399 int resolved_index = -1;
400 int arg_index = private_format_check::ct_parse_num(fmt, pos);
409 if (arg_index >= n_args)
411 resolved_index = arg_index;
419 if (auto_count >= n_args)
421 resolved_index = auto_count;
425 char type_char =
'\0';
426 bool has_precision =
false;
430 if (!private_format_check::ct_skip_format_spec(fmt, pos, n_args, auto_count, has_auto, has_manual, type_char, has_precision))
437 if (resolved_index >= 0 && resolved_index < n_args)
439 if (!private_format_check::ct_check_type_spec(arg_categories[resolved_index], type_char))
447 auto cat = arg_categories[resolved_index];
448 if (cat == private_format_check::type_category::INTEGER || cat == private_format_check::type_category::BOOLEAN
449 || cat == private_format_check::type_category::POINTER)
454 if (cat == private_format_check::type_category::CHAR && (type_char ==
'\0' || type_char ==
'c' || type_char ==
'?'))
480 inline void please_note_this_is_error_message_format_string_syntax_error() noexcept {}
483 template <
class... Args>
484 struct basic_format_string
486 inline ETL_CONSTEVAL basic_format_string(
const char* fmt)
492 if (!check_format<Args...>(fmt))
495 please_note_this_is_error_message_format_string_syntax_error();
500 ETL_CONSTEXPR basic_format_string(
const basic_format_string& other) =
default;
501 ETL_CONSTEXPR14 basic_format_string& operator=(
const basic_format_string& other) =
default;
503 ETL_CONSTEXPR string_view
get()
const
513 template <
class... Args>
514 using format_string = basic_format_string<type_identity_t<Args>...>;
516 template <
class CharT>
517 class basic_format_parse_context
521 using iterator = string_view::const_iterator;
522 using const_iterator = string_view::const_iterator;
523 using char_type = CharT;
525 basic_format_parse_context(etl::string_view fmt,
size_t n_args = 0)
529 , automatic_mode(false)
534 basic_format_parse_context<CharT>& operator=(
const basic_format_parse_context&) =
delete;
536 iterator
begin() const noexcept
538 return range.begin();
541 iterator
end() const noexcept
546 ETL_CONSTEXPR14
void advance_to(iterator pos)
548 range = etl::string_view(pos, range.end());
551 ETL_CONSTEXPR14
size_t next_arg_id()
554 ETL_ASSERT(manual_mode ==
false, ETL_ERROR(bad_format_string_exception));
555 automatic_mode =
true;
556 ETL_ASSERT(current < num_args, ETL_ERROR(bad_format_string_exception) );
560 ETL_CONSTEXPR14
void check_arg_id(
size_t id)
564 ETL_ASSERT(automatic_mode ==
false, ETL_ERROR(bad_format_string_exception));
566 ETL_ASSERT(
id < num_args, ETL_ERROR(bad_format_string_exception) );
571 etl::string_view range;
577 template <
class,
class>
578 friend struct formatter;
581 using format_parse_context = basic_format_parse_context<char>;
586 template <
class T,
class CharT =
char>
592 template <
class OutputIt,
class CharT>
593 class basic_format_context;
595 namespace private_format
598 template <
typename T,
typename =
void>
603 template <
typename T>
604 struct has_formatter_parse<T, etl::void_t<decltype(etl::declval<etl::formatter<T>&>().parse(etl::declval<format_parse_context&>()))> >
612 template <
typename T,
typename =
void>
617 template <
typename T>
618 struct has_formatter_format<T, etl::void_t<decltype(etl::declval<etl::formatter<T>&>().format(
619 etl::declval<const T&>(), etl::declval<etl::basic_format_context<char*, char>&>()))> > : etl::true_type
626 template <
typename T>
627 struct is_formattable : etl::bool_constant<has_formatter_parse<T>::value && has_formatter_format<T>::value>
632 template <
class Context>
633 class basic_format_arg
643 template <
typename T>
644 explicit handle(
const T& value)
645 : obj(static_cast<const void*>(etl::
addressof(value)))
646 , func(&format_custom_type<T>)
650 void format(etl::basic_format_parse_context<char>& parse_ctx, Context& format_ctx)
const
652 func(parse_ctx, format_ctx, obj);
657 template <
typename T>
658 static void format_custom_type(etl::basic_format_parse_context<char>& parse_ctx, Context& format_ctx,
const void* ptr)
660 const T& value = *
static_cast<const T*
>(ptr);
662 parse_ctx.advance_to(f.parse(parse_ctx));
663 format_ctx.advance_to(f.format(value, format_ctx));
667 typedef void (*function_type)(etl::basic_format_parse_context<char>&, Context&,
const void*);
671 basic_format_arg() {}
673 basic_format_arg(
const bool v)
678 basic_format_arg(
const int v)
683 basic_format_arg(
const short v)
684 :
data(static_cast<int>(v))
688 basic_format_arg(
const unsigned short v)
689 :
data(static_cast<unsigned int>(v))
693 basic_format_arg(
const long int v)
694 :
data(static_cast<long long int>(v))
698 basic_format_arg(
const unsigned int v)
703 basic_format_arg(
const long long int v)
708 basic_format_arg(
const unsigned long long int v)
715 basic_format_arg(
const unsigned long v)
716 :
data(static_cast<unsigned long long int>(v))
720 basic_format_arg(
const char* v)
725 basic_format_arg(
char v)
730 basic_format_arg(
const signed char v)
731 :
data(static_cast<char>(v))
735 basic_format_arg(
const unsigned char v)
736 :
data(static_cast<char>(v))
740 #if ETL_USING_FORMAT_FLOATING_POINT
741 basic_format_arg(
const float v)
746 basic_format_arg(
const double v)
751 basic_format_arg(
const long double v)
757 basic_format_arg(
const etl::string_view v)
762 basic_format_arg(
const etl::ibasic_string<char>& v)
767 basic_format_arg(
const basic_format_arg& other)
772 basic_format_arg(
const void* v)
780 template <typename T, typename = etl::enable_if_t<private_format::is_formattable<T>::value> >
781 basic_format_arg(
const T& v)
786 basic_format_arg& operator=(
const basic_format_arg& other)
792 explicit operator bool()
const
794 return !etl::holds_alternative<etl::monostate>(data);
797 template <
class R,
class Visitor>
798 R visit(Visitor&& vis)
800 return etl::visit(etl::forward<Visitor>(vis), data);
814 etl::variant<
etl::monostate, bool, char, int,
unsigned int,
long long int,
unsigned long long int,
815 #if ETL_USING_FORMAT_FLOATING_POINT
816 float, double,
long double,
818 const char*, etl::string_view,
const void*, handle >
822 template <
class Context,
class... Args>
823 class format_arg_store
827 format_arg_store(Args&... args)
832 basic_format_arg<Context>
get(
size_t i)
const
837 etl::array_view<basic_format_arg<Context>>
get()
844 etl::array<basic_format_arg<Context>,
sizeof...(Args)> _args;
847 template <
class Context>
848 class basic_format_args
852 template <
class... Args>
853 basic_format_args(format_arg_store<Context, Args...>& store)
858 basic_format_args(
const basic_format_args<Context>& other)
863 basic_format_args& operator=(
const basic_format_args<Context>& other)
869 basic_format_arg<Context>
get(
size_t i)
const
882 etl::array_view<basic_format_arg<Context>> _args;
885 namespace private_format
887 using char_type = char;
889 enum class spec_align_t
897 enum class spec_sign_t
906 etl::optional<size_t> index{etl::nullopt_t()};
907 spec_align_t
align{spec_align_t::NONE};
909 spec_sign_t sign{spec_sign_t::MINUS};
912 etl::optional<size_t> width{etl::nullopt_t()};
913 bool width_nested_replacement{
false};
914 etl::optional<size_t> precision{etl::nullopt_t()};
916 bool precision_nested_replacement{
false};
917 bool locale_specific{
false};
918 etl::optional<char> type{etl::nullopt_t()};
922 template <
class OutputIt,
class CharT>
923 class basic_format_context
927 using iterator = OutputIt;
928 using char_type = CharT;
930 basic_format_context(
const basic_format_context& other)
932 , _format_args(other._format_args)
936 basic_format_context(OutputIt it, basic_format_args<basic_format_context>& fmt_args)
938 , _format_args(fmt_args)
942 basic_format_context& operator=(
const basic_format_context&) =
delete;
944 basic_format_arg<basic_format_context> arg(
size_t id)
const
946 return _format_args.get(
id);
954 void advance_to(iterator it)
959 private_format::format_spec_t format_spec;
964 basic_format_args<basic_format_context>& _format_args;
967 template <
class OutputIt>
968 using format_context = basic_format_context<OutputIt, char>;
970 template <
class OutputIt>
971 using format_args = basic_format_args<format_context<OutputIt>>;
973 template <
class OutputIt>
974 using format_arg = basic_format_arg<format_context<OutputIt>>;
976 template <
class OutputIt,
class Context = format_context<OutputIt>,
class... Args>
977 format_arg_store<Context, Args...> make_format_args(Args&... args)
979 return format_arg_store<Context, Args...>(args...);
982 namespace private_format
984 inline bool is_digit(
const char c)
986 return c >=
'0' && c <=
'9';
989 inline void advance(format_parse_context& parse_ctx)
991 parse_ctx.advance_to(parse_ctx.begin() + 1);
994 inline etl::optional<size_t> parse_num(format_parse_context& parse_ctx)
996 etl::optional<size_t> result;
997 auto fmt_it = parse_ctx.begin();
998 while (fmt_it != parse_ctx.end())
1000 const char c = *fmt_it;
1003 size_t old_value = result.value_or(0);
1004 size_t new_value = old_value * 10 +
static_cast<size_t>(c -
'0');
1005 if (new_value < old_value)
1008 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1018 if (result.has_value())
1020 parse_ctx.advance_to(fmt_it);
1025 inline etl::optional<char> parse_any_of(format_parse_context& parse_ctx, etl::string_view chars)
1027 etl::optional<char> result;
1028 auto fmt_it = parse_ctx.
begin();
1029 if (fmt_it != parse_ctx.end())
1031 const char c = *fmt_it;
1032 auto it = etl::find(chars.
cbegin(), chars.cend(), c);
1033 if (it != chars.cend())
1037 parse_ctx.advance_to(fmt_it);
1043 inline bool parse_char(format_parse_context& parse_ctx,
char c)
1045 auto fmt_it = parse_ctx.
begin();
1046 if (fmt_it != parse_ctx.end())
1048 char value = *fmt_it;
1052 parse_ctx.advance_to(fmt_it);
1059 inline bool is_align_character(
char c)
1061 return c ==
'<' || c ==
'>' || c ==
'^';
1064 inline spec_align_t align_from_char(
char c)
1066 spec_align_t result = spec_align_t::NONE;
1069 case '<': result = spec_align_t::START;
break;
1070 case '>': result = spec_align_t::END;
break;
1071 case '^': result = spec_align_t::CENTER;
break;
1074 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1079 inline spec_align_t parse_fill_and_align(format_parse_context& parse_ctx, char_type& fill)
1081 spec_align_t result = spec_align_t::NONE;
1084 auto fmt_it = parse_ctx.begin();
1085 if (fmt_it != parse_ctx.end())
1087 const char c = *fmt_it;
1090 if (is_align_character(c))
1092 result = align_from_char(c);
1093 parse_ctx.advance_to(fmt_it);
1095 else if (fmt_it != parse_ctx.end())
1097 const char c2 = *fmt_it;
1099 if (is_align_character(c2))
1101 result = align_from_char(c2);
1103 ETL_ERROR(bad_format_string_exception));
1106 parse_ctx.advance_to(fmt_it);
1117 inline spec_sign_t sign_from_char(
const char c)
1119 spec_sign_t result = spec_sign_t::MINUS;
1122 case '-': result = spec_sign_t::MINUS;
break;
1123 case '+': result = spec_sign_t::PLUS;
break;
1124 case ' ': result = spec_sign_t::SPACE;
break;
1127 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1132 inline bool parse_nested_replacement(format_parse_context& parse_ctx, etl::optional<size_t>& index)
1134 bool start = parse_char(parse_ctx,
'{');
1137 auto num = parse_num(parse_ctx);
1142 parse_ctx.check_arg_id(*index);
1143 bool end = parse_char(parse_ctx,
'}');
1151 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1156 bool end = parse_char(parse_ctx,
'}');
1159 index = parse_ctx.next_arg_id();
1165 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1172 template <
class OutputIt>
1173 void parse_format_spec(format_parse_context& parse_ctx, format_context<OutputIt>& fmt_context)
1175 auto& format_spec = fmt_context.format_spec;
1177 format_spec = format_spec_t();
1179 format_spec.index = parse_num(parse_ctx);
1185 if (!format_spec.index.has_value())
1187 format_spec.index = parse_ctx.next_arg_id();
1191 parse_ctx.check_arg_id(*format_spec.index);
1194 bool colon = parse_char(parse_ctx,
':');
1197 format_spec.align = parse_fill_and_align(parse_ctx, format_spec.
fill);
1199 etl::optional<char> sign = parse_any_of(parse_ctx,
"+- ");
1202 format_spec.sign = sign_from_char(*sign);
1205 format_spec.hash = parse_char(parse_ctx,
'#');
1206 format_spec.zero = parse_char(parse_ctx,
'0');
1208 format_spec.
width = parse_num(parse_ctx);
1209 if (!format_spec.
width)
1212 format_spec.width_nested_replacement = parse_nested_replacement(parse_ctx, format_spec.
width);
1215 if (parse_char(parse_ctx,
'.'))
1217 format_spec.
precision = parse_num(parse_ctx);
1221 format_spec.precision_nested_replacement = parse_nested_replacement(parse_ctx, format_spec.
precision);
1225 format_spec.locale_specific = parse_char(parse_ctx,
'L');
1227 format_spec.type = parse_any_of(parse_ctx,
"s?bBcdoxXaAeEfFgGpP");
1232 template <
class T,
class CharT>
1235 using char_type = CharT;
1241 format_parse_context::iterator parse(format_parse_context& parse_ctx)
1243 return parse_ctx.end();
1246 template <
class OutputIt>
1247 typename format_context<OutputIt>::iterator format(
etl::monostate arg, format_context<OutputIt>& fmt_ctx)
1250 return fmt_ctx.out();
1254 namespace private_format
1257 template <typename UnsignedT, typename = etl::enable_if_t<etl::is_unsigned<UnsignedT>::value>>
1258 UnsignedT get_highest_digit(UnsignedT value,
size_t base = 10)
1260 ETL_ASSERT(base > 1, ETL_ERROR(bad_format_string_exception));
1261 UnsignedT result = 1;
1263 while (result <= value)
1270 template <
typename T>
1271 T int_pow(T base, T exp)
1284 template <
typename OutputIt,
typename T>
1285 void format_sign(OutputIt& it, T value,
const format_spec_t& spec)
1296 case spec_sign_t::MINUS:
1299 case spec_sign_t::PLUS: c =
'+';
break;
1300 case spec_sign_t::SPACE: c =
' ';
break;
1303 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1314 template <
typename OutputIt>
1315 void format_sequence(OutputIt& out_it, etl::string_view value)
1317 auto it = value.
cbegin();
1318 while (it != value.cend())
1326 template <
typename OutputIt,
typename T>
1327 void format_alternate_form(OutputIt& it, T value,
const format_spec_t& spec)
1329 if (spec.hash && spec.type.has_value())
1331 switch (spec.type.value())
1333 case 'b': format_sequence(it,
"0b");
break;
1334 case 'B': format_sequence(it,
"0B");
break;
1339 format_sequence(it,
"0");
1342 case 'x': format_sequence(it,
"0x");
break;
1344 format_sequence(it,
"0X");
1351 template <
typename OutputIt>
1352 void format_plain_char(OutputIt& it, char_type c)
1358 template <
typename OutputIt>
1359 void format_escaped_char(OutputIt& it, char_type c)
1363 case '\t': format_sequence(it,
"\\t");
break;
1364 case '\n': format_sequence(it,
"\\n");
break;
1365 case '\r': format_sequence(it,
"\\r");
break;
1366 case '"': format_sequence(it,
"\\\"");
break;
1367 case '\'': format_sequence(it,
"\\'");
break;
1368 case '\\': format_sequence(it,
"\\\\");
break;
1369 default: *it = c; ++it;
1373 template <
typename OutputIt>
1374 void fill(OutputIt& it,
size_t size, char_type c)
1384 template <
size_t default_base = 10>
1385 inline size_t base_from_spec(
const format_spec_t& spec)
1387 size_t base = default_base;
1388 if (spec.type.has_value())
1390 switch (spec.type.value())
1393 case 'A': base = 16;
break;
1395 case 'B': base = 2;
break;
1396 case 'o': base = 8;
break;
1409 inline bool is_uppercase(
const char c)
1411 return c >=
'A' && c <=
'Z';
1414 template <
typename OutputIt,
typename T>
1415 void format_digit_char(OutputIt& it, T value,
const format_spec_t& spec)
1419 *it =
static_cast<char_type
>(
'0' +
static_cast<typename etl::make_unsigned<T>::type
>(value));
1423 if (spec.type.has_value() && is_uppercase(spec.type.value()))
1425 *it =
static_cast<char_type
>(
'A' +
static_cast<typename etl::make_unsigned<T>::type
>(value - 10));
1429 *it =
static_cast<char_type
>(
'a' +
static_cast<typename etl::make_unsigned<T>::type
>(value - 10));
1435 inline void adjust_width_from_spec(
const format_spec_t& spec,
size_t& width)
1437 if (spec.zero && spec.width.has_value())
1439 width = etl::max(width, spec.width.value());
1443 inline void check_precision(
const format_spec_t& spec)
1445 if (spec.precision.has_value())
1448 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1455 template <
typename OutputIt,
typename T, T default_base = 10,
bool skip_last_zeros = false>
1456 void format_plain_num(OutputIt& it, T value,
const format_spec_t& spec,
size_t width = 0)
1458 using UnsignedT =
typename etl::make_unsigned<T>::type;
1460 UnsignedT unsigned_value = etl::absolute_unsigned(value);
1462 size_t base = base_from_spec<default_base>(spec);
1463 UnsignedT highest_digit = get_highest_digit<UnsignedT>(unsigned_value, base);
1466 UnsignedT align_highest_digit = int_pow<UnsignedT>(base, width - 1);
1467 highest_digit = etl::max<UnsignedT>(align_highest_digit, highest_digit);
1471 while (highest_digit > 0)
1473 UnsignedT digit = unsigned_value / highest_digit;
1474 unsigned_value %= highest_digit;
1475 format_digit_char(it, digit, spec);
1477 if ETL_IF_CONSTEXPR (skip_last_zeros)
1479 if (unsigned_value == 0)
1485 highest_digit /= base;
1490 template <
typename OutputIt,
typename T,
bool skip_last_zeros = false>
1491 void format_num(OutputIt& it, T value,
const format_spec_t& spec)
1494 format_sign<OutputIt, T>(it, value, spec);
1495 format_alternate_form<OutputIt, T>(it, value, spec);
1496 adjust_width_from_spec(spec, width);
1497 check_precision(spec);
1498 format_plain_num(it, value, spec, width);
1501 #if ETL_USING_FORMAT_FLOATING_POINT
1502 #if ETL_NOT_USING_FORMAT_LONG_DOUBLE_MATH
1510 inline long double format_log10(
long double value)
1512 return static_cast<long double>(::log10(
static_cast<double>(value)));
1514 inline long double format_floor(
long double value)
1516 return static_cast<long double>(::floor(
static_cast<double>(value)));
1518 inline long double format_pow(
long double base,
long double exp)
1520 return static_cast<long double>(::pow(
static_cast<double>(base),
static_cast<double>(exp)));
1522 inline long double format_round(
long double value)
1524 return static_cast<long double>(::round(
static_cast<double>(value)));
1526 inline long double format_modf(
long double value,
long double* iptr)
1529 double result = ::modf(
static_cast<double>(value), &d_iptr);
1530 *iptr =
static_cast<long double>(d_iptr);
1531 return static_cast<long double>(result);
1535 template <
typename T>
1536 T format_log10(T value)
1538 return ::log10(value);
1540 template <
typename T>
1541 T format_floor(T value)
1543 return ::floor(value);
1545 template <
typename T>
1546 T format_pow(T base, T exp)
1548 return ::pow(base, exp);
1550 template <
typename T>
1551 T format_round(T value)
1553 return ::round(value);
1555 template <
typename T>
1556 T format_modf(T value, T* iptr)
1558 return ::modf(value, iptr);
1561 template <
typename OutputIt,
typename T>
1562 void format_floating_default(OutputIt& it, T value,
const format_spec_t& spec)
1564 const size_t fractional_decimals = 6;
1567 bool sign = signbit(value);
1568 T abs_value = sign ? -value : value;
1572 if (abs_value >=
static_cast<T
>(1e18) || (abs_value >
static_cast<T
>(0) && abs_value <
static_cast<T
>(1e-6)))
1574 format_spec_t spec_e = spec;
1576 format_floating_e(it, value, spec_e);
1581 T fractional = format_modf(value, &integral);
1586 fractional = -fractional;
1587 integral = -integral;
1590 unsigned long long int scale = int_pow<unsigned long long int>(10, fractional_decimals);
1591 unsigned long long int fractional_int =
static_cast<unsigned long long int>(format_round(fractional * scale));
1592 unsigned long long int integral_int =
static_cast<unsigned long long int>(integral);
1594 if (fractional_int == scale)
1600 private_format::format_sign<OutputIt, int>(it, sign ? -1 : 0, spec);
1601 private_format::format_plain_num<OutputIt, unsigned long long int>(it, integral_int, spec);
1602 private_format::format_sequence<OutputIt>(it,
".");
1603 private_format::format_plain_num<OutputIt, unsigned long long int, 10, true>(it, fractional_int, spec, fractional_decimals);
1607 template <
typename OutputIt,
typename T>
1608 void format_floating_a(OutputIt& it, T value,
const format_spec_t& spec)
1610 static const size_t fractional_decimals = 10;
1611 static const size_t exponent_decimals = 1;
1612 long long int exponent_int = 0;
1615 bool sign = signbit(value);
1618 T fractional = format_modf(value, &integral);
1620 while (value >= 0x10 || value <= -0x10)
1624 fractional = format_modf(value, &integral);
1627 while ((value > 0.0000000000001 && value < 1) || (value < -0.0000000000001 && value > -1))
1631 fractional = format_modf(value, &integral);
1637 fractional = -fractional;
1638 integral = -integral;
1641 unsigned long long int scale = int_pow<unsigned long long int>(0x10, fractional_decimals);
1642 unsigned long long int fractional_int =
static_cast<unsigned long long int>(format_round(fractional * scale));
1643 unsigned long long int integral_int =
static_cast<unsigned long long int>(integral);
1645 if (fractional_int == scale)
1651 private_format::format_sign<OutputIt, int>(it, sign ? -1 : 0, spec);
1652 private_format::format_plain_char<OutputIt>(it,
'0');
1653 char hex_letter =
'x';
1654 if (is_uppercase(spec.type.value()))
1658 private_format::format_plain_char<OutputIt>(it, hex_letter);
1659 private_format::format_plain_num<OutputIt, unsigned long long int, 16>(it, integral_int, spec);
1660 private_format::format_plain_char<OutputIt>(it,
'.');
1661 private_format::format_plain_num<OutputIt, unsigned long long int, 16, true>(it, fractional_int, spec, fractional_decimals);
1663 if (is_uppercase(spec.type.value()))
1667 private_format::format_plain_char<OutputIt>(it, letter);
1668 private_format::format_plain_char<OutputIt>(it, (exponent_int < 0) ?
'-' :
'+');
1669 private_format::format_plain_num<OutputIt, long long int, 16>(it, exponent_int, spec, exponent_decimals);
1672 template <
typename OutputIt,
typename T>
1673 void format_floating_e(OutputIt& it, T value,
const format_spec_t& spec)
1675 static const size_t fractional_decimals = 6;
1676 static const size_t exponent_decimals = 2;
1677 long long int exponent_int = 0;
1680 bool sign = signbit(value);
1682 T abs_value = sign ? -value : value;
1684 if (abs_value >
static_cast<T
>(0))
1686 exponent_int =
static_cast<long long int>(format_floor(format_log10(abs_value)));
1687 value = abs_value / format_pow(
static_cast<T
>(10),
static_cast<T
>(exponent_int));
1689 if (value >=
static_cast<T
>(10))
1691 value /=
static_cast<T
>(10);
1694 else if (value <
static_cast<T
>(1))
1696 value *=
static_cast<T
>(10);
1702 value =
static_cast<T
>(0);
1706 T fractional = format_modf(value, &integral);
1708 unsigned long long int scale = int_pow<unsigned long long int>(10, fractional_decimals);
1709 unsigned long long int fractional_int =
static_cast<unsigned long long int>(format_round(fractional * scale));
1710 unsigned long long int integral_int =
static_cast<unsigned long long int>(integral);
1712 if (fractional_int == scale)
1717 if (integral_int == 10)
1724 private_format::format_sign<OutputIt, int>(it, sign ? -1 : 0, spec);
1725 private_format::format_plain_num<OutputIt, unsigned long long int>(it, integral_int, spec);
1726 private_format::format_sequence<OutputIt>(it,
".");
1727 private_format::format_plain_num<OutputIt, unsigned long long int>(it, fractional_int, spec, fractional_decimals);
1729 if (is_uppercase(spec.type.value()))
1733 private_format::format_plain_char<OutputIt>(it, letter);
1734 private_format::format_plain_char<OutputIt>(it, (exponent_int < 0) ?
'-' :
'+');
1735 private_format::format_plain_num<OutputIt, long long int>(it, exponent_int, spec, exponent_decimals);
1738 template <
typename OutputIt,
typename T>
1739 void format_floating_f(OutputIt& it, T value,
const format_spec_t& spec)
1741 const size_t fractional_decimals = 6;
1744 bool sign = signbit(value);
1747 T fractional = format_modf(value, &integral);
1752 fractional = -fractional;
1753 integral = -integral;
1756 unsigned long long int scale = int_pow<unsigned long long int>(10, fractional_decimals);
1757 unsigned long long int fractional_int =
static_cast<unsigned long long int>(format_round(fractional * scale));
1758 unsigned long long int integral_int =
static_cast<unsigned long long int>(integral);
1760 if (fractional_int == scale)
1766 private_format::format_sign<OutputIt, int>(it, sign ? -1 : 0, spec);
1767 private_format::format_plain_num<OutputIt, unsigned long long int>(it, integral_int, spec);
1768 private_format::format_sequence<OutputIt>(it,
".");
1769 private_format::format_plain_num<OutputIt, unsigned long long int>(it, fractional_int, spec, fractional_decimals);
1773 class dummy_assign_to
1777 dummy_assign_to& operator=(char_type)
1783 template <
class OutputIt>
1784 class limit_assign_to
1788 limit_assign_to(OutputIt o,
bool is_active)
1794 limit_assign_to& operator=(char_type c)
1809 template <
class OutputIt>
1810 class limit_iterator
1814 limit_iterator(OutputIt& it,
size_t n)
1820 limit_iterator(
const limit_iterator& other) =
default;
1821 limit_iterator(limit_iterator&& other) =
default;
1822 limit_iterator& operator=(
const limit_iterator& other) =
default;
1823 limit_iterator& operator=(limit_iterator&& other) =
default;
1827 return limit_assign_to<OutputIt>(out, (limit > 0));
1830 limit_iterator& operator++()
1840 limit_iterator operator++(
int)
1842 limit_iterator temp = *
this;
1862 class counter_iterator
1871 counter_iterator(
const counter_iterator& other) =
default;
1872 counter_iterator& operator=(
const counter_iterator& other) =
default;
1876 return dummy_assign_to();
1879 counter_iterator& operator++()
1885 counter_iterator operator++(
int)
1887 counter_iterator temp = *
this;
1902 #if ETL_USING_FORMAT_FLOATING_POINT
1903 template <
typename OutputIt,
typename T>
1904 void format_floating_g(OutputIt& it, T value,
const format_spec_t& spec)
1906 private_format::counter_iterator counter_e, counter_f;
1908 format_floating_e(counter_e, value, spec);
1909 format_floating_f(counter_f, value, spec);
1911 if (counter_e.value() < counter_f.value())
1913 format_floating_e(it, value, spec);
1917 format_floating_f(it, value, spec);
1921 template <
typename OutputIt,
typename T>
1922 void format_floating(OutputIt& it, T value,
const format_spec_t& spec)
1926 if (spec.type.has_value() && (is_uppercase(spec.type.value())))
1928 format_sequence(it,
"NAN");
1932 format_sequence(it,
"nan");
1935 else if (isinf(value))
1937 if (spec.type.has_value() && (is_uppercase(spec.type.value())))
1939 format_sequence(it,
"INF");
1943 format_sequence(it,
"inf");
1946 else if (!spec.type.has_value())
1948 format_floating_default(it, value, spec);
1952 switch (spec.type.value())
1955 case 'A': format_floating_a(it, value, spec);
break;
1957 case 'E': format_floating_e(it, value, spec);
break;
1959 case 'F': format_floating_f(it, value, spec);
break;
1961 case 'G': format_floating_g(it, value, spec);
break;
1964 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
1970 template <
class OutputIt>
1971 struct format_visitor
1973 using output_iterator = OutputIt;
1975 format_visitor(format_parse_context& parse_context, format_context<OutputIt>& f_ctx)
1976 : parse_ctx(parse_context)
1982 template <
typename T>
1983 void operator()(T value)
1986 format_parse_context::iterator it = f.parse(parse_ctx);
1987 parse_ctx.advance_to(it);
1988 OutputIt fit = f.format(value, fmt_ctx);
1989 fmt_ctx.advance_to(fit);
1993 void operator()(
typename basic_format_arg<format_context<OutputIt> >::handle h)
1995 h.format(parse_ctx, fmt_ctx);
1998 format_parse_context& parse_ctx;
1999 format_context<OutputIt>& fmt_ctx;
2002 template <
class OutputIt>
2003 void output(format_context<OutputIt>& fmt_context,
char c)
2005 *fmt_context.out() = c;
2006 OutputIt tmp = fmt_context.out();
2008 fmt_context.advance_to(tmp);
2012 struct size_t_extractor
2021 void operator()(
int v)
2023 value =
static_cast<size_t>(v);
2025 void operator()(
unsigned int v)
2027 value =
static_cast<size_t>(v);
2029 void operator()(
long long int v)
2031 value =
static_cast<size_t>(v);
2033 void operator()(
unsigned long long int v)
2035 value =
static_cast<size_t>(v);
2039 template <
typename T>
2048 template <
class OutputIt>
2049 void resolve_nested_replacements(format_spec_t& spec, format_args<OutputIt>& args)
2051 if (spec.width_nested_replacement && spec.width.has_value())
2053 format_arg<OutputIt> width_arg = args.get(spec.width.value());
2054 size_t_extractor ext;
2055 width_arg.template visit<void>(ext);
2056 spec.width = ext.value;
2057 spec.width_nested_replacement =
false;
2059 if (spec.precision_nested_replacement && spec.precision.has_value())
2061 format_arg<OutputIt> prec_arg = args.get(spec.precision.value());
2062 size_t_extractor ext;
2063 prec_arg.template visit<void>(ext);
2064 spec.precision = ext.value;
2065 spec.precision_nested_replacement =
false;
2071 inline void compute_padding(
size_t pad, spec_align_t align,
bool default_align_start,
size_t& prefix_size,
size_t& suffix_size)
2075 case spec_align_t::START:
2079 case spec_align_t::CENTER:
2080 prefix_size =
pad / 2;
2081 suffix_size =
pad - prefix_size;
2083 case spec_align_t::END:
2087 case spec_align_t::NONE:
2089 if (default_align_start)
2103 template <
typename OutputIt,
typename Int>
2104 typename format_context<OutputIt>::iterator format_aligned_int(Int arg, format_context<OutputIt>& fmt_ctx)
2106 size_t prefix_size = 0;
2107 size_t suffix_size = 0;
2109 if (fmt_ctx.format_spec.width)
2111 private_format::counter_iterator counter;
2112 private_format::format_num<private_format::counter_iterator, Int>(counter, arg, fmt_ctx.format_spec);
2114 if (counter.value() < fmt_ctx.format_spec.width.value())
2116 size_t pad = fmt_ctx.format_spec.width.value() - counter.value();
2117 compute_padding(pad, fmt_ctx.format_spec.align,
false, prefix_size, suffix_size);
2122 OutputIt it = fmt_ctx.out();
2123 private_format::fill<OutputIt>(it, prefix_size, fmt_ctx.format_spec.fill);
2124 private_format::format_num<OutputIt, Int>(it, arg, fmt_ctx.format_spec);
2125 private_format::fill<OutputIt>(it, suffix_size, fmt_ctx.format_spec.fill);
2129 #if ETL_USING_FORMAT_FLOATING_POINT
2130 template <
typename OutputIt,
typename Float>
2131 typename format_context<OutputIt>::iterator format_aligned_floating(Float arg, format_context<OutputIt>& fmt_ctx)
2133 size_t prefix_size = 0;
2134 size_t suffix_size = 0;
2137 char_type fill_char = fmt_ctx.format_spec.fill;
2138 if (fmt_ctx.format_spec.zero && fmt_ctx.format_spec.align == spec_align_t::NONE)
2143 if (fmt_ctx.format_spec.width)
2145 private_format::counter_iterator counter;
2146 private_format::format_floating<private_format::counter_iterator, Float>(counter, arg, fmt_ctx.format_spec);
2148 if (counter.value() < fmt_ctx.format_spec.width.value())
2150 size_t pad = fmt_ctx.format_spec.width.value() - counter.value();
2151 if (fmt_ctx.format_spec.zero && fmt_ctx.format_spec.align == spec_align_t::NONE)
2158 compute_padding(pad, fmt_ctx.format_spec.align,
false, prefix_size, suffix_size);
2164 OutputIt it = fmt_ctx.out();
2166 if (fmt_ctx.format_spec.zero && fmt_ctx.format_spec.align == spec_align_t::NONE)
2169 bool sign = signbit(arg);
2170 if (sign || fmt_ctx.format_spec.sign != spec_sign_t::MINUS)
2173 char_type sc =
'\0';
2180 switch (fmt_ctx.format_spec.sign)
2182 case spec_sign_t::PLUS: sc =
'+';
break;
2183 case spec_sign_t::SPACE: sc =
' ';
break;
2193 private_format::fill<OutputIt>(it, prefix_size,
'0');
2195 format_spec_t no_sign_spec = fmt_ctx.format_spec;
2196 no_sign_spec.sign = spec_sign_t::MINUS;
2197 Float abs_arg = sign ? -arg : arg;
2198 private_format::format_floating<OutputIt, Float>(it, abs_arg, no_sign_spec);
2202 private_format::fill<OutputIt>(it, prefix_size, fill_char);
2203 private_format::format_floating<OutputIt, Float>(it, arg, fmt_ctx.format_spec);
2204 private_format::fill<OutputIt>(it, suffix_size, fill_char);
2210 template <
typename OutputIt>
2211 void format_string_view(OutputIt& it, etl::string_view arg,
const format_spec_t& spec)
2213 bool escaped =
false;
2214 if (spec.type.has_value())
2216 switch (spec.type.value())
2227 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
2230 size_t limit = etl::numeric_limits<size_t>::max();
2231 if (spec.precision.has_value())
2233 limit = spec.precision.value();
2238 format_plain_char(it,
'"');
2240 etl::string_view::const_iterator arg_it = arg.
begin();
2241 while (arg_it != arg.cend() && limit > 0)
2245 format_escaped_char(it, *arg_it);
2249 format_plain_char(it, *arg_it);
2256 format_plain_char(it,
'"');
2260 template <
typename OutputIt>
2261 typename format_context<OutputIt>::iterator format_aligned_string_view(etl::string_view arg, format_context<OutputIt>& fmt_ctx)
2263 size_t prefix_size = 0;
2264 size_t suffix_size = 0;
2266 if (fmt_ctx.format_spec.width)
2268 private_format::counter_iterator counter;
2269 private_format::format_string_view<private_format::counter_iterator>(counter, arg, fmt_ctx.format_spec);
2271 if (counter.value() < fmt_ctx.format_spec.width.value())
2273 size_t pad = fmt_ctx.format_spec.width.value() - counter.value();
2274 compute_padding(pad, fmt_ctx.format_spec.align,
true, prefix_size, suffix_size);
2279 OutputIt it = fmt_ctx.out();
2280 private_format::fill<OutputIt>(it, prefix_size, fmt_ctx.format_spec.fill);
2281 private_format::format_string_view<OutputIt>(it, arg, fmt_ctx.format_spec);
2282 private_format::fill<OutputIt>(it, suffix_size, fmt_ctx.format_spec.fill);
2286 template <
typename OutputIt>
2287 typename format_context<OutputIt>::iterator format_aligned_chars(
const char* arg, format_context<OutputIt>& fmt_ctx)
2289 return format_aligned_string_view<OutputIt>(etl::string_view(arg), fmt_ctx);
2292 inline void check_char_spec(
const format_spec_t& spec)
2294 if ((!spec.type.has_value() || spec.type.value() ==
'c' || spec.type.value() ==
'?')
2295 && (spec.sign != spec_sign_t::MINUS || spec.zero || spec.hash || spec.precision))
2297 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
2301 template <
typename OutputIt>
2302 void format_char(OutputIt& it, char_type c,
const format_spec_t& spec)
2304 check_char_spec(spec);
2305 if (spec.type.has_value())
2307 switch (spec.type.value())
2311 format_plain_char(it, c);
2315 format_plain_char(it,
'\'');
2316 format_escaped_char(it, c);
2317 format_plain_char(it,
'\'');
2324 case 'X': private_format::format_num<OutputIt, unsigned int>(it,
static_cast<unsigned int>(
static_cast<unsigned char>(c)), spec);
break;
2327 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
2332 format_plain_char(it, c);
2336 template <
typename OutputIt>
2337 typename format_context<OutputIt>::iterator format_aligned_char(char_type arg, format_context<OutputIt>& fmt_ctx)
2339 size_t prefix_size = 0;
2340 size_t suffix_size = 0;
2342 if (fmt_ctx.format_spec.width)
2344 private_format::counter_iterator counter;
2345 private_format::format_char<private_format::counter_iterator>(counter, arg, fmt_ctx.format_spec);
2347 if (counter.value() < fmt_ctx.format_spec.width.value())
2349 size_t pad = fmt_ctx.format_spec.width.value() - counter.value();
2351 bool default_start =
2352 !fmt_ctx.format_spec.type.has_value() || fmt_ctx.format_spec.type.value() ==
'c' || fmt_ctx.format_spec.type.value() ==
'?';
2353 compute_padding(pad, fmt_ctx.format_spec.align, default_start, prefix_size, suffix_size);
2358 OutputIt it = fmt_ctx.out();
2359 private_format::fill<OutputIt>(it, prefix_size, fmt_ctx.format_spec.fill);
2360 private_format::format_char<OutputIt>(it, arg, fmt_ctx.format_spec);
2361 private_format::fill<OutputIt>(it, suffix_size, fmt_ctx.format_spec.fill);
2365 template <
typename OutputIt>
2366 void format_bool(OutputIt& it,
bool value,
const format_spec_t& spec)
2368 if (spec.type.has_value())
2370 switch (spec.type.value())
2374 format_sequence(it, value ?
"true" :
"false");
2381 case 'X': private_format::format_num<OutputIt, unsigned int>(it,
static_cast<unsigned int>(
static_cast<unsigned char>(value)), spec);
break;
2384 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
2389 format_sequence(it, value ?
"true" :
"false");
2393 template <
typename OutputIt>
2394 typename format_context<OutputIt>::iterator format_aligned_bool(
bool arg, format_context<OutputIt>& fmt_ctx)
2396 size_t prefix_size = 0;
2397 size_t suffix_size = 0;
2399 if (fmt_ctx.format_spec.width)
2401 private_format::counter_iterator counter;
2402 private_format::format_bool<private_format::counter_iterator>(counter, arg, fmt_ctx.format_spec);
2404 if (counter.value() < fmt_ctx.format_spec.width.value())
2406 size_t pad = fmt_ctx.format_spec.width.value() - counter.value();
2407 compute_padding(pad, fmt_ctx.format_spec.align,
false, prefix_size, suffix_size);
2412 OutputIt it = fmt_ctx.out();
2413 private_format::fill<OutputIt>(it, prefix_size, fmt_ctx.format_spec.fill);
2414 private_format::format_bool<OutputIt>(it, arg, fmt_ctx.format_spec);
2415 private_format::fill<OutputIt>(it, suffix_size, fmt_ctx.format_spec.fill);
2419 template <
typename OutputIt>
2420 void format_pointer(OutputIt& it,
const void* value,
const format_spec_t& spec)
2422 if (spec.type.has_value())
2424 switch (spec.type.value())
2428 format_sequence(it, spec.type.value() ==
'p' ?
"0x" :
"0X");
2429 format_plain_num<OutputIt, uintptr_t>(it,
reinterpret_cast<uintptr_t
>(value), spec);
2433 ETL_ASSERT_FAIL(ETL_ERROR(bad_format_string_exception));
2438 format_sequence(it,
"0x");
2439 format_plain_num<OutputIt, uintptr_t>(it,
reinterpret_cast<uintptr_t
>(value), spec);
2443 template <
typename OutputIt>
2444 typename format_context<OutputIt>::iterator format_aligned_pointer(
const void* arg, format_context<OutputIt>& fmt_ctx)
2446 size_t prefix_size = 0;
2447 size_t suffix_size = 0;
2449 if (fmt_ctx.format_spec.width)
2451 private_format::counter_iterator counter;
2452 private_format::format_pointer<private_format::counter_iterator>(counter, arg, fmt_ctx.format_spec);
2454 if (counter.value() < fmt_ctx.format_spec.width.value())
2456 size_t pad = fmt_ctx.format_spec.width.value() - counter.value();
2457 compute_padding(pad, fmt_ctx.format_spec.align,
false, prefix_size, suffix_size);
2462 OutputIt it = fmt_ctx.out();
2463 private_format::fill<OutputIt>(it, prefix_size, fmt_ctx.format_spec.fill);
2464 private_format::format_pointer<OutputIt>(it, arg, fmt_ctx.format_spec);
2465 private_format::fill<OutputIt>(it, suffix_size, fmt_ctx.format_spec.fill);
2471 struct formatter<int>
2473 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2476 return parse_ctx.begin();
2479 template <
class OutputIt>
2480 typename format_context<OutputIt>::iterator format(
int arg, format_context<OutputIt>& fmt_ctx)
2482 if (fmt_ctx.format_spec.type.has_value() && fmt_ctx.format_spec.type.value() ==
'c')
2484 return private_format::format_aligned_char<OutputIt>(
static_cast<private_format::char_type
>(arg), fmt_ctx);
2486 return private_format::format_aligned_int<OutputIt, int>(arg, fmt_ctx);
2491 struct formatter<unsigned int>
2493 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2496 return parse_ctx.begin();
2499 template <
class OutputIt>
2500 typename format_context<OutputIt>::iterator format(
unsigned int arg, format_context<OutputIt>& fmt_ctx)
2502 if (fmt_ctx.format_spec.type.has_value() && fmt_ctx.format_spec.type.value() ==
'c')
2504 return private_format::format_aligned_char<OutputIt>(
static_cast<private_format::char_type
>(arg), fmt_ctx);
2506 return private_format::format_aligned_int<OutputIt, unsigned int>(arg, fmt_ctx);
2511 struct formatter<long long int>
2513 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2516 return parse_ctx.begin();
2519 template <
class OutputIt>
2520 typename format_context<OutputIt>::iterator format(
long long int arg, format_context<OutputIt>& fmt_ctx)
2522 if (fmt_ctx.format_spec.type.has_value() && fmt_ctx.format_spec.type.value() ==
'c')
2524 return private_format::format_aligned_char<OutputIt>(
static_cast<private_format::char_type
>(arg), fmt_ctx);
2526 return private_format::format_aligned_int<OutputIt, long long int>(arg, fmt_ctx);
2531 struct formatter<unsigned long long int>
2533 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2536 return parse_ctx.begin();
2539 template <
class OutputIt>
2540 typename format_context<OutputIt>::iterator format(
unsigned long long int arg, format_context<OutputIt>& fmt_ctx)
2542 if (fmt_ctx.format_spec.type.has_value() && fmt_ctx.format_spec.type.value() ==
'c')
2544 return private_format::format_aligned_char<OutputIt>(
static_cast<private_format::char_type
>(arg), fmt_ctx);
2546 return private_format::format_aligned_int<OutputIt, unsigned long long int>(arg, fmt_ctx);
2551 struct formatter<char>
2553 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2556 return parse_ctx.begin();
2559 template <
class OutputIt>
2560 typename format_context<OutputIt>::iterator format(private_format::char_type arg, format_context<OutputIt>& fmt_ctx)
2562 return private_format::format_aligned_char<OutputIt>(arg, fmt_ctx);
2566 #if ETL_USING_FORMAT_FLOATING_POINT
2568 struct formatter<float>
2570 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2573 return parse_ctx.begin();
2576 template <
class OutputIt>
2577 typename format_context<OutputIt>::iterator format(
float arg, format_context<OutputIt>& fmt_ctx)
2579 return private_format::format_aligned_floating<OutputIt, float>(arg, fmt_ctx);
2584 struct formatter<double>
2586 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2589 return parse_ctx.begin();
2592 template <
class OutputIt>
2593 typename format_context<OutputIt>::iterator format(
double arg, format_context<OutputIt>& fmt_ctx)
2595 return private_format::format_aligned_floating<OutputIt, double>(arg, fmt_ctx);
2600 struct formatter<long double>
2602 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2605 return parse_ctx.begin();
2608 template <
class OutputIt>
2609 typename format_context<OutputIt>::iterator format(
long double arg, format_context<OutputIt>& fmt_ctx)
2611 return private_format::format_aligned_floating<OutputIt, long double>(arg, fmt_ctx);
2617 struct formatter<etl::string_view>
2619 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2622 return parse_ctx.begin();
2625 template <
class OutputIt>
2626 typename format_context<OutputIt>::iterator format(etl::string_view arg, format_context<OutputIt>& fmt_ctx)
2628 return private_format::format_aligned_string_view<OutputIt>(arg, fmt_ctx);
2634 struct formatter<const char*>
2636 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2639 return parse_ctx.begin();
2642 template <
class OutputIt>
2643 typename format_context<OutputIt>::iterator format(
const char* arg, format_context<OutputIt>& fmt_ctx)
2645 return private_format::format_aligned_chars<OutputIt>(arg, fmt_ctx);
2650 struct formatter<bool>
2652 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2655 return parse_ctx.begin();
2658 template <
class OutputIt>
2659 typename format_context<OutputIt>::iterator format(
bool arg, format_context<OutputIt>& fmt_ctx)
2661 return private_format::format_aligned_bool<OutputIt>(arg, fmt_ctx);
2666 struct formatter<const void*>
2668 format_parse_context::iterator parse(format_parse_context& parse_ctx)
2671 return parse_ctx.begin();
2674 template <
class OutputIt>
2675 typename format_context<OutputIt>::iterator format(
const void* arg, format_context<OutputIt>& fmt_ctx)
2677 return private_format::format_aligned_pointer<OutputIt>(arg, fmt_ctx);
2681 template <
class OutputIt>
2682 OutputIt vformat_to(OutputIt out, etl::string_view fmt, format_args<OutputIt> args)
2684 format_parse_context parse_context(fmt, args.size());
2685 format_context<OutputIt> fmt_context(out, args);
2686 private_format::format_visitor<OutputIt> v(parse_context, fmt_context);
2688 while (parse_context.begin() != parse_context.end())
2690 const char c = *parse_context.begin();
2691 private_format::advance(parse_context);
2694 if (*parse_context.begin() ==
'{')
2697 private_format::output<OutputIt>(fmt_context, c);
2698 private_format::advance(parse_context);
2702 private_format::parse_format_spec<OutputIt>(parse_context, fmt_context);
2705 private_format::resolve_nested_replacements<OutputIt>(fmt_context.format_spec, args);
2708 size_t index = fmt_context.format_spec.index.value();
2709 format_arg<OutputIt> arg = args.get(index);
2710 arg.template visit<void>(v);
2712 ETL_ASSERT(*parse_context.begin() ==
'}', ETL_ERROR(bad_format_string_exception) );
2713 if (parse_context.begin() != parse_context.end())
2715 private_format::advance(parse_context);
2721 ETL_ASSERT(*parse_context.begin() ==
'}', ETL_ERROR(bad_format_string_exception) );
2723 private_format::output<OutputIt>(fmt_context, c);
2724 private_format::advance(parse_context);
2728 private_format::output<OutputIt>(fmt_context, c);
2732 return fmt_context.out();
2735 template <typename OutputIt, typename = etl::enable_if_t< !etl::is_base_of< etl::remove_reference<etl::istring>::type, OutputIt>::value>,
2737 OutputIt format_to(OutputIt out, format_string<Args...> fmt, Args&&... args)
2739 auto the_args{make_format_args<OutputIt>(args...)};
2740 return vformat_to(etl::move(out), fmt.get(), format_args<OutputIt>(the_args));
2743 template <
typename OutputIt,
class WrapperIt = private_format::limit_iterator<OutputIt>,
class... Args>
2744 OutputIt format_to_n(OutputIt out,
size_t n, format_string<Args...> fmt, Args&&... args)
2746 auto the_args{make_format_args<WrapperIt>(args...)};
2747 return vformat_to(WrapperIt(out, n), fmt.get(), format_args<WrapperIt>(the_args)).get();
2751 template <
class... Args>
2752 etl::istring::iterator format_to(etl::istring& out, format_string<Args...> fmt, Args&&... args)
2754 etl::istring::iterator result = format_to_n(out.
begin(), out.
max_size(), fmt, etl::forward<Args>(args)...);
2759 template <
class... Args>
2760 size_t formatted_size(format_string<Args...> fmt, Args&&... args)
2762 private_format::counter_iterator it;
2763 it = format_to(it, fmt, etl::forward<Args>(args)...);
ETL_CONSTEXPR const_iterator cbegin() const ETL_NOEXCEPT
Returns a const iterator to the beginning of the array.
Definition string_view.h:239
ETL_CONSTEXPR const_iterator begin() const ETL_NOEXCEPT
Returns a const iterator to the beginning of the array.
Definition string_view.h:231
iterator begin()
Definition basic_string.h:356
void uninitialized_resize(size_type new_size)
Definition basic_string.h:523
size_type max_size() const
Definition basic_string.h:223
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
ETL_CONSTEXPR17 etl::enable_if<!etl::is_same< T, etl::nullptr_t >::value, T >::type * addressof(T &t)
Definition addressof.h:52
void * align(size_t alignment, size_t size, void *&ptr, size_t &space) ETL_NOEXCEPT
Definition memory.h:334
ETL_CONSTEXPR20_STL iterator begin() ETL_NOEXCEPT
Returns an iterator to the beginning of the optional.
Definition optional.h:1491
etl::monostate monostate
Definition variant_legacy.h:80
ETL_CONSTEXPR TContainer::pointer data(TContainer &container)
Definition iterator.h:1470
void pad(TIString &s, typename TIString::size_type required_size, string_pad_direction pad_direction, typename TIString::value_type pad_char)
pad
Definition string_utilities.h:831
integral_constant< bool, false > false_type
integral_constant specialisations
Definition type_traits.h:80
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1434
ETL_CONSTEXPR14 enable_if<!etl::is_specialization< TRep2, etl::chrono::duration >::value, etl::chrono::duration< typenameetl::common_type< TRep1, TRep2 >::type, TPeriod1 > >::type operator*(const etl::chrono::duration< TRep1, TPeriod1 > &lhs, const TRep2 &rhs) ETL_NOEXCEPT
Operator *.
Definition duration.h:541
TContainer::iterator end(TContainer &container)
Definition iterator.h:1166
T & get(array< T, Size > &a)
Definition array.h:1158
TContainer::iterator begin(TContainer &container)
Definition iterator.h:1136
A 'no-value' placeholder.
Definition monostate.h:42