string.cpp raw

   1  // Copyright (c) 2019-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <util/string.h>
   6  
   7  #include <iterator>
   8  #include <memory>
   9  #include <regex>
  10  #include <stdexcept>
  11  #include <string>
  12  
  13  namespace util {
  14  void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute)
  15  {
  16      if (search.empty()) return;
  17      in_out = std::regex_replace(in_out, std::regex(search), substitute);
  18  }
  19  
  20  LineReader::LineReader(std::span<const std::byte> buffer, size_t max_line_length)
  21      : start(buffer.begin()), end(buffer.end()), max_line_length(max_line_length), it(buffer.begin()) {}
  22  
  23  std::optional<std::string_view> LineReader::ReadLine()
  24  {
  25      if (it == end) {
  26          return std::nullopt;
  27      }
  28  
  29      auto line_start = it;
  30      size_t count = 0;
  31      while (it != end) {
  32          // Read a character from the incoming buffer and increment the iterator
  33          auto c = static_cast<char>(*it);
  34          ++it;
  35          ++count;
  36          // If the character we just consumed was \n, the line is terminated.
  37          // The \n itself does not count against max_line_length.
  38          if (c == '\n') {
  39              const std::string_view untrimmed_line(reinterpret_cast<const char*>(std::to_address(line_start)), count);
  40              std::string_view line = RemoveSuffixView(untrimmed_line, "\n");
  41              return RemoveSuffixView(line, "\r");
  42          }
  43          // If the character we just consumed gives us a line length greater
  44          // than max_line_length, and we are not at the end of the line (or buffer) yet,
  45          // that means the line we are currently reading is too long, and we throw.
  46          if (count > max_line_length) {
  47              // Reset iterator
  48              it = line_start;
  49              throw std::runtime_error("max_line_length exceeded by LineReader");
  50          }
  51      }
  52      // End of buffer reached without finding a \n or exceeding max_line_length.
  53      // Reset the iterator so the rest of the buffer can be read granularly
  54      // with ReadLength() and return null to indicate a line was not found.
  55      it = line_start;
  56      return std::nullopt;
  57  }
  58  
  59  // Ignores max_line_length but won't overflow
  60  std::string_view LineReader::ReadLength(size_t len)
  61  {
  62      if (len == 0) return {};
  63      if (Remaining() < len) throw std::runtime_error("Not enough data in buffer");
  64      std::string_view out(reinterpret_cast<const char*>(std::to_address(it)), len);
  65      it += len;
  66      return out;
  67  }
  68  
  69  size_t LineReader::Remaining() const
  70  {
  71      return std::distance(it, end);
  72  }
  73  
  74  size_t LineReader::Consumed() const
  75  {
  76      return std::distance(start, it);
  77  }
  78  } // namespace util
  79