LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
bwf_base.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Apache Software Foundation 2019
7
8#pragma once
9
10#include <cstdlib>
11#include <utility>
12#include <cstring>
13#include <vector>
14#include <unordered_map>
15#include <string>
16#include <iosfwd>
17#include <string_view>
18#include <functional>
19#include <tuple>
20#include <any>
21#include <array>
22
23#include "swoc/swoc_version.h"
24#include "swoc/TextView.h"
25#include "swoc/MemSpan.h"
26#include "swoc/MemArena.h"
27#include "swoc/BufferWriter.h"
28#include "swoc/swoc_meta.h"
29
30namespace swoc { inline namespace SWOC_VERSION_NS {
31namespace bwf {
37struct Spec {
38 using self_type = Spec;
39
40 static constexpr char DEFAULT_TYPE = 'g';
41 static constexpr char INVALID_TYPE = 0;
42 static constexpr char LITERAL_TYPE = '"';
43 static constexpr char CAPTURE_TYPE = 1;
44
45 static constexpr char SIGN_ALWAYS = '+';
46 static constexpr char SIGN_NEVER = ' ';
47 static constexpr char SIGN_NEG = '-';
48
50 constexpr Spec() {}
51
53 Spec(const TextView &fmt);
54
57 bool parse(TextView fmt);
58
59 char _fill = ' ';
60 char _sign = SIGN_NEG;
62 enum class Align : char {
68 } _align = Align::NONE;
70 bool _radix_lead_p = false;
71 // @a _min is unsigned because there's no point in an invalid default, 0 works fine.
72 unsigned int _min = 0;
73 int _prec = -1;
74 unsigned int _max = std::numeric_limits<unsigned int>::max();
75 int _idx = -1;
76 std::string_view _name;
77 std::string_view _ext;
78
80 static const self_type DEFAULT;
81
83 static bool is_type(char c);
84
86 static bool is_numeric_type(char c);
87
89 static bool is_upper_case_type(char c);
90
92 bool has_numeric_type() const;
93
95 bool has_upper_case_type() const;
96
98 bool has_pointer_type() const;
99
101 bool has_valid_type() const;
102
103protected:
105 Align align_of(char c);
106
108 bool is_sign(char c);
109
111 struct Property {
112 Property();
114 uint8_t _data[0x100]{};
116 static constexpr uint8_t ALIGN_MASK = 0x0F;
117 static constexpr uint8_t TYPE_CHAR = 0x10;
118 static constexpr uint8_t UPPER_TYPE_CHAR = 0x20;
119 static constexpr uint8_t NUMERIC_TYPE_CHAR = 0x40;
120 static constexpr uint8_t SIGN_CHAR = 0x80;
121 };
122 static const Property &
124 {
125 static const Property prop;
126 return prop;
127 }
128};
129
140struct Format {
142
144 Format() = default;
145
147 Format(TextView fmt);
148
150 Format(self_type &&that) = default;
152 Format(self_type const &) = delete;
153
157
159 explicit operator bool() const;
160
167 bool operator()(std::string_view &literal_v, Spec &spec);
168
180 static bool parse(TextView &fmt, std::string_view &literal, std::string_view &specifier);
181 };
182
184 static TextViewExtractor bind(TextView fmt);
185
189 int _idx = 0;
191 explicit operator bool() const;
192
199 bool operator()(std::string_view &literal_v, Spec &spec);
200 };
201
203 FormatExtractor bind() const;
204
206 bool is_literal() const;
207
208 using Container = std::vector<Spec>;
209 Container _items;
210
211 using iterator = Container::iterator;
212 using const_iterator = Container::const_iterator;
213
214 iterator
215 begin() {
216 return _items.begin();
217 }
218 iterator
219 end() {
220 return _items.end();
221 }
222 const_iterator
223 begin() const {
224 return _items.begin();
225 }
226 const_iterator
227 end() const {
228 return _items.end();
229 }
230};
231
232// Name binding - support for having format specifier names.
233
242
253public:
254 virtual ~NameBinding();
255
266 virtual BufferWriter &operator()(BufferWriter &w, Spec const &spec) const = 0;
267
268protected:
275 static BufferWriter &err_invalid_name(BufferWriter &w, Spec const &spec);
276};
277
284class NilBinding : public NameBinding {
285public:
288 BufferWriter &operator()(BufferWriter &, Spec const &) const override;
289};
290
299template <typename F> class NameMap {
300public:
302 using Generator = std::function<F>;
303
304protected:
305 using Map = std::unordered_map<std::string_view, Generator>;
306
307private:
308 using self_type = NameMap;
309public:
312
314 NameMap(std::initializer_list<std::tuple<std::string_view, Generator const &>> list);
315
321 self_type &assign(std::string_view const &name, Generator const &generator);
322
328 bool contains(std::string_view name);
329
330protected:
332 std::string_view localize(std::string_view const &name);
333
335 Map _map;
337};
338
345class ExternalNames : public NameMap<ExternalGeneratorSignature>, public NameBinding {
346 using self_type = ExternalNames;
347 using super_type = NameMap<ExternalGeneratorSignature>;
348 using Map = super_type::Map;
349
350public:
351 using super_type::super_type; // import constructors.
352
354 NameBinding const &bind() const;
355
357 BufferWriter &operator()(BufferWriter &w, const Spec &spec) const override;
358
360};
361
382template <typename T> class ContextNames : public NameMap<BufferWriter &(BufferWriter &, const Spec &, T &)> {
383private:
384 using self_type = ContextNames;
385 using super_type = NameMap<BufferWriter &(BufferWriter &, const Spec &, T &)>;
386 using Map = typename super_type::Map;
387
388public:
389 using context_type = T;
393 using ExternalGenerator = std::function<ExternalGeneratorSignature>;
394
395 using super_type::super_type; // inherit @c super_type constructors.
396
398 class Binding : public NameBinding {
399 public:
410 operator()(BufferWriter &w, const Spec &spec) const override {
411 return _names(w, spec, _ctx);
412 }
413
414 protected:
420 Binding(ContextNames const &names, context_type &ctx) : _ctx(ctx), _names(names) {}
421
423 ContextNames const &_names;
424
425 friend class ContextNames;
426 };
427
436 self_type &assign(std::string_view const &name, const ExternalGenerator &bg);
437
446 self_type &assign(std::string_view const &name, Generator const &generator);
447
455 Binding bind(context_type &context);
456
457protected:
469 virtual BufferWriter &operator()(BufferWriter &w, const Spec &spec, context_type &ctx) const;
470};
471
477
478// --------------- Implementation --------------------
480
481inline Spec::Align
483 return static_cast<Align>(Get_Prop()._data[static_cast<unsigned>(c)] & Property::ALIGN_MASK);
484}
485
486inline bool
488 return Get_Prop()._data[static_cast<unsigned>(c)] & Property::SIGN_CHAR;
489}
490
491inline bool
493 return Get_Prop()._data[static_cast<unsigned>(c)] & Property::TYPE_CHAR;
494}
495
496inline bool
498 return Get_Prop()._data[static_cast<unsigned>(c)] & Property::UPPER_TYPE_CHAR;
499}
500
501inline bool
503 return Get_Prop()._data[static_cast<unsigned>(c)] & Property::NUMERIC_TYPE_CHAR;
504}
505
506inline bool
508 return Get_Prop()._data[static_cast<unsigned>(_type)] & Property::NUMERIC_TYPE_CHAR;
509}
510
511inline bool
513 return Get_Prop()._data[static_cast<unsigned>(_type)] & Property::UPPER_TYPE_CHAR;
514}
515
516inline bool
518 return _type == 'p' || _type == 'P';
519}
520
521inline bool
523 return _type != INVALID_TYPE;
524}
525
526inline auto
528 return {fmt};
529}
530
531inline auto
533 return {_items};
534}
535
536inline Format::TextViewExtractor::operator bool() const {
537 return !_fmt.empty();
538}
539
540inline Format::FormatExtractor::operator bool() const {
541 return _idx < static_cast<int>(_fmt.size());
542}
543
545
546inline BufferWriter &
548 return w.print("{{~{}~}}", spec._name);
549}
550
551inline BufferWriter &
553 throw std::runtime_error("Use of nil bound names in BW formatting");
554}
555
556template <typename T>
557inline auto
559 return {*this, ctx};
560}
561
562template <typename T>
565 if (!spec._name.empty()) {
566 if (auto spot = super_type::_map.find(spec._name); spot != super_type::_map.end()) {
567 spot->second(w, spec, ctx);
568 } else {
570 }
571 }
572 return w;
573}
574
575template <typename F> NameMap<F>::NameMap() {}
576
577template <typename F> NameMap<F>::NameMap(std::initializer_list<std::tuple<std::string_view, const Generator &>> list) {
578 for (auto &&[name, generator] : list) {
579 this->assign(name, generator);
580 }
581}
582
583template <typename F>
584bool
585NameMap<F>::contains(std::string_view name) {
586 return _map.end() != _map.find(name);
587}
588
589template <typename F>
590std::string_view
591NameMap<F>::localize(std::string_view const &name) {
592 auto span = _arena.alloc_span<char>(name.size());
593 memcpy(span, name);
594 return std::string_view(span.data(), span.size());
595}
596
597template <typename F>
598auto
599NameMap<F>::assign(std::string_view const &name, Generator const &generator) -> self_type & {
600 _map[this->localize(name)] = generator;
601 return *this;
602}
603
604inline BufferWriter &
606 if (!spec._name.empty()) {
607 if (auto spot = _map.find(spec._name); spot != _map.end()) {
608 spot->second(w, spec);
609 } else {
610 this->err_invalid_name(w, spec);
611 }
612 }
613 return w;
614}
615
616inline NameBinding const &
618 return *this;
619}
620
621template <typename T>
622auto
623ContextNames<T>::assign(std::string_view const &name, ExternalGenerator const &bg) -> self_type & {
624 // wrap @a bg in a shim that discards the context so it can be stored in the map.
625 super_type::assign(name, [bg](BufferWriter &w, Spec const &spec, context_type &) -> BufferWriter & { return bg(w, spec); });
626 return *this;
627}
628
629template <typename T>
630auto
631ContextNames<T>::assign(std::string_view const &name, Generator const &g) -> self_type & {
632 super_type::assign(name, g);
633 return *this;
634}
635
637
640template <typename TUPLE> using ArgFormatterSignature = BufferWriter &(*)(BufferWriter &w, Spec const &, TUPLE const &args);
641
643void Err_Bad_Arg_Index(BufferWriter &w, int i, size_t n);
644
645// MSVC will expand the parameter pack inside a lambda but not gcc, so this indirection is required.
646
651template <typename TUPLE, size_t I>
653Arg_Formatter(BufferWriter &w, Spec const &spec, TUPLE const &args) {
654 return bwformat(w, spec, std::get<I>(args));
655}
656
661template <typename TUPLE, size_t... N>
662ArgFormatterSignature<TUPLE> *
663Get_Arg_Formatter_Array(std::index_sequence<N...>) {
664 static ArgFormatterSignature<TUPLE> fa[sizeof...(N)] = {&bwf::Arg_Formatter<TUPLE, N>...};
665 return fa;
666}
667
672void Adjust_Alignment(BufferWriter &aux, Spec const &spec);
673
684BufferWriter &Format_Integer(BufferWriter &w, Spec const &spec, uintmax_t n, bool negative_p);
685
696BufferWriter &Format_Float(BufferWriter &w, Spec const &spec, double f, bool negative_p);
697
706void Format_As_Hex(BufferWriter &w, std::string_view view, const char *digits);
707
708/* Capture support, which allows format extractors to capture arguments and consume them.
709 * This was built in order to support C style formatting, which needs to capture arguments
710 * to set the minimum width and/or the precision of other arguments.
711 *
712 * The key component is the ability to dynamically access an element of a tuple using
713 * @c std::any.
714 *
715 * Note: Much of this was originally in the meta support but it caused problems in use if
716 * the tuple header wasn't also included. I was unable to determine why, so this code doesn't
717 * depend on tuple explicitly.
718 */
720template <typename T> using TupleAccessorSignature = std::any (*)(T const &t);
721
723template <size_t IDX, typename T>
724std::any
725TupleAccessor(T const &t) {
726 return std::any(&std::get<IDX>(t));
727}
728
730template <typename T, size_t... N>
731std::array<TupleAccessorSignature<T>, sizeof...(N)> &
732Tuple_Accessor_Array(std::index_sequence<N...>) {
733 static std::array<TupleAccessorSignature<T>, sizeof...(N)> accessors = {&TupleAccessor<N>...};
734 return accessors;
735}
736
738template <typename T>
739std::any
740Tuple_Nth(T const &t, size_t idx) {
741 return Tuple_Accessor_Array<T>(std::make_index_sequence<std::tuple_size<T>::value>())[idx](t);
742}
743
747template <typename F>
748auto
749arg_capture(F &&, BufferWriter &, Spec const &, std::any &&, swoc::meta::CaseTag<0>) -> void {
750 throw std::runtime_error("Capture specification used in format extractor that does not support capture");
751}
752
753template <typename F>
754auto
755arg_capture(F &&f, BufferWriter &w, Spec const &spec, std::any &&value, swoc::meta::CaseTag<1>)
756 -> decltype(f.capture(w, spec, value)) {
757 return f.capture(w, spec, value);
758}
759
774template <typename EXTRACTOR, typename VIEW, typename SPEC>
775auto
776extractor_spec_type(bool (EXTRACTOR::*)(VIEW, SPEC)) -> SPEC {}
777
788class ArgPack {
789public:
790 virtual ~ArgPack() = default;
791
800 virtual std::any capture(unsigned idx) const = 0;
801
810 virtual BufferWriter &print(BufferWriter &w, Spec const &spec, unsigned idx) const = 0;
811
813 virtual unsigned count() const = 0;
814};
815
823template <typename... Args> class ArgTuple : public ArgPack {
824public:
826 ArgTuple(std::tuple<Args...> const &tuple) : _tuple(tuple) {}
827
828protected:
830 unsigned count() const override;
831
833 BufferWriter &print(BufferWriter &w, Spec const &spec, unsigned idx) const override;
834
836 std::any capture(unsigned idx) const override;
837
839 std::tuple<Args...> const &_tuple;
840};
841
842template <typename... Args>
843unsigned
845 return sizeof...(Args);
846}
847
848template <typename... Args>
850ArgTuple<Args...>::print(BufferWriter &w, Spec const &spec, unsigned idx) const {
851 static const auto _fa{bwf::Get_Arg_Formatter_Array<std::tuple<Args...>>(std::index_sequence_for<Args...>{})};
852 return _fa[idx](w, spec, _tuple);
853}
854
855template <typename... Args>
856std::any
857ArgTuple<Args...>::capture(unsigned idx) const {
858 return {Tuple_Nth(_tuple, idx)};
859}
860
861} // namespace bwf
862
863template <typename Binding, typename Extractor>
865BufferWriter::print_nfv(Binding &&names, Extractor &&ex, bwf::ArgPack const &args) {
866 using namespace std::literals;
867 // This gets the actual specifier type from the Extractor - it must be a subclass of @c bwf::Spec
868 // but this enables format extractors to use a subclass if additional data needs to be passed
869 // via the specifier.
870 using spec_type =
871 typename std::remove_reference<decltype(bwf::extractor_spec_type(&std::remove_reference<Extractor>::type::operator()))>::type;
872 int N = args.count();
873 int arg_idx = 0; // the next argument index to be processed.
874
875 // Parser is required to return @c false if there's no more data, @c true if something was parsed.
876 while (ex) {
877 std::string_view lit_v;
878 spec_type spec;
879 bool spec_p = ex(lit_v, spec);
880
881 // If there's a literal, just ship it.
882 if (lit_v.size()) {
883 this->write(lit_v);
884 }
885
886 if (spec_p) {
887 if (spec._name.size() == 0) {
888 spec._idx = arg_idx++;
889 }
890
891 while (true) {
892 size_t width = this->remaining();
893 if (spec._max < width) {
894 width = spec._max;
895 }
896
897 FixedBufferWriter lw{this->aux_data(), width};
898
899 if (0 <= spec._idx) {
900 if (spec._idx < N) {
901 if (spec._type == bwf::Spec::CAPTURE_TYPE) {
902 bwf::arg_capture(ex, lw, spec, args.capture(spec._idx), swoc::meta::CaseArg);
903 } else {
904 args.print(lw, spec, spec._idx);
905 }
906 } else {
907 bwf::Err_Bad_Arg_Index(lw, spec._idx, N);
908 }
909 } else if (spec._name.size()) {
910 names(lw, spec);
911 }
912 if (lw.extent()) {
913 bwf::Adjust_Alignment(lw, spec);
914 if (!this->commit(lw.extent())) {
915 continue;
916 }
917 }
918 break;
919 }
920 }
921 }
922 return *this;
923}
924
925template <typename... Args>
927BufferWriter::print(const TextView &fmt, Args &&...args) {
928 return this->print_nfv(bwf::Global_Names().bind(), bwf::Format::bind(fmt), bwf::ArgTuple{std::forward_as_tuple(args...)});
929}
930
931template <typename... Args>
933BufferWriter::print(bwf::Format const &fmt, Args &&...args) {
934 return this->print_nfv(bwf::Global_Names().bind(), fmt.bind(), bwf::ArgTuple{std::forward_as_tuple(args...)});
935}
936
937template <typename... Args>
939BufferWriter::print_v(TextView const &fmt, std::tuple<Args...> const &args) {
940 return this->print_nfv(bwf::Global_Names().bind(), bwf::Format::bind(fmt), bwf::ArgTuple{args});
941}
942
943template <typename... Args>
945BufferWriter::print_v(const bwf::Format &fmt, const std::tuple<Args...> &args) {
946 return this->print_nfv(bwf::Global_Names().bind(), fmt.bind(), bwf::ArgTuple{args});
947}
948
949template <typename Binding, typename Extractor>
951BufferWriter::print_nfv(Binding const &names, Extractor &&f) {
952 return print_nfv(names, f, bwf::ArgTuple{std::make_tuple()});
953}
954
955template <typename Binding>
957BufferWriter::print_n(Binding const &names, TextView const &fmt) {
958 return print_nfv(names, bwf::Format::bind(fmt), bwf::ArgTuple{std::make_tuple()});
959}
960
961inline MemSpan<char>
963 return {this->aux_data(), this->remaining()};
964}
965
966// ---- Formatting for specific types.
967
977BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv);
978
988BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, const void *ptr);
989
1000BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, MemSpan<void const> const &span);
1001
1015inline BufferWriter &
1016bwformat(BufferWriter &w, bwf::Spec const &spec, MemSpan<void> const &span) {
1017 return bwformat(w, spec, span.rebind<void const>());
1018}
1019
1020template <typename T>
1021BufferWriter &
1022bwformat(BufferWriter &w, bwf::Spec const &spec, MemSpan<T> const &span) {
1023 bwf::Spec s{spec};
1024 // If the precision isn't already specified, make it the size of the objects in the span.
1025 // This will break the output into blocks of that size.
1026 if (spec._prec <= 0) {
1027 s._prec = sizeof(T);
1028 }
1029 return bwformat(w, s, span.template rebind<void const>());
1030}
1031
1032template <size_t N>
1033BufferWriter &
1034bwformat(BufferWriter &w, bwf::Spec const &spec, const char (&a)[N]) {
1035 return bwformat(w, spec, std::string_view(a, N - 1));
1036}
1037
1038// Capture this explicitly so it doesn't go to any other pointer type.
1039inline BufferWriter &
1040bwformat(BufferWriter &w, bwf::Spec const &spec, std::nullptr_t) {
1041 return bwformat(w, spec, static_cast<void *>(nullptr));
1042}
1043
1044// Char pointer formatting
1045inline BufferWriter &
1046bwformat(BufferWriter &w, bwf::Spec const &spec, const char *v) {
1047 if (spec._type == 'x' || spec._type == 'X' || spec._type == 'p' || spec._type == 'P') {
1048 bwformat(w, spec, static_cast<const void *>(v));
1049 } else if (v != nullptr) {
1050 bwformat(w, spec, std::string_view(v));
1051 } else {
1052 bwformat(w, spec, nullptr);
1053 }
1054 return w;
1055}
1056// doc end
1057
1058inline BufferWriter &
1059bwformat(BufferWriter &w, bwf::Spec const &spec, std::string const &s) {
1060 return bwformat(w, spec, std::string_view{s});
1061}
1062
1063inline BufferWriter &
1064bwformat(BufferWriter &w, bwf::Spec const &spec, TextView tv) {
1065 return bwformat(w, spec, static_cast<std::string_view>(tv));
1066}
1067
1068template <typename X, typename V>
1069BufferWriter &
1070bwformat(BufferWriter &w, bwf::Spec const &, TransformView<X, V> &&view) {
1071 while (view)
1072 w.write(char(*(view++)));
1073 return w;
1074}
1075
1076template <typename F>
1077auto
1078bwformat(BufferWriter &w, bwf::Spec const &spec, F &&f) ->
1079 typename std::enable_if<std::is_floating_point_v<typename std::remove_reference_t<F>>, BufferWriter &>::type {
1080 return f < 0 ? bwf::Format_Float(w, spec, -f, true) : bwf::Format_Float(w, spec, f, false);
1081}
1082
1083/* Integer types.
1084
1085 Due to some oddities for MacOS building, need a bit more template magic here. The underlying
1086 integer rendering is in @c Format_Integer which takes @c intmax_t or @c uintmax_t. For @c
1087 bwformat templates are defined, one for signed and one for unsigned. These forward their argument
1088 to the internal renderer. To avoid additional ambiguity the template argument is checked with @c
1089 std::enable_if to invalidate the overload if the argument type isn't a signed / unsigned
1090 integer. One exception to this is @c char which is handled by a previous overload in order to
1091 treat the value as a character and not an integer. The overall benefit is this works for any set
1092 of integer types, rather tuning and hoping to get just the right set of overloads.
1093 */
1094
1095template <typename I>
1096auto
1097bwformat(BufferWriter &w, bwf::Spec const &spec, I &&i) ->
1098 typename std::enable_if<std::is_unsigned<typename std::remove_reference<I>::type>::value &&
1099 std::is_integral<typename std::remove_reference<I>::type>::value,
1100 BufferWriter &>::type {
1101 return bwf::Format_Integer(w, spec, i, false);
1102}
1103
1104template <typename I>
1105auto
1106bwformat(BufferWriter &w, bwf::Spec const &spec, I &&i) ->
1107 typename std::enable_if<std::is_signed<typename std::remove_reference<I>::type>::value &&
1108 std::is_integral<typename std::remove_reference<I>::type>::value,
1109 BufferWriter &>::type {
1110 bool neg_p = false;
1111 uintmax_t n = static_cast<uintmax_t>(i);
1112 if (i < 0) {
1113 n = static_cast<uintmax_t>(-i);
1114 neg_p = true;
1115 }
1116 return bwf::Format_Integer(w, spec, n, neg_p);
1117}
1118
1119inline BufferWriter &
1120bwformat(BufferWriter &w, bwf::Spec const &, char c) {
1121 return w.write(c);
1122}
1123
1124inline BufferWriter &
1125bwformat(BufferWriter &w, bwf::Spec const &spec, bool f) {
1126 using namespace std::literals;
1127 if ('s' == spec._type) {
1128 w.write(f ? "true"sv : "false"sv);
1129 } else if ('S' == spec._type) {
1130 w.write(f ? "TRUE"sv : "FALSE"sv);
1131 } else {
1132 bwf::Format_Integer(w, spec, static_cast<uintmax_t>(f), false);
1133 }
1134 return w;
1135}
1136
1137// std::string support
1154template <typename... Args>
1155std::string &
1156bwprint_v(std::string &s, TextView fmt, std::tuple<Args...> const &args) {
1157 auto const len = s.size(); // remember initial size
1158 auto printer = [&]() { return FixedBufferWriter(s.data(), s.capacity()).print_v(fmt, args).extent(); };
1159 size_t n = printer();
1160 s.resize(n); // always need to resize - if shorter, must clip pre-existing text.
1161 if (n > len) { // dropped data, try again.
1162 printer();
1163 }
1164 return s;
1165}
1166
1183template <typename... Args>
1184std::string &
1185bwprint(std::string &s, TextView fmt, Args &&...args) {
1186 return bwprint_v(s, fmt, std::forward_as_tuple(args...));
1187}
1188
1201template <typename... Args>
1202std::string &
1203bwappend(std::string &s, TextView fmt, Args &&...args) {
1204 auto const len = s.length(); // Text to preserve.
1205 auto const capacity = s.capacity(); // Working space.
1206 auto printer = [&]() { return FixedBufferWriter(s.data() + len, s.capacity() - len).print(fmt, args...).extent(); };
1207 // Resize first, otherwise capacity past @a len is cleared on @c resize.
1208 s.resize(capacity);
1209 auto n = printer() + len; // Get the final length.
1210 s.resize(n); // Adjust to correct string length.
1211 if (n > capacity) { // dropped data, write it again.
1212 printer();
1213 }
1214 return s;
1215}
1216
1218template <typename... Args>
1219auto
1220FixedBufferWriter::print(TextView fmt, Args &&...args) -> self_type & {
1221 return static_cast<self_type &>(this->super_type::print_v(fmt, std::forward_as_tuple(args...)));
1222}
1223
1224template <typename... Args>
1225auto
1226FixedBufferWriter::print_v(TextView fmt, std::tuple<Args...> const &args) -> self_type & {
1227 return static_cast<self_type &>(this->super_type::print_v(fmt, args));
1228}
1229
1230template <typename... Args>
1231auto
1232FixedBufferWriter::print(bwf::Format const &fmt, Args &&...args) -> self_type & {
1233 return static_cast<self_type &>(this->super_type::print_v(fmt, std::forward_as_tuple(args...)));
1234}
1235
1236template <typename... Args>
1237auto
1238FixedBufferWriter::print_v(bwf::Format const &fmt, std::tuple<Args...> const &args) -> self_type & {
1239 return static_cast<self_type &>(this->super_type::print_v(fmt, args));
1240}
1242
1243// Special case support for @c Scalar, because @c Scalar is a base utility for some other utilities
1244// there can be some unpleasant circularities if @c Scalar includes BufferWriter formatting. If the
1245// support is here then it's fine because anything using BWF for @c Scalar must include this header.
1246template <intmax_t N, typename C, typename T> class Scalar;
1247namespace detail {
1248template <typename T>
1249auto
1250tag_label(BufferWriter &, const bwf::Spec &, meta::CaseTag<0>) -> void {}
1251
1252template <typename T>
1253auto
1254tag_label(BufferWriter &w, const bwf::Spec &, meta::CaseTag<1>) -> decltype(T::label, meta::TypeFunc<void>()) {
1255 w.print("{}", T::label);
1256}
1257} // namespace detail
1258
1259template <intmax_t N, typename C, typename T>
1260BufferWriter &
1261bwformat(BufferWriter &w, bwf::Spec const &spec, Scalar<N, C, T> const &x) {
1262 bwformat(w, spec, x.value());
1263 if (!spec.has_numeric_type()) {
1264 detail::tag_label<T>(w, spec, meta::CaseArg);
1265 }
1266 return w;
1267}
1268
1269// Generically a stream operator is a formatter with the default specification.
1270template <typename V>
1271BufferWriter &
1272operator<<(BufferWriter &w, V &&v) {
1273 return bwformat(w, bwf::Spec::DEFAULT, std::forward<V>(v));
1274}
1275
1276// Basic format wrappers - these are here because they're used internally.
1277namespace bwf {
1285struct HexDump {
1286 std::string_view _view;
1287
1293 HexDump(void const *mem, size_t n) : _view(static_cast<char const *>(mem), n) {}
1294};
1295
1307template <typename T>
1308HexDump
1309As_Hex(T const &t) {
1310 return HexDump(&t, sizeof(T));
1311}
1312
1313} // namespace bwf
1314
1322BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::HexDump const &hex);
1323
1333inline BufferWriter &
1334bwformat(BufferWriter &w, bwf::Spec const &spec, BufferWriter const &ww) {
1335 return bwformat(w, spec, TextView(ww));
1336}
1337
1338template <typename T>
1339BufferWriter &
1340BufferWriter::format(bwf::Spec const &spec, T const &t) {
1341 return bwformat(*this, spec, t);
1342}
1343
1344template <typename T>
1346BufferWriter::format(bwf::Spec const &spec, T &&t) {
1347 return bwformat(*this, spec, t);
1348}
1349
1350}} // namespace swoc::SWOC_VERSION_NS
BufferWriter & Format_Float(BufferWriter &w, Spec const &spec, double f, bool negative_p)
Definition bw_format.cc:500
ExternalNames & Global_Names()
Definition bw_format.cc:33
void Err_Bad_Arg_Index(BufferWriter &w, int i, size_t n)
Internal error / reporting message generators.
Definition bw_format.cc:264
void Adjust_Alignment(BufferWriter &aux, Spec const &spec)
Definition bw_format.cc:276
auto arg_capture(F &&, BufferWriter &, Spec const &, std::any &&, swoc::meta::CaseTag< 0 >) -> void
Definition bwf_base.h:749
ArgFormatterSignature< TUPLE > * Get_Arg_Formatter_Array(std::index_sequence< N... >)
Definition bwf_base.h:663
BufferWriter &(*)(BufferWriter &w, Spec const &, TUPLE const &args) ArgFormatterSignature
— Formatting —
Definition bwf_base.h:640
std::any(*)(T const &t) TupleAccessorSignature
The signature for accessing an element of a tuple.
Definition bwf_base.h:720
std::any Tuple_Nth(T const &t, size_t idx)
Get the Nth element of the tuple as std::any.
Definition bwf_base.h:740
BufferWriter &(BufferWriter &w, Spec const &spec) ExternalGeneratorSignature
Definition bwf_base.h:241
std::array< TupleAccessorSignature< T >, sizeof...(N)> & Tuple_Accessor_Array(std::index_sequence< N... >)
Create and return an array of specialized accessors, indexed by tuple index.
Definition bwf_base.h:732
BufferWriter & Arg_Formatter(BufferWriter &w, Spec const &spec, TUPLE const &args)
Definition bwf_base.h:653
std::any TupleAccessor(T const &t)
Template access method.
Definition bwf_base.h:725
HexDump As_Hex(T const &t)
Definition bwf_base.h:1309
auto extractor_spec_type(bool(EXTRACTOR::*)(VIEW, SPEC)) -> SPEC
Definition bwf_base.h:776
virtual bool commit(size_t n)=0
BufferWriter & print(const TextView &fmt, Args &&...args)
Definition bwf_base.h:927
BufferWriter & print_nfv(Binding &&names, Extractor &&ex, bwf::ArgPack const &args)
Definition bwf_base.h:865
BufferWriter & format(bwf::Spec const &spec, T &&t)
Definition bwf_base.h:1346
BufferWriter & print_n(Binding const &names, TextView const &fmt)
Definition bwf_base.h:957
BufferWriter & print_v(const TextView &fmt, const std::tuple< Args... > &args)
Definition bwf_base.h:939
virtual size_t extent() const =0
size_t remaining() const
virtual BufferWriter & write(char c)=0
MemSpan< char > aux_span()
Definition bwf_base.h:962
virtual char * aux_data()
MemSpan< U > rebind() const
Definition MemSpan.h:1304
virtual unsigned count() const =0
Number of arguments in the pack.
virtual BufferWriter & print(BufferWriter &w, Spec const &spec, unsigned idx) const =0
virtual std::any capture(unsigned idx) const =0
Force virtual destructor for subclasses.
std::any capture(unsigned idx) const override
Capture the idx argument for later use.
Definition bwf_base.h:857
ArgTuple(std::tuple< Args... > const &tuple)
Construct from a tuple.
Definition bwf_base.h:826
BufferWriter & print(BufferWriter &w, Spec const &spec, unsigned idx) const override
Generate formatted output on w for argument at idx.
Definition bwf_base.h:850
unsigned count() const override
Numnber of arguments in the tuple.
Definition bwf_base.h:844
std::tuple< Args... > const & _tuple
The source arguments.
Definition bwf_base.h:839
Specialized binding for names in an instance of ContextNames.
Definition bwf_base.h:398
BufferWriter & operator()(BufferWriter &w, const Spec &spec) const override
Definition bwf_base.h:410
context_type & _ctx
Context for generators.
Definition bwf_base.h:422
ContextNames const & _names
Base set of names.
Definition bwf_base.h:423
Binding(ContextNames const &names, context_type &ctx)
Definition bwf_base.h:420
virtual BufferWriter & operator()(BufferWriter &w, const Spec &spec, context_type &ctx) const
Definition bwf_base.h:564
self_type & assign(std::string_view const &name, const ExternalGenerator &bg)
Definition bwf_base.h:623
std::function< ExternalGeneratorSignature > ExternalGenerator
Signature for an external (context-free) generator.
Definition bwf_base.h:393
Binding bind(context_type &context)
Definition bwf_base.h:558
typename super_type::Generator Generator
Functional type for a generator.
Definition bwf_base.h:391
BufferWriter & operator()(BufferWriter &w, const Spec &spec) const override
Bound name access.
Definition bwf_base.h:605
NameBinding const & bind() const
The bound accessor is this class.
Definition bwf_base.h:617
virtual BufferWriter & operator()(BufferWriter &w, Spec const &spec) const =0
virtual ~NameBinding()
Force virtual destructor.
static BufferWriter & err_invalid_name(BufferWriter &w, Spec const &spec)
— Names / Generators —
Definition bwf_base.h:547
bool contains(std::string_view name)
Definition bwf_base.h:585
std::string_view localize(std::string_view const &name)
Copy name in to local storage and return a view of it.
Definition bwf_base.h:591
std::function< F > Generator
Signature for generators.
Definition bwf_base.h:302
self_type & assign(std::string_view const &name, Generator const &generator)
Definition bwf_base.h:599
NameMap()
Construct an empty container.
Definition bwf_base.h:575
NameMap(std::initializer_list< std::tuple< std::string_view, Generator const & > > list)
Construct and assign the names and generators in list.
Definition bwf_base.h:577
BufferWriter & operator()(BufferWriter &, Spec const &) const override
Definition bwf_base.h:552
For template deduction guides.
Definition ArenaWriter.cc:9
BufferWriter & bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv)
Definition bw_format.cc:649
std::string & bwprint_v(std::string &s, TextView fmt, std::tuple< Args... > const &args)
Definition bwf_base.h:1156
std::string & bwprint(std::string &s, TextView fmt, Args &&...args)
Definition bwf_base.h:1185
std::string & bwappend(std::string &s, TextView fmt, Args &&...args)
Definition bwf_base.h:1203
void * memcpy(void *dst, const std::string_view &src)
Extraction support for pre-parsed format strings.
Definition bwf_base.h:187
MemSpan< Spec const > _fmt
Parsed format string.
Definition bwf_base.h:188
bool operator()(std::string_view &literal_v, Spec &spec)
Definition bw_format.cc:251
Extraction support for TextView.
Definition bwf_base.h:155
TextView _fmt
Format string.
Definition bwf_base.h:156
bool operator()(std::string_view &literal_v, Spec &spec)
Definition bw_format.cc:240
static bool parse(TextView &fmt, std::string_view &literal, std::string_view &specifier)
Definition bw_format.cc:195
Format self_type
Self reference type.
Definition bwf_base.h:141
Format(self_type &&that)=default
Move constructor.
Format(self_type const &)=delete
No copy.
bool is_literal() const
Definition bw_format.cc:635
Container _items
Items from format string.
Definition bwf_base.h:209
static TextViewExtractor bind(TextView fmt)
Wrap the format string in an extractor.
Definition bwf_base.h:527
Format()=default
Empty format.
std::string_view _view
A view of the memory to dump.
Definition bwf_base.h:1286
HexDump(void const *mem, size_t n)
Definition bwf_base.h:1293
Handrolled initialization the character syntactic property data.
Definition bwf_base.h:111
static constexpr uint8_t UPPER_TYPE_CHAR
Upper case flag.
Definition bwf_base.h:118
static constexpr uint8_t ALIGN_MASK
Flag mask values.
Definition bwf_base.h:116
static constexpr uint8_t TYPE_CHAR
A valid type character.
Definition bwf_base.h:117
static constexpr uint8_t NUMERIC_TYPE_CHAR
Numeric output.
Definition bwf_base.h:119
static constexpr uint8_t SIGN_CHAR
Is sign character.
Definition bwf_base.h:120
uint8_t _data[0x100]
Flag storage, indexed by character value.
Definition bwf_base.h:114
bool has_upper_case_type() const
Check if the type in this is an upper case variant.
Definition bwf_base.h:512
bool _radix_lead_p
Print leading radix indication.
Definition bwf_base.h:70
static constexpr char INVALID_TYPE
Type for missing or invalid specifier.
Definition bwf_base.h:41
int _prec
Precision.
Definition bwf_base.h:73
static const Property & Get_Prop()
Character property map.
Definition bwf_base.h:123
static constexpr char SIGN_NEG
Print a sign character only for negative values (default).
Definition bwf_base.h:47
unsigned int _max
Maximum width.
Definition bwf_base.h:74
static constexpr char DEFAULT_TYPE
Default format type.
Definition bwf_base.h:40
unsigned int _min
Minimum width.
Definition bwf_base.h:72
static bool is_type(char c)
Validate c is a specifier type indicator.
Definition bwf_base.h:492
constexpr Spec()
Constructor a default instance.
Definition bwf_base.h:50
int _idx
Positional "name" of the specification.
Definition bwf_base.h:75
Align align_of(char c)
Validate character is alignment character and return the appropriate enum value.
Definition bwf_base.h:482
bool is_sign(char c)
Validate is sign indicator.
Definition bwf_base.h:487
Align
Flag for how to align the output inside a limited width field.
Definition bwf_base.h:62
@ RIGHT
Right alignment '>'.
Definition bwf_base.h:65
@ SIGN
Align plus/minus sign before numeric fill. '='.
Definition bwf_base.h:67
@ LEFT
Left alignment '<'.
Definition bwf_base.h:64
@ NONE
No alignment.
Definition bwf_base.h:63
@ CENTER
Center alignment '^'.
Definition bwf_base.h:66
static constexpr char SIGN_ALWAYS
Always print a sign character.
Definition bwf_base.h:45
char _fill
Fill character.
Definition bwf_base.h:59
static bool is_numeric_type(char c)
Check if the type flag is numeric.
Definition bwf_base.h:502
static const self_type DEFAULT
Global default instance for use in situations where a format specifier isn't available.
Definition bwf_base.h:80
static bool is_upper_case_type(char c)
Check if the type is an upper case variant.
Definition bwf_base.h:497
static constexpr char SIGN_NEVER
Never print a sign character.
Definition bwf_base.h:46
bool has_pointer_type() const
Check if the type is a raw pointer.
Definition bwf_base.h:517
static constexpr char LITERAL_TYPE
Internal type to mark a literal.
Definition bwf_base.h:42
char _type
Type / radix indicator.
Definition bwf_base.h:69
bool has_numeric_type() const
Check if the type in this is numeric.
Definition bwf_base.h:507
static constexpr char CAPTURE_TYPE
Internal type to mark a capture.
Definition bwf_base.h:43
Spec self_type
Self reference type.
Definition bwf_base.h:38
bool has_valid_type() const
Check if the type is valid.
Definition bwf_base.h:522
std::string_view _name
Name of the specification.
Definition bwf_base.h:76
std::string_view _ext
Extension if provided.
Definition bwf_base.h:77
Case hierarchy.
Definition swoc_meta.h:66