bind.cc
Go to the documentation of this file.
2 
3 #include <cerrno>
4 #include <limits>
5 #include <sstream>
6 #include <string>
7 
8 namespace absl {
9 namespace str_format_internal {
10 
11 namespace {
12 
13 inline bool BindFromPosition(int position, int* value,
15  assert(position > 0);
16  if (static_cast<size_t>(position) > pack.size()) {
17  return false;
18  }
19  // -1 because positions are 1-based
20  return FormatArgImplFriend::ToInt(pack[position - 1], value);
21 }
22 
23 class ArgContext {
24  public:
25  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
26 
27  // Fill 'bound' with the results of applying the context's argument pack
28  // to the specified 'unbound'. We synthesize a BoundConversion by
29  // lining up a UnboundConversion with a user argument. We also
30  // resolve any '*' specifiers for width and precision, so after
31  // this call, 'bound' has all the information it needs to be formatted.
32  // Returns false on failure.
33  bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
34 
35  private:
37 };
38 
39 inline bool ArgContext::Bind(const UnboundConversion* unbound,
40  BoundConversion* bound) {
41  const FormatArgImpl* arg = nullptr;
42  int arg_position = unbound->arg_position;
43  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
44  arg = &pack_[arg_position - 1]; // 1-based
45 
46  if (!unbound->flags.basic) {
47  int width = unbound->width.value();
48  bool force_left = false;
49  if (unbound->width.is_from_arg()) {
50  if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
51  return false;
52  if (width < 0) {
53  // "A negative field width is taken as a '-' flag followed by a
54  // positive field width."
55  force_left = true;
56  // Make sure we don't overflow the width when negating it.
57  width = -std::max(width, -std::numeric_limits<int>::max());
58  }
59  }
60 
61  int precision = unbound->precision.value();
62  if (unbound->precision.is_from_arg()) {
63  if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
64  pack_))
65  return false;
66  }
67 
68  bound->set_width(width);
69  bound->set_precision(precision);
70  bound->set_flags(unbound->flags);
71  if (force_left)
72  bound->set_left(true);
73  } else {
74  bound->set_flags(unbound->flags);
75  bound->set_width(-1);
76  bound->set_precision(-1);
77  }
78 
79  bound->set_length_mod(unbound->length_mod);
80  bound->set_conv(unbound->conv);
81  bound->set_arg(arg);
82  return true;
83 }
84 
85 template <typename Converter>
86 class ConverterConsumer {
87  public:
88  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
89  : converter_(converter), arg_context_(pack) {}
90 
91  bool Append(string_view s) {
92  converter_.Append(s);
93  return true;
94  }
95  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
96  BoundConversion bound;
97  if (!arg_context_.Bind(&conv, &bound)) return false;
98  return converter_.ConvertOne(bound, conv_string);
99  }
100 
101  private:
102  Converter converter_;
103  ArgContext arg_context_;
104 };
105 
106 template <typename Converter>
107 bool ConvertAll(const UntypedFormatSpecImpl format,
108  absl::Span<const FormatArgImpl> args, Converter converter) {
109  if (format.has_parsed_conversion()) {
110  return format.parsed_conversion()->ProcessFormat(
111  ConverterConsumer<Converter>(converter, args));
112  } else {
113  return ParseFormatString(format.str(),
114  ConverterConsumer<Converter>(converter, args));
115  }
116 }
117 
118 class DefaultConverter {
119  public:
120  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
121 
122  void Append(string_view s) const { sink_->Append(s); }
123 
124  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
125  return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
126  }
127 
128  private:
129  FormatSinkImpl* sink_;
130 };
131 
132 class SummarizingConverter {
133  public:
134  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
135 
136  void Append(string_view s) const { sink_->Append(s); }
137 
138  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
139  UntypedFormatSpecImpl spec("%d");
140 
141  std::ostringstream ss;
142  ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags();
143  if (bound.width() >= 0) ss << bound.width();
144  if (bound.precision() >= 0) ss << "." << bound.precision();
145  ss << bound.length_mod() << bound.conv() << "}";
146  Append(ss.str());
147  return true;
148  }
149 
150  private:
151  FormatSinkImpl* sink_;
152 };
153 
154 } // namespace
155 
156 bool BindWithPack(const UnboundConversion* props,
158  BoundConversion* bound) {
159  return ArgContext(pack).Bind(props, bound);
160 }
161 
164  typedef SummarizingConverter Converter;
166  {
167  // inner block to destroy sink before returning out. It ensures a last
168  // flush.
169  FormatSinkImpl sink(&out);
170  if (!ConvertAll(format, args, Converter(&sink))) {
171  return "";
172  }
173  }
174  return out;
175 }
176 
180  FormatSinkImpl sink(raw_sink);
181  using Converter = DefaultConverter;
182  return ConvertAll(format, args, Converter(&sink));
183 }
184 
185 std::ostream& Streamable::Print(std::ostream& os) const {
186  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
187  return os;
188 }
189 
192  size_t orig = out->size();
193  if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
194  out->erase(orig);
195  }
196  return *out;
197 }
198 
199 int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
201  FILERawSink sink(output);
202  if (!FormatUntyped(&sink, format, args)) {
203  errno = EINVAL;
204  return -1;
205  }
206  if (sink.error()) {
207  errno = sink.error();
208  return -1;
209  }
210  if (sink.count() > std::numeric_limits<int>::max()) {
211  errno = EFBIG;
212  return -1;
213  }
214  return static_cast<int>(sink.count());
215 }
216 
217 int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
219  BufferRawSink sink(output, size ? size - 1 : 0);
220  if (!FormatUntyped(&sink, format, args)) {
221  errno = EINVAL;
222  return -1;
223  }
224  size_t total = sink.total_written();
225  if (size) output[std::min(total, size - 1)] = 0;
226  return static_cast<int>(total);
227 }
228 
229 } // namespace str_format_internal
230 } // namespace absl
int FprintF(std::FILE *output, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: bind.cc:199
absl::Span< const FormatArgImpl > pack_
Definition: bind.cc:36
Converter converter_
Definition: bind.cc:102
FormatSinkImpl * sink_
Definition: bind.cc:129
ArgContext arg_context_
Definition: bind.cc:103
#define ABSL_PREDICT_FALSE(x)
Definition: optimization.h:177
std::string Summarize(const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: bind.cc:162
std::vector< std::string > args_
Definition: parse.cc:130
Definition: algorithm.h:29
constexpr size_type size() const noexcept
Definition: span.h:261
size_t value
int SnprintF(char *output, size_t size, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: bind.cc:217
std::string format(const std::string &, const time_point< seconds > &, const femtoseconds &, const time_zone &)
bool BindWithPack(const UnboundConversion *props, absl::Span< const FormatArgImpl > pack, BoundConversion *bound)
Definition: bind.cc:156
static bool Convert(Arg arg, str_format_internal::ConversionSpec conv, FormatSinkImpl *out)
Definition: arg.h:207
static bool ToInt(Arg arg, int *out)
Definition: arg.h:200
bool ParseFormatString(string_view src, Consumer consumer)
Definition: parser.h:117
uintptr_t size
bool FormatUntyped(FormatRawSinkImpl raw_sink, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: bind.cc:177
void * arg
Definition: mutex.cc:292
std::string & AppendPack(std::string *out, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: bind.cc:190
static char * Append(char *out, const AlphaNum &x)
Definition: str_cat.cc:88
char * out
Definition: mutex.h:1013
std::ostream & Print(std::ostream &os) const
Definition: bind.cc:185


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:19:56