File indexing completed on 2025-01-18 09:27:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
0016 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
0017
0018 #include <stddef.h>
0019 #include <stdlib.h>
0020
0021 #include <cassert>
0022 #include <cstring>
0023 #include <initializer_list>
0024 #include <memory>
0025 #include <string>
0026 #include <utility>
0027 #include <vector>
0028
0029 #include "absl/base/config.h"
0030 #include "absl/base/optimization.h"
0031 #include "absl/strings/internal/str_format/checker.h"
0032 #include "absl/strings/internal/str_format/constexpr_parser.h"
0033 #include "absl/strings/internal/str_format/extension.h"
0034 #include "absl/strings/string_view.h"
0035
0036 namespace absl {
0037 ABSL_NAMESPACE_BEGIN
0038 namespace str_format_internal {
0039
0040 std::string LengthModToString(LengthMod v);
0041
0042 const char* ConsumeUnboundConversionNoInline(const char* p, const char* end,
0043 UnboundConversion* conv,
0044 int* next_arg);
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 template <typename Consumer>
0057 bool ParseFormatString(string_view src, Consumer consumer) {
0058 int next_arg = 0;
0059 const char* p = src.data();
0060 const char* const end = p + src.size();
0061 while (p != end) {
0062 const char* percent =
0063 static_cast<const char*>(memchr(p, '%', static_cast<size_t>(end - p)));
0064 if (!percent) {
0065
0066 return consumer.Append(string_view(p, static_cast<size_t>(end - p)));
0067 }
0068
0069 if (ABSL_PREDICT_FALSE(!consumer.Append(
0070 string_view(p, static_cast<size_t>(percent - p))))) {
0071 return false;
0072 }
0073 if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false;
0074
0075 auto tag = GetTagForChar(percent[1]);
0076 if (tag.is_conv()) {
0077 if (ABSL_PREDICT_FALSE(next_arg < 0)) {
0078
0079
0080
0081
0082 return false;
0083 }
0084 p = percent + 2;
0085
0086
0087
0088
0089 UnboundConversion conv;
0090 conv.conv = tag.as_conv();
0091 conv.arg_position = ++next_arg;
0092 if (ABSL_PREDICT_FALSE(
0093 !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) {
0094 return false;
0095 }
0096 } else if (percent[1] != '%') {
0097 UnboundConversion conv;
0098 p = ConsumeUnboundConversionNoInline(percent + 1, end, &conv, &next_arg);
0099 if (ABSL_PREDICT_FALSE(p == nullptr)) return false;
0100 if (ABSL_PREDICT_FALSE(!consumer.ConvertOne(
0101 conv, string_view(percent + 1,
0102 static_cast<size_t>(p - (percent + 1)))))) {
0103 return false;
0104 }
0105 } else {
0106 if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false;
0107 p = percent + 2;
0108 continue;
0109 }
0110 }
0111 return true;
0112 }
0113
0114
0115
0116 constexpr bool EnsureConstexpr(string_view s) {
0117 return s.empty() || s[0] == s[0];
0118 }
0119
0120 class ParsedFormatBase {
0121 public:
0122 explicit ParsedFormatBase(
0123 string_view format, bool allow_ignored,
0124 std::initializer_list<FormatConversionCharSet> convs);
0125
0126 ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
0127
0128 ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); }
0129
0130 ParsedFormatBase& operator=(const ParsedFormatBase& other) {
0131 if (this == &other) return *this;
0132 has_error_ = other.has_error_;
0133 items_ = other.items_;
0134 size_t text_size = items_.empty() ? 0 : items_.back().text_end;
0135 data_.reset(new char[text_size]);
0136 memcpy(data_.get(), other.data_.get(), text_size);
0137 return *this;
0138 }
0139
0140 ParsedFormatBase& operator=(ParsedFormatBase&& other) {
0141 if (this == &other) return *this;
0142 has_error_ = other.has_error_;
0143 data_ = std::move(other.data_);
0144 items_ = std::move(other.items_);
0145
0146 other.items_.clear();
0147 return *this;
0148 }
0149
0150 template <typename Consumer>
0151 bool ProcessFormat(Consumer consumer) const {
0152 const char* const base = data_.get();
0153 string_view text(base, 0);
0154 for (const auto& item : items_) {
0155 const char* const end = text.data() + text.size();
0156 text =
0157 string_view(end, static_cast<size_t>((base + item.text_end) - end));
0158 if (item.is_conversion) {
0159 if (!consumer.ConvertOne(item.conv, text)) return false;
0160 } else {
0161 if (!consumer.Append(text)) return false;
0162 }
0163 }
0164 return !has_error_;
0165 }
0166
0167 bool has_error() const { return has_error_; }
0168
0169 private:
0170
0171
0172 bool MatchesConversions(
0173 bool allow_ignored,
0174 std::initializer_list<FormatConversionCharSet> convs) const;
0175
0176 struct ParsedFormatConsumer;
0177
0178 struct ConversionItem {
0179 bool is_conversion;
0180
0181 size_t text_end;
0182 UnboundConversion conv;
0183 };
0184
0185 bool has_error_;
0186 std::unique_ptr<char[]> data_;
0187 std::vector<ConversionItem> items_;
0188 };
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 template <FormatConversionCharSet... C>
0220 class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
0221 public:
0222 explicit ExtendedParsedFormat(string_view format)
0223 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
0224 __attribute__((
0225 enable_if(str_format_internal::EnsureConstexpr(format),
0226 "Format string is not constexpr."),
0227 enable_if(str_format_internal::ValidFormatImpl<C...>(format),
0228 "Format specified does not match the template arguments.")))
0229 #endif
0230 : ExtendedParsedFormat(format, false) {
0231 }
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 static std::unique_ptr<ExtendedParsedFormat> New(string_view format) {
0246 return New(format, false);
0247 }
0248 static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored(
0249 string_view format) {
0250 return New(format, true);
0251 }
0252
0253 private:
0254 static std::unique_ptr<ExtendedParsedFormat> New(string_view format,
0255 bool allow_ignored) {
0256 std::unique_ptr<ExtendedParsedFormat> conv(
0257 new ExtendedParsedFormat(format, allow_ignored));
0258 if (conv->has_error()) return nullptr;
0259 return conv;
0260 }
0261
0262 ExtendedParsedFormat(string_view s, bool allow_ignored)
0263 : ParsedFormatBase(s, allow_ignored, {C...}) {}
0264 };
0265 }
0266 ABSL_NAMESPACE_END
0267 }
0268
0269 #endif