14#include <unordered_map>
30namespace swoc {
inline namespace SWOC_VERSION_NS {
68 } _align = Align::NONE;
74 unsigned int _max = std::numeric_limits<unsigned int>::max();
159 explicit operator bool()
const;
180 static bool parse(
TextView &fmt, std::string_view &literal, std::string_view &specifier);
191 explicit operator bool()
const;
208 using Container = std::vector<Spec>;
211 using iterator = Container::iterator;
212 using const_iterator = Container::const_iterator;
224 return _items.begin();
305 using Map = std::unordered_map<std::string_view, Generator>;
314 NameMap(std::initializer_list<std::tuple<std::string_view, Generator const &>> list);
332 std::string_view
localize(std::string_view
const &name);
348 using Map = super_type::Map;
351 using super_type::super_type;
382template <
typename T>
class ContextNames :
public NameMap<BufferWriter &(BufferWriter &, const Spec &, T &)> {
386 using Map =
typename super_type::Map;
395 using super_type::super_type;
425 friend class ContextNames;
446 self_type &
assign(std::string_view
const &name,
Generator const &generator);
536inline Format::TextViewExtractor::operator bool()
const {
537 return !
_fmt.empty();
540inline Format::FormatExtractor::operator bool()
const {
541 return _idx < static_cast<int>(
_fmt.size());
553 throw std::runtime_error(
"Use of nil bound names in BW formatting");
565 if (!spec.
_name.empty()) {
567 spot->second(w, spec, ctx);
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);
586 return _map.end() !=
_map.find(name);
592 auto span =
_arena.alloc_span<
char>(name.size());
594 return std::string_view(span.data(), span.size());
606 if (!spec.
_name.empty()) {
608 spot->second(w, spec);
651template <
typename TUPLE,
size_t I>
654 return bwformat(w, spec, std::get<I>(args));
661template <
typename TUPLE,
size_t... N>
662ArgFormatterSignature<TUPLE> *
706void Format_As_Hex(
BufferWriter &w, std::string_view view,
const char *digits);
723template <
size_t IDX,
typename T>
726 return std::any(&std::get<IDX>(t));
730template <
typename T,
size_t... N>
731std::array<TupleAccessorSignature<T>,
sizeof...(N)> &
733 static std::array<TupleAccessorSignature<T>,
sizeof...(N)> accessors = {&
TupleAccessor<N>...};
750 throw std::runtime_error(
"Capture specification used in format extractor that does not support capture");
756 ->
decltype(f.capture(w, spec, value)) {
757 return f.capture(w, spec, value);
774template <
typename EXTRACTOR,
typename VIEW,
typename SPEC>
800 virtual std::any
capture(
unsigned idx)
const = 0;
830 unsigned count()
const override;
836 std::any capture(
unsigned idx)
const override;
842template <
typename... Args>
845 return sizeof...(Args);
848template <
typename... Args>
852 return _fa[idx](w, spec,
_tuple);
855template <
typename... Args>
863template <
typename Binding,
typename Extractor>
866 using namespace std::literals;
871 typename std::remove_reference<
decltype(
bwf::extractor_spec_type(&std::remove_reference<Extractor>::type::operator()))>::type;
872 int N = args.
count();
877 std::string_view lit_v;
879 bool spec_p = ex(lit_v, spec);
887 if (spec._name.size() == 0) {
888 spec._idx = arg_idx++;
893 if (spec._max < width) {
899 if (0 <= spec._idx) {
904 args.
print(lw, spec, spec._idx);
909 }
else if (spec._name.size()) {
914 if (!this->
commit(lw.extent())) {
925template <
typename... Args>
931template <
typename... Args>
937template <
typename... Args>
943template <
typename... Args>
949template <
typename Binding,
typename Extractor>
955template <
typename Binding>
1020template <
typename T>
1022bwformat(BufferWriter &w, bwf::Spec
const &spec, MemSpan<T>
const &span) {
1026 if (spec._prec <= 0) {
1027 s._prec =
sizeof(T);
1029 return bwformat(w, s, span.template rebind<void const>());
1034bwformat(BufferWriter &w, bwf::Spec
const &spec,
const char (&a)[N]) {
1035 return bwformat(w, spec, std::string_view(a, N - 1));
1039inline BufferWriter &
1040bwformat(BufferWriter &w, bwf::Spec
const &spec, std::nullptr_t) {
1041 return bwformat(w, spec,
static_cast<void *
>(
nullptr));
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));
1058inline BufferWriter &
1059bwformat(BufferWriter &w, bwf::Spec
const &spec, std::string
const &s) {
1060 return bwformat(w, spec, std::string_view{s});
1063inline BufferWriter &
1064bwformat(BufferWriter &w, bwf::Spec
const &spec, TextView tv) {
1065 return bwformat(w, spec,
static_cast<std::string_view
>(tv));
1068template <
typename X,
typename V>
1070bwformat(BufferWriter &w, bwf::Spec
const &, TransformView<X, V> &&view) {
1072 w.
write(
char(*(view++)));
1076template <
typename F>
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);
1095template <
typename I>
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);
1104template <
typename I>
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 {
1111 uintmax_t n =
static_cast<uintmax_t
>(i);
1113 n =
static_cast<uintmax_t
>(-i);
1116 return bwf::Format_Integer(w, spec, n, neg_p);
1119inline BufferWriter &
1120bwformat(BufferWriter &w, bwf::Spec
const &,
char c) {
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);
1132 bwf::Format_Integer(w, spec,
static_cast<uintmax_t
>(f),
false);
1154template <
typename... Args>
1157 auto const len = s.size();
1159 size_t n = printer();
1183template <
typename... Args>
1186 return bwprint_v(s, fmt, std::forward_as_tuple(args...));
1201template <
typename... Args>
1204 auto const len = s.length();
1205 auto const capacity = s.capacity();
1209 auto n = printer() + len;
1218template <
typename... Args>
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...)));
1224template <
typename... Args>
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));
1230template <
typename... Args>
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...)));
1236template <
typename... Args>
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));
1246template <
intmax_t N,
typename C,
typename T>
class Scalar;
1248template <
typename T>
1250tag_label(BufferWriter &,
const bwf::Spec &, meta::CaseTag<0>) ->
void {}
1252template <
typename T>
1254tag_label(BufferWriter &w,
const bwf::Spec &, meta::CaseTag<1>) ->
decltype(T::label, meta::TypeFunc<void>()) {
1255 w.print(
"{}", T::label);
1259template <
intmax_t N,
typename C,
typename T>
1261bwformat(BufferWriter &w, bwf::Spec
const &spec, Scalar<N, C, T>
const &x) {
1263 if (!spec.has_numeric_type()) {
1264 detail::tag_label<T>(w, spec, meta::CaseArg);
1270template <
typename V>
1272operator<<(BufferWriter &w, V &&v) {
1273 return bwformat(w, bwf::Spec::DEFAULT, std::forward<V>(v));
1293 HexDump(
void const *mem,
size_t n) :
_view(static_cast<char const *>(mem), n) {}
1307template <
typename T>
1310 return HexDump(&t,
sizeof(T));
1322BufferWriter &bwformat(BufferWriter &w, bwf::Spec
const &spec, bwf::HexDump
const &hex);
1333inline BufferWriter &
1338template <
typename T>
1344template <
typename T>
auto arg_capture(F &&, BufferWriter &, Spec const &, std::any &&, swoc::meta::CaseTag< 0 >) -> void
ArgFormatterSignature< TUPLE > * Get_Arg_Formatter_Array(std::index_sequence< N... >)
BufferWriter &(*)(BufferWriter &w, Spec const &, TUPLE const &args) ArgFormatterSignature
— Formatting —
std::any(*)(T const &t) TupleAccessorSignature
The signature for accessing an element of a tuple.
std::any Tuple_Nth(T const &t, size_t idx)
Get the Nth element of the tuple as std::any.
BufferWriter &(BufferWriter &w, Spec const &spec) ExternalGeneratorSignature
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.
BufferWriter & Arg_Formatter(BufferWriter &w, Spec const &spec, TUPLE const &args)
std::any TupleAccessor(T const &t)
Template access method.
HexDump As_Hex(T const &t)
auto extractor_spec_type(bool(EXTRACTOR::*)(VIEW, SPEC)) -> SPEC
virtual bool commit(size_t n)=0
BufferWriter & print(const TextView &fmt, Args &&...args)
BufferWriter & print_nfv(Binding &&names, Extractor &&ex, bwf::ArgPack const &args)
BufferWriter & format(bwf::Spec const &spec, T &&t)
BufferWriter & print_n(Binding const &names, TextView const &fmt)
BufferWriter & print_v(const TextView &fmt, const std::tuple< Args... > &args)
virtual size_t extent() const =0
virtual BufferWriter & write(char c)=0
MemSpan< char > aux_span()
virtual char * aux_data()
MemSpan< U > rebind() const
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.
ArgTuple(std::tuple< Args... > const &tuple)
Construct from a tuple.
BufferWriter & print(BufferWriter &w, Spec const &spec, unsigned idx) const override
Generate formatted output on w for argument at idx.
unsigned count() const override
Numnber of arguments in the tuple.
std::tuple< Args... > const & _tuple
The source arguments.
Specialized binding for names in an instance of ContextNames.
BufferWriter & operator()(BufferWriter &w, const Spec &spec) const override
context_type & _ctx
Context for generators.
ContextNames const & _names
Base set of names.
Binding(ContextNames const &names, context_type &ctx)
virtual BufferWriter & operator()(BufferWriter &w, const Spec &spec, context_type &ctx) const
self_type & assign(std::string_view const &name, const ExternalGenerator &bg)
std::function< ExternalGeneratorSignature > ExternalGenerator
Signature for an external (context-free) generator.
Binding bind(context_type &context)
typename super_type::Generator Generator
Functional type for a generator.
BufferWriter & operator()(BufferWriter &w, const Spec &spec) const override
Bound name access.
NameBinding const & bind() const
The bound accessor is this class.
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 —
bool contains(std::string_view name)
std::string_view localize(std::string_view const &name)
Copy name in to local storage and return a view of it.
std::function< F > Generator
Signature for generators.
self_type & assign(std::string_view const &name, Generator const &generator)
NameMap()
Construct an empty container.
NameMap(std::initializer_list< std::tuple< std::string_view, Generator const & > > list)
Construct and assign the names and generators in list.
BufferWriter & operator()(BufferWriter &, Spec const &) const override
For template deduction guides.
BufferWriter & bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv)
std::string & bwprint_v(std::string &s, TextView fmt, std::tuple< Args... > const &args)
std::string & bwprint(std::string &s, TextView fmt, Args &&...args)
std::string & bwappend(std::string &s, TextView fmt, Args &&...args)
void * memcpy(void *dst, const std::string_view &src)
std::string_view _view
A view of the memory to dump.
HexDump(void const *mem, size_t n)
Handrolled initialization the character syntactic property data.
static constexpr uint8_t UPPER_TYPE_CHAR
Upper case flag.
static constexpr uint8_t ALIGN_MASK
Flag mask values.
static constexpr uint8_t TYPE_CHAR
A valid type character.
static constexpr uint8_t NUMERIC_TYPE_CHAR
Numeric output.
static constexpr uint8_t SIGN_CHAR
Is sign character.
uint8_t _data[0x100]
Flag storage, indexed by character value.
bool has_upper_case_type() const
Check if the type in this is an upper case variant.
bool _radix_lead_p
Print leading radix indication.
static constexpr char INVALID_TYPE
Type for missing or invalid specifier.
static const Property & Get_Prop()
Character property map.
static constexpr char SIGN_NEG
Print a sign character only for negative values (default).
unsigned int _max
Maximum width.
static constexpr char DEFAULT_TYPE
Default format type.
unsigned int _min
Minimum width.
static bool is_type(char c)
Validate c is a specifier type indicator.
constexpr Spec()
Constructor a default instance.
int _idx
Positional "name" of the specification.
Align align_of(char c)
Validate character is alignment character and return the appropriate enum value.
bool is_sign(char c)
Validate is sign indicator.
Align
Flag for how to align the output inside a limited width field.
@ RIGHT
Right alignment '>'.
@ SIGN
Align plus/minus sign before numeric fill. '='.
@ LEFT
Left alignment '<'.
@ CENTER
Center alignment '^'.
static constexpr char SIGN_ALWAYS
Always print a sign character.
char _fill
Fill character.
static bool is_numeric_type(char c)
Check if the type flag is numeric.
static const self_type DEFAULT
Global default instance for use in situations where a format specifier isn't available.
static bool is_upper_case_type(char c)
Check if the type is an upper case variant.
static constexpr char SIGN_NEVER
Never print a sign character.
bool has_pointer_type() const
Check if the type is a raw pointer.
static constexpr char LITERAL_TYPE
Internal type to mark a literal.
char _type
Type / radix indicator.
bool has_numeric_type() const
Check if the type in this is numeric.
static constexpr char CAPTURE_TYPE
Internal type to mark a capture.
Spec self_type
Self reference type.
bool has_valid_type() const
Check if the type is valid.
std::string_view _name
Name of the specification.
std::string_view _ext
Extension if provided.