abseil-cpp/absl/strings/internal/str_format/bind.cc
Go to the documentation of this file.
1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/strings/internal/str_format/bind.h"
16 
17 #include <cerrno>
18 #include <limits>
19 #include <sstream>
20 #include <string>
21 
22 namespace absl {
24 namespace str_format_internal {
25 
26 namespace {
27 
28 inline bool BindFromPosition(int position, int* value,
30  assert(position > 0);
31  if (static_cast<size_t>(position) > pack.size()) {
32  return false;
33  }
34  // -1 because positions are 1-based
35  return FormatArgImplFriend::ToInt(pack[position - 1], value);
36 }
37 
38 class ArgContext {
39  public:
40  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
41 
42  // Fill 'bound' with the results of applying the context's argument pack
43  // to the specified 'unbound'. We synthesize a BoundConversion by
44  // lining up a UnboundConversion with a user argument. We also
45  // resolve any '*' specifiers for width and precision, so after
46  // this call, 'bound' has all the information it needs to be formatted.
47  // Returns false on failure.
48  bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
49 
50  private:
52 };
53 
54 inline bool ArgContext::Bind(const UnboundConversion* unbound,
55  BoundConversion* bound) {
56  const FormatArgImpl* arg = nullptr;
57  int arg_position = unbound->arg_position;
58  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
59  arg = &pack_[arg_position - 1]; // 1-based
60 
61  if (unbound->flags != Flags::kBasic) {
62  int width = unbound->width.value();
63  bool force_left = false;
64  if (unbound->width.is_from_arg()) {
65  if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
66  return false;
67  if (width < 0) {
68  // "A negative field width is taken as a '-' flag followed by a
69  // positive field width."
70  force_left = true;
71  // Make sure we don't overflow the width when negating it.
73  }
74  }
75 
76  int precision = unbound->precision.value();
77  if (unbound->precision.is_from_arg()) {
78  if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
79  pack_))
80  return false;
81  }
82 
85 
86  if (force_left) {
88  bound);
89  } else {
90  FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
91  }
92  } else {
93  FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
96  }
98  bound->set_arg(arg);
99  return true;
100 }
101 
102 template <typename Converter>
103 class ConverterConsumer {
104  public:
105  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
106  : converter_(converter), arg_context_(pack) {}
107 
108  bool Append(string_view s) {
109  converter_.Append(s);
110  return true;
111  }
112  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
113  BoundConversion bound;
114  if (!arg_context_.Bind(&conv, &bound)) return false;
115  return converter_.ConvertOne(bound, conv_string);
116  }
117 
118  private:
119  Converter converter_;
120  ArgContext arg_context_;
121 };
122 
123 template <typename Converter>
124 bool ConvertAll(const UntypedFormatSpecImpl format,
126  if (format.has_parsed_conversion()) {
127  return format.parsed_conversion()->ProcessFormat(
128  ConverterConsumer<Converter>(converter, args));
129  } else {
130  return ParseFormatString(format.str(),
131  ConverterConsumer<Converter>(converter, args));
132  }
133 }
134 
135 class DefaultConverter {
136  public:
137  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
138 
139  void Append(string_view s) const { sink_->Append(s); }
140 
141  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
142  return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
143  }
144 
145  private:
146  FormatSinkImpl* sink_;
147 };
148 
149 class SummarizingConverter {
150  public:
151  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
152 
153  void Append(string_view s) const { sink_->Append(s); }
154 
155  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
156  UntypedFormatSpecImpl spec("%d");
157 
158  std::ostringstream ss;
159  ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
161  if (bound.width() >= 0) ss << bound.width();
162  if (bound.precision() >= 0) ss << "." << bound.precision();
163  ss << bound.conversion_char() << "}";
164  Append(ss.str());
165  return true;
166  }
167 
168  private:
169  FormatSinkImpl* sink_;
170 };
171 
172 } // namespace
173 
174 bool BindWithPack(const UnboundConversion* props,
176  BoundConversion* bound) {
177  return ArgContext(pack).Bind(props, bound);
178 }
179 
182  typedef SummarizingConverter Converter;
184  {
185  // inner block to destroy sink before returning out. It ensures a last
186  // flush.
188  if (!ConvertAll(format, args, Converter(&sink))) {
189  return "";
190  }
191  }
192  return out;
193 }
194 
198  FormatSinkImpl sink(raw_sink);
199  using Converter = DefaultConverter;
200  return ConvertAll(format, args, Converter(&sink));
201 }
202 
203 std::ostream& Streamable::Print(std::ostream& os) const {
204  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
205  return os;
206 }
207 
210  size_t orig = out->size();
212  out->erase(orig);
213  }
214  return *out;
215 }
216 
221  out.clear();
222  }
223  return out;
224 }
225 
229  if (!FormatUntyped(&sink, format, args)) {
230  errno = EINVAL;
231  return -1;
232  }
233  if (sink.error()) {
234  errno = sink.error();
235  return -1;
236  }
237  if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
238  errno = EFBIG;
239  return -1;
240  }
241  return static_cast<int>(sink.count());
242 }
243 
246  BufferRawSink sink(output, size ? size - 1 : 0);
247  if (!FormatUntyped(&sink, format, args)) {
248  errno = EINVAL;
249  return -1;
250  }
251  size_t total = sink.total_written();
252  if (size) output[std::min(total, size - 1)] = 0;
253  return static_cast<int>(total);
254 }
255 
256 } // namespace str_format_internal
258 } // namespace absl
ABSL_PREDICT_FALSE
#define ABSL_PREDICT_FALSE(x)
Definition: abseil-cpp/absl/base/optimization.h:180
absl::str_format_internal::FormatUntyped
bool FormatUntyped(FormatRawSinkImpl raw_sink, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:195
absl::Append
static char * Append(char *out, const AlphaNum &x)
Definition: abseil-cpp/absl/strings/str_cat.cc:88
width
int width
Definition: libuv/docs/code/tty-gravity/main.c:10
precision
int precision
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:448
http2_test_server.format
format
Definition: http2_test_server.py:118
absl::str_format_internal::FormatArgImplFriend::ToInt
static bool ToInt(Arg arg, int *out)
Definition: abseil-cpp/absl/strings/internal/str_format/arg.h:284
arg_context_
ArgContext arg_context_
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:120
absl::Span
Definition: abseil-cpp/absl/types/span.h:152
position
intern position
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/array.c:487
total
size_t total
Definition: cord_analysis.cc:59
absl::str_format_internal::FormatConversionSpecImplFriend::SetFlags
static void SetFlags(Flags f, FormatConversionSpecImpl *conv)
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:316
absl::str_format_internal::AppendPack
std::string & AppendPack(std::string *out, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:208
absl::str_format_internal::FprintF
int FprintF(std::FILE *output, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:226
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
absl::str_format_internal::FormatRawSinkImpl
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:40
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::str_format_internal::UnboundConversion
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser.h:43
make_cmakelists.converter
converter
Definition: make_cmakelists.py:317
sink_
FormatSinkImpl * sink_
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:146
absl::str_format_internal::FormatConversionSpecImplFriend::FlagsToString
static std::string FlagsToString(const FormatConversionSpecImpl &spec)
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:329
absl::str_format_internal::Summarize
std::string Summarize(const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:180
pack_
absl::Span< const FormatArgImpl > pack_
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:51
absl::str_format_internal::FormatConversionSpecImplFriend::SetWidth
static void SetWidth(int w, FormatConversionSpecImpl *conv)
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:323
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
run_interop_tests.spec
def spec
Definition: run_interop_tests.py:1394
absl::str_format_internal::FILERawSink
Definition: abseil-cpp/absl/strings/internal/str_format/output.h:55
absl::str_format_internal::Flags::kLeft
@ kLeft
absl::str_format_internal::BoundConversion
Definition: abseil-cpp/absl/strings/internal/str_format/bind.h:37
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
gmock_output_test.output
output
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
converter_
Converter converter_
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:119
conv
const FormatConversionSpecImpl & conv
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:449
absl::str_format_internal::ParseFormatString
bool ParseFormatString(string_view src, Consumer consumer)
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser.h:149
absl::str_format_internal::FormatPack
std::string FormatPack(const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:217
absl::str_format_internal::FormatArgImplFriend::Convert
static bool Convert(Arg arg, FormatConversionSpecImpl conv, FormatSinkImpl *out)
Definition: abseil-cpp/absl/strings/internal/str_format/arg.h:291
arg
Definition: cmdline.cc:40
absl::str_format_internal::FormatConversionSpecImplFriend::SetPrecision
static void SetPrecision(int p, FormatConversionSpecImpl *conv)
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:326
absl::str_format_internal::FormatSinkImpl
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:67
absl::str_format_internal::Streamable::Print
std::ostream & Print(std::ostream &os) const
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:203
min
#define min(a, b)
Definition: qsort.h:83
absl::str_format_internal::UntypedFormatSpecImpl
Definition: abseil-cpp/absl/strings/internal/str_format/bind.h:47
absl::str_format_internal::Streamable::args_
absl::Span< const FormatArgImpl > args_
Definition: abseil-cpp/absl/strings/internal/str_format/bind.h:200
absl::str_format_internal::FormatConversionSpecImplFriend::SetConversionChar
static void SetConversionChar(FormatConversionChar c, FormatConversionSpecImpl *conv)
Definition: abseil-cpp/absl/strings/internal/str_format/extension.h:319
value
const char * value
Definition: hpack_parser_table.cc:165
absl::str_format_internal::SnprintF
int SnprintF(char *output, size_t size, const UntypedFormatSpecImpl format, absl::Span< const FormatArgImpl > args)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:244
benchmark.FILE
FILE
Definition: benchmark.py:21
absl::str_format_internal::BufferRawSink
Definition: abseil-cpp/absl/strings/internal/str_format/output.h:39
sink
FormatSinkImpl * sink
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:450
absl::Span::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/types/span.h:261
absl::str_format_internal::BindWithPack
bool BindWithPack(const UnboundConversion *props, absl::Span< const FormatArgImpl > pack, BoundConversion *bound)
Definition: abseil-cpp/absl/strings/internal/str_format/bind.cc:174
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::out
char * out
Definition: abseil-cpp/absl/synchronization/mutex.h:1048
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
str_format_internal
absl::str_format_internal::Flags::kBasic
@ kBasic
absl::str_format_internal::Streamable::format_
const UntypedFormatSpecImpl & format_
Definition: abseil-cpp/absl/strings/internal/str_format/bind.h:199


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:47