Coverage Report

Created: 2024-09-08 06:07

/proc/self/cwd/external/com_google_absl/absl/strings/internal/str_format/bind.cc
Line
Count
Source (jump to first uncovered line)
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 <algorithm>
18
#include <cassert>
19
#include <cerrno>
20
#include <cstddef>
21
#include <cstdio>
22
#include <ios>
23
#include <limits>
24
#include <ostream>
25
#include <sstream>
26
#include <string>
27
#include "absl/base/config.h"
28
#include "absl/base/optimization.h"
29
#include "absl/strings/internal/str_format/arg.h"
30
#include "absl/strings/internal/str_format/constexpr_parser.h"
31
#include "absl/strings/internal/str_format/extension.h"
32
#include "absl/strings/internal/str_format/output.h"
33
#include "absl/strings/string_view.h"
34
#include "absl/types/span.h"
35
36
namespace absl {
37
ABSL_NAMESPACE_BEGIN
38
namespace str_format_internal {
39
40
namespace {
41
42
inline bool BindFromPosition(int position, int* value,
43
0
                             absl::Span<const FormatArgImpl> pack) {
44
0
  assert(position > 0);
45
0
  if (static_cast<size_t>(position) > pack.size()) {
46
0
    return false;
47
0
  }
48
  // -1 because positions are 1-based
49
0
  return FormatArgImplFriend::ToInt(pack[static_cast<size_t>(position) - 1],
50
0
                                    value);
51
0
}
52
53
class ArgContext {
54
 public:
55
4.96k
  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
56
57
  // Fill 'bound' with the results of applying the context's argument pack
58
  // to the specified 'unbound'. We synthesize a BoundConversion by
59
  // lining up a UnboundConversion with a user argument. We also
60
  // resolve any '*' specifiers for width and precision, so after
61
  // this call, 'bound' has all the information it needs to be formatted.
62
  // Returns false on failure.
63
  bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
64
65
 private:
66
  absl::Span<const FormatArgImpl> pack_;
67
};
68
69
inline bool ArgContext::Bind(const UnboundConversion* unbound,
70
4.96k
                             BoundConversion* bound) {
71
4.96k
  const FormatArgImpl* arg = nullptr;
72
4.96k
  int arg_position = unbound->arg_position;
73
4.96k
  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
74
4.96k
  arg = &pack_[static_cast<size_t>(arg_position - 1)];  // 1-based
75
76
4.96k
  if (unbound->flags != Flags::kBasic) {
77
0
    int width = unbound->width.value();
78
0
    bool force_left = false;
79
0
    if (unbound->width.is_from_arg()) {
80
0
      if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
81
0
        return false;
82
0
      if (width < 0) {
83
        // "A negative field width is taken as a '-' flag followed by a
84
        // positive field width."
85
0
        force_left = true;
86
        // Make sure we don't overflow the width when negating it.
87
0
        width = -std::max(width, -std::numeric_limits<int>::max());
88
0
      }
89
0
    }
90
91
0
    int precision = unbound->precision.value();
92
0
    if (unbound->precision.is_from_arg()) {
93
0
      if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
94
0
                            pack_))
95
0
        return false;
96
0
    }
97
98
0
    FormatConversionSpecImplFriend::SetWidth(width, bound);
99
0
    FormatConversionSpecImplFriend::SetPrecision(precision, bound);
100
101
0
    if (force_left) {
102
0
      FormatConversionSpecImplFriend::SetFlags(unbound->flags | Flags::kLeft,
103
0
                                               bound);
104
0
    } else {
105
0
      FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
106
0
    }
107
108
0
    FormatConversionSpecImplFriend::SetLengthMod(unbound->length_mod, bound);
109
4.96k
  } else {
110
4.96k
    FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
111
4.96k
    FormatConversionSpecImplFriend::SetWidth(-1, bound);
112
4.96k
    FormatConversionSpecImplFriend::SetPrecision(-1, bound);
113
4.96k
  }
114
4.96k
  FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);
115
4.96k
  bound->set_arg(arg);
116
4.96k
  return true;
117
4.96k
}
118
119
template <typename Converter>
120
class ConverterConsumer {
121
 public:
122
  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
123
4.96k
      : converter_(converter), arg_context_(pack) {}
Unexecuted instantiation: bind.cc:absl::str_format_internal::(anonymous namespace)::ConverterConsumer<absl::str_format_internal::(anonymous namespace)::SummarizingConverter>::ConverterConsumer(absl::str_format_internal::(anonymous namespace)::SummarizingConverter, absl::Span<absl::str_format_internal::FormatArgImpl const>)
bind.cc:absl::str_format_internal::(anonymous namespace)::ConverterConsumer<absl::str_format_internal::(anonymous namespace)::DefaultConverter>::ConverterConsumer(absl::str_format_internal::(anonymous namespace)::DefaultConverter, absl::Span<absl::str_format_internal::FormatArgImpl const>)
Line
Count
Source
123
4.96k
      : converter_(converter), arg_context_(pack) {}
124
125
4.96k
  bool Append(string_view s) {
126
4.96k
    converter_.Append(s);
127
4.96k
    return true;
128
4.96k
  }
Unexecuted instantiation: bind.cc:absl::str_format_internal::(anonymous namespace)::ConverterConsumer<absl::str_format_internal::(anonymous namespace)::SummarizingConverter>::Append(absl::string_view)
bind.cc:absl::str_format_internal::(anonymous namespace)::ConverterConsumer<absl::str_format_internal::(anonymous namespace)::DefaultConverter>::Append(absl::string_view)
Line
Count
Source
125
4.96k
  bool Append(string_view s) {
126
4.96k
    converter_.Append(s);
127
4.96k
    return true;
128
4.96k
  }
129
4.96k
  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
130
4.96k
    BoundConversion bound;
131
4.96k
    if (!arg_context_.Bind(&conv, &bound)) return false;
132
4.96k
    return converter_.ConvertOne(bound, conv_string);
133
4.96k
  }
