Go to the documentation of this file.00001 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
00002 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
00003
00004 #include <limits.h>
00005 #include <stddef.h>
00006 #include <stdlib.h>
00007
00008 #include <cassert>
00009 #include <initializer_list>
00010 #include <iosfwd>
00011 #include <iterator>
00012 #include <memory>
00013 #include <vector>
00014
00015 #include "absl/strings/internal/str_format/checker.h"
00016 #include "absl/strings/internal/str_format/extension.h"
00017
00018 namespace absl {
00019 namespace str_format_internal {
00020
00021
00022 struct UnboundConversion {
00023 UnboundConversion()
00024 : flags() {
00025 flags.basic = true;
00026 }
00027
00028 class InputValue {
00029 public:
00030 void set_value(int value) {
00031 assert(value >= 0);
00032 value_ = value;
00033 }
00034 int value() const { return value_; }
00035
00036
00037
00038
00039
00040
00041 void set_from_arg(int value) {
00042 assert(value > 0);
00043 value_ = -value - 1;
00044 }
00045 bool is_from_arg() const { return value_ < -1; }
00046 int get_from_arg() const {
00047 assert(is_from_arg());
00048 return -value_ - 1;
00049 }
00050
00051 private:
00052 int value_ = -1;
00053 };
00054
00055
00056 int arg_position;
00057
00058 InputValue width;
00059 InputValue precision;
00060
00061 Flags flags;
00062 LengthMod length_mod;
00063 ConversionChar conv;
00064 };
00065
00066
00067
00068
00069
00070
00071 const char* ConsumeUnboundConversion(const char* p, const char* end,
00072 UnboundConversion* conv, int* next_arg);
00073
00074
00075
00076 class ConvTag {
00077 public:
00078 constexpr ConvTag(ConversionChar::Id id) : tag_(id) {}
00079
00080
00081 constexpr ConvTag(LengthMod::Id id) : tag_(~id) {}
00082
00083 constexpr ConvTag() : tag_(-128) {}
00084
00085 bool is_conv() const { return tag_ >= 0; }
00086 bool is_length() const { return tag_ < 0 && tag_ != -128; }
00087 ConversionChar as_conv() const {
00088 assert(is_conv());
00089 return ConversionChar::FromId(static_cast<ConversionChar::Id>(tag_));
00090 }
00091 LengthMod as_length() const {
00092 assert(is_length());
00093 return LengthMod::FromId(static_cast<LengthMod::Id>(~tag_));
00094 }
00095
00096 private:
00097 std::int8_t tag_;
00098 };
00099
00100 extern const ConvTag kTags[256];
00101
00102 inline ConvTag GetTagForChar(char c) {
00103 return kTags[static_cast<unsigned char>(c)];
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 template <typename Consumer>
00117 bool ParseFormatString(string_view src, Consumer consumer) {
00118 int next_arg = 0;
00119 const char* p = src.data();
00120 const char* const end = p + src.size();
00121 while (p != end) {
00122 const char* percent = static_cast<const char*>(memchr(p, '%', end - p));
00123 if (!percent) {
00124
00125 return consumer.Append(string_view(p, end - p));
00126 }
00127
00128 if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) {
00129 return false;
00130 }
00131 if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false;
00132
00133 auto tag = GetTagForChar(percent[1]);
00134 if (tag.is_conv()) {
00135 if (ABSL_PREDICT_FALSE(next_arg < 0)) {
00136
00137
00138
00139
00140 return false;
00141 }
00142 p = percent + 2;
00143
00144
00145
00146
00147 UnboundConversion conv;
00148 conv.conv = tag.as_conv();
00149 conv.arg_position = ++next_arg;
00150 if (ABSL_PREDICT_FALSE(
00151 !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) {
00152 return false;
00153 }
00154 } else if (percent[1] != '%') {
00155 UnboundConversion conv;
00156 p = ConsumeUnboundConversion(percent + 1, end, &conv, &next_arg);
00157 if (ABSL_PREDICT_FALSE(p == nullptr)) return false;
00158 if (ABSL_PREDICT_FALSE(!consumer.ConvertOne(
00159 conv, string_view(percent + 1, p - (percent + 1))))) {
00160 return false;
00161 }
00162 } else {
00163 if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false;
00164 p = percent + 2;
00165 continue;
00166 }
00167 }
00168 return true;
00169 }
00170
00171
00172
00173 constexpr bool EnsureConstexpr(string_view s) {
00174 return s.empty() || s[0] == s[0];
00175 }
00176
00177 class ParsedFormatBase {
00178 public:
00179 explicit ParsedFormatBase(string_view format, bool allow_ignored,
00180 std::initializer_list<Conv> convs);
00181
00182 ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
00183
00184 ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); }
00185
00186 ParsedFormatBase& operator=(const ParsedFormatBase& other) {
00187 if (this == &other) return *this;
00188 has_error_ = other.has_error_;
00189 items_ = other.items_;
00190 size_t text_size = items_.empty() ? 0 : items_.back().text_end;
00191 data_.reset(new char[text_size]);
00192 memcpy(data_.get(), other.data_.get(), text_size);
00193 return *this;
00194 }
00195
00196 ParsedFormatBase& operator=(ParsedFormatBase&& other) {
00197 if (this == &other) return *this;
00198 has_error_ = other.has_error_;
00199 data_ = std::move(other.data_);
00200 items_ = std::move(other.items_);
00201
00202 other.items_.clear();
00203 return *this;
00204 }
00205
00206 template <typename Consumer>
00207 bool ProcessFormat(Consumer consumer) const {
00208 const char* const base = data_.get();
00209 string_view text(base, 0);
00210 for (const auto& item : items_) {
00211 const char* const end = text.data() + text.size();
00212 text = string_view(end, (base + item.text_end) - end);
00213 if (item.is_conversion) {
00214 if (!consumer.ConvertOne(item.conv, text)) return false;
00215 } else {
00216 if (!consumer.Append(text)) return false;
00217 }
00218 }
00219 return !has_error_;
00220 }
00221
00222 bool has_error() const { return has_error_; }
00223
00224 private:
00225
00226
00227 bool MatchesConversions(bool allow_ignored,
00228 std::initializer_list<Conv> convs) const;
00229
00230 struct ParsedFormatConsumer;
00231
00232 struct ConversionItem {
00233 bool is_conversion;
00234
00235 size_t text_end;
00236 UnboundConversion conv;
00237 };
00238
00239 bool has_error_;
00240 std::unique_ptr<char[]> data_;
00241 std::vector<ConversionItem> items_;
00242 };
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 template <str_format_internal::Conv... C>
00274 class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
00275 public:
00276 explicit ExtendedParsedFormat(string_view format)
00277 #if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
00278 __attribute__((
00279 enable_if(str_format_internal::EnsureConstexpr(format),
00280 "Format std::string is not constexpr."),
00281 enable_if(str_format_internal::ValidFormatImpl<C...>(format),
00282 "Format specified does not match the template arguments.")))
00283 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
00284 : ExtendedParsedFormat(format, false) {
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 static std::unique_ptr<ExtendedParsedFormat> New(string_view format) {
00300 return New(format, false);
00301 }
00302 static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored(
00303 string_view format) {
00304 return New(format, true);
00305 }
00306
00307 private:
00308 static std::unique_ptr<ExtendedParsedFormat> New(string_view format,
00309 bool allow_ignored) {
00310 std::unique_ptr<ExtendedParsedFormat> conv(
00311 new ExtendedParsedFormat(format, allow_ignored));
00312 if (conv->has_error()) return nullptr;
00313 return conv;
00314 }
00315
00316 ExtendedParsedFormat(string_view s, bool allow_ignored)
00317 : ParsedFormatBase(s, allow_ignored, {C...}) {}
00318 };
00319 }
00320 }
00321
00322 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_