parser.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. #include "absl/strings/internal/str_format/parser.h"
  15. #include <assert.h>
  16. #include <string.h>
  17. #include <wchar.h>
  18. #include <cctype>
  19. #include <cstdint>
  20. #include <algorithm>
  21. #include <initializer_list>
  22. #include <limits>
  23. #include <ostream>
  24. #include <string>
  25. #include <unordered_set>
  26. namespace absl {
  27. ABSL_NAMESPACE_BEGIN
  28. namespace str_format_internal {
  29. // Define the array for non-constexpr uses.
  30. constexpr ConvTag ConvTagHolder::value[256];
  31. ABSL_ATTRIBUTE_NOINLINE const char* ConsumeUnboundConversionNoInline(
  32. const char* p, const char* end, UnboundConversion* conv, int* next_arg) {
  33. return ConsumeUnboundConversion(p, end, conv, next_arg);
  34. }
  35. std::string LengthModToString(LengthMod v) {
  36. switch (v) {
  37. case LengthMod::h:
  38. return "h";
  39. case LengthMod::hh:
  40. return "hh";
  41. case LengthMod::l:
  42. return "l";
  43. case LengthMod::ll:
  44. return "ll";
  45. case LengthMod::L:
  46. return "L";
  47. case LengthMod::j:
  48. return "j";
  49. case LengthMod::z:
  50. return "z";
  51. case LengthMod::t:
  52. return "t";
  53. case LengthMod::q:
  54. return "q";
  55. case LengthMod::none:
  56. return "";
  57. }
  58. return "";
  59. }
  60. struct ParsedFormatBase::ParsedFormatConsumer {
  61. explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat)
  62. : parsed(parsedformat), data_pos(parsedformat->data_.get()) {}
  63. bool Append(string_view s) {
  64. if (s.empty()) return true;
  65. size_t text_end = AppendText(s);
  66. if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) {
  67. // Let's extend the existing text run.
  68. parsed->items_.back().text_end = text_end;
  69. } else {
  70. // Let's make a new text run.
  71. parsed->items_.push_back({false, text_end, {}});
  72. }
  73. return true;
  74. }
  75. bool ConvertOne(const UnboundConversion &conv, string_view s) {
  76. size_t text_end = AppendText(s);
  77. parsed->items_.push_back({true, text_end, conv});
  78. return true;
  79. }
  80. size_t AppendText(string_view s) {
  81. memcpy(data_pos, s.data(), s.size());
  82. data_pos += s.size();
  83. return static_cast<size_t>(data_pos - parsed->data_.get());
  84. }
  85. ParsedFormatBase *parsed;
  86. char* data_pos;
  87. };
  88. ParsedFormatBase::ParsedFormatBase(
  89. string_view format, bool allow_ignored,
  90. std::initializer_list<FormatConversionCharSet> convs)
  91. : data_(format.empty() ? nullptr : new char[format.size()]) {
  92. has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
  93. !MatchesConversions(allow_ignored, convs);
  94. }
  95. bool ParsedFormatBase::MatchesConversions(
  96. bool allow_ignored,
  97. std::initializer_list<FormatConversionCharSet> convs) const {
  98. std::unordered_set<int> used;
  99. auto add_if_valid_conv = [&](int pos, char c) {
  100. if (static_cast<size_t>(pos) > convs.size() ||
  101. !Contains(convs.begin()[pos - 1], c))
  102. return false;
  103. used.insert(pos);
  104. return true;
  105. };
  106. for (const ConversionItem &item : items_) {
  107. if (!item.is_conversion) continue;
  108. auto &conv = item.conv;
  109. if (conv.precision.is_from_arg() &&
  110. !add_if_valid_conv(conv.precision.get_from_arg(), '*'))
  111. return false;
  112. if (conv.width.is_from_arg() &&
  113. !add_if_valid_conv(conv.width.get_from_arg(), '*'))
  114. return false;
  115. if (!add_if_valid_conv(conv.arg_position,
  116. FormatConversionCharToChar(conv.conv)))
  117. return false;
  118. }
  119. return used.size() == convs.size() || allow_ignored;
  120. }
  121. } // namespace str_format_internal
  122. ABSL_NAMESPACE_END
  123. } // namespace absl