Unexecuted instantiation: bind.cc:absl::str_format_internal::(anonymous namespace)::ConverterConsumer<absl::str_format_internal::(anonymous namespace)::SummarizingConverter>::ConvertOne(absl::str_format_internal::UnboundConversion const&, absl::string_view)
bind.cc:absl::str_format_internal::(anonymous namespace)::ConverterConsumer<absl::str_format_internal::(anonymous namespace)::DefaultConverter>::ConvertOne(absl::str_format_internal::UnboundConversion const&, absl::string_view)
Line
Count
Source
129
4.96k
  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
130
4.96k
    BoundConversion bound;
131
4.96k
    if (!arg_context_.Bind(&conv, &bound)) return false;
132
4.96k
    return converter_.ConvertOne(bound, conv_string);
133
4.96k
  }
134
135
 private:
136
  Converter converter_;
137
  ArgContext arg_context_;
138
};
139
140
template <typename Converter>
141
bool ConvertAll(const UntypedFormatSpecImpl format,
142
4.96k
                absl::Span<const FormatArgImpl> args, Converter converter) {
143
4.96k
  if (format.has_parsed_conversion()) {
144
0
    return format.parsed_conversion()->ProcessFormat(
145
0
        ConverterConsumer<Converter>(converter, args));
146
4.96k
  } else {
147
4.96k
    return ParseFormatString(format.str(),
148
4.96k
                             ConverterConsumer<Converter>(converter, args));
149
4.96k
  }
150
4.96k
}
Unexecuted instantiation: bind.cc:bool absl::str_format_internal::(anonymous namespace)::ConvertAll<absl::str_format_internal::(anonymous namespace)::SummarizingConverter>(absl::str_format_internal::UntypedFormatSpecImpl, absl::Span<absl::str_format_internal::FormatArgImpl const>, absl::str_format_internal::(anonymous namespace)::SummarizingConverter)
bind.cc:bool absl::str_format_internal::(anonymous namespace)::ConvertAll<absl::str_format_internal::(anonymous namespace)::DefaultConverter>(absl::str_format_internal::UntypedFormatSpecImpl, absl::Span<absl::str_format_internal::FormatArgImpl const>, absl::str_format_internal::(anonymous namespace)::DefaultConverter)
Line
Count
Source
142
4.96k
                absl::Span<const FormatArgImpl> args, Converter converter) {
143
4.96k
  if (format.has_parsed_conversion()) {
144
0
    return format.parsed_conversion()->ProcessFormat(
145
0
        ConverterConsumer<Converter>(converter, args));
146
4.96k
  } else {
147
4.96k
    return ParseFormatString(format.str(),
148
4.96k
                             ConverterConsumer<Converter>(converter, args));
149
4.96k
  }
150
4.96k
}
151
152
class DefaultConverter {
153
 public:
154
4.96k
  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
155
156
4.96k
  void Append(string_view s) const { sink_->Append(s); }
157
158
4.96k
  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
159
4.96k
    return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
160
4.96k
  }
161
162
 private:
163
  FormatSinkImpl* sink_;
164
};
165
166
class SummarizingConverter {
167
 public:
168
0
  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
169
170
0
  void Append(string_view s) const { sink_->Append(s); }
171
172
0
  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
173
0
    UntypedFormatSpecImpl spec("%d");
174
175
0
    std::ostringstream ss;
176
0
    ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
177
0
       << FormatConversionSpecImplFriend::FlagsToString(bound);
178
0
    if (bound.width() >= 0) ss << bound.width();
179
0
    if (bound.precision() >= 0) ss << "." << bound.precision();
180
0
    ss << bound.conversion_char() << "}";
181
0
    Append(ss.str());
182
0
    return true;
183
0
  }
184
185
 private:
186
  FormatSinkImpl* sink_;
187
};
188
189
}  // namespace
190
191
bool BindWithPack(const UnboundConversion* props,
192
                  absl::Span<const FormatArgImpl> pack,
193
0
                  BoundConversion* bound) {
194
0
  return ArgContext(pack).Bind(props, bound);
195
0
}
196
197
std::string Summarize(const UntypedFormatSpecImpl format,
198
0
                      absl::Span<const FormatArgImpl> args) {
199
0
  typedef SummarizingConverter Converter;
200
0
  std::string out;
201
0
  {
202
    // inner block to destroy sink before returning out. It ensures a last
203
    // flush.
204
0
    FormatSinkImpl sink(&out);
205
0
    if (!ConvertAll(format, args, Converter(&sink))) {
206
0
      return "";
207
0
    }
208
0
  }
209
0
  return out;
210
0
}
211
212
bool FormatUntyped(FormatRawSinkImpl raw_sink,
213
                   const UntypedFormatSpecImpl format,
214
4.96k
                   absl::Span<const FormatArgImpl> args) {
215
4.96k
  FormatSinkImpl sink(raw_sink);
216
4.96k
  using Converter = DefaultConverter;
217
4.96k
  return ConvertAll(format, args, Converter(&sink));
218
4.96k
}
219
220
0
std::ostream& Streamable::Print(std::ostream& os) const {
221
0
  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
222
0
  return os;
223
0
}
224
225
std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
226
0
                        absl::Span<const FormatArgImpl> args) {
227
0
  size_t orig = out->size();
228
0
  if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
229
0
    out->erase(orig);
230
0
  }
231
0
  return *out;
232
0
}
233
234
std::string FormatPack(UntypedFormatSpecImpl format,
235
4.96k
                       absl::Span<const FormatArgImpl> args) {
236
4.96k
  std::string out;
237
4.96k
  if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {
238
0
    out.clear();
239
0
  }
240
4.96k
  return out;
241
4.96k
}
242
243
int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
244
0
            absl::Span<const FormatArgImpl> args) {
245
0
  FILERawSink sink(output);
246
0
  if (!FormatUntyped(&sink, format, args)) {
247
0
    errno = EINVAL;
248
0
    return -1;
249
0
  }
250
0
  if (sink.error()) {
251
0
    errno = sink.error();
252
0
    return -1;
253
0
  }
254
0
  if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
255
0
    errno = EFBIG;
256
0
    return -1;
257
0
  }
258
0
  return static_cast<int>(sink.count());
259
0
}
260
261
int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
262
0
             absl::Span<const FormatArgImpl> args) {
263
0
  BufferRawSink sink(output, size ? size - 1 : 0);
264
0
  if (!FormatUntyped(&sink, format, args)) {
265
0
    errno = EINVAL;
266
0
    return -1;
267
0
  }
268
0
  size_t total = sink.total_written();
269
0
  if (size) output[std::min(total, size - 1)] = 0;
270
0
  return static_cast<int>(total);
271
0
}
272
273
}  // namespace str_format_internal
274
ABSL_NAMESPACE_END
275
}  // namespace absl