include-what-you-use/iwyu_string_util.h

213 lines
6.2 KiB
C++

//===--- iwyu_string_util.h - string utilities for include-what-you-use ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// String utilities for the IWYU checker.
//
#ifndef INCLUDE_WHAT_YOU_USE_IWYU_STRING_UTIL_H_
#define INCLUDE_WHAT_YOU_USE_IWYU_STRING_UTIL_H_
#include <cctype>
#include <cstddef>
#include <string>
#include <vector>
#include "iwyu_port.h"
namespace include_what_you_use {
using std::string;
using std::vector;
// Returns true if str starts with prefix.
inline bool StartsWith(const string& str, const string& prefix) {
return str.substr(0, prefix.length()) == prefix;
}
// Returns true if str ends with suffix.
inline bool EndsWith(const string& str, const string& suffix) {
if (suffix.length() > str.length())
return false;
return str.substr(str.length() - suffix.length()) == suffix;
}
// If *str starts with prefix, removes the prefix and returns true.
inline bool StripLeft(string* str, const string& prefix) {
if (StartsWith(*str, prefix)) {
*str = str->substr(prefix.length());
return true;
}
return false;
}
// If *str ends with suffix, removes the suffix and returns true.
inline bool StripRight(string* str, const string& suffix) {
if (str->length() >= suffix.length() &&
str->substr(str->length() - suffix.length()) == suffix) {
*str = str->substr(0, str->length() - suffix.length());
return true;
}
return false;
}
// Truncate str to width with ellipses to indicate truncation.
// Return str unchanged if it fits within width.
// Return empty string if width is too short to fit anything meaningful.
// Otherwise return str truncated to width chars.
inline string Ellipsize(const string& str, size_t width) {
if (str.length() <= width)
return str;
// If we truncate strings too short, we'll end up with nonsense abbreviations
// like '...', 'T...' or 'Ty...' so make sure we have at least three chars
// from str and three chars for ellipsis.
if (width < 6)
return string();
return str.substr(0, width - 3) + "...";
}
// Finds the first occurrence of substr in *str and removes from *str
// everything before the occurrence and the occurrence itself. For
// example, string s = "What a hat!"; StripPast(&s, "hat"); will make s
// " a hat!".
inline bool StripPast(string* str, const string& substr) {
const size_t pos = str->find(substr);
if (pos == string::npos)
return false;
*str = str->substr(pos + substr.length());
return true;
}
// Removes leading whitespace.
inline void StripWhiteSpaceLeft(string* str) {
for (string::size_type i = 0; i < str->size(); ++i) {
if (!isspace((*str)[i])) {
*str = str->substr(i);
return;
}
}
// Everything is whitespace. Return with an empty string.
str->clear();
}
// Removes trailing whitespace.
inline void StripWhiteSpaceRight(string* str) {
for (string::size_type end_of_string = str->size();
end_of_string > 0; --end_of_string) {
if (!isspace((*str)[end_of_string - 1])) {
*str = str->substr(0, end_of_string);
return;
}
}
// Everything is whitespace. Return with an empty string.
str->clear();
}
// Removes both leading and trailing whitespace.
inline void StripWhiteSpace(string* str) {
StripWhiteSpaceLeft(str);
StripWhiteSpaceRight(str);
}
inline void ReplaceAll(std::string* str, const std::string& from,
const std::string& to) {
for (size_t pos = str->find(from); pos != std::string::npos;
pos = str->find(from, pos + to.length())) {
str->replace(pos, from.length(), to);
}
}
// This is the same as split() in Python. If max_segs is 0, there's
// no limit on the number of the generated segments.
inline vector<string> Split(
string str, const string& divider, size_t max_segs) {
CHECK_(!divider.empty());
vector<string> retval;
size_t pos;
// If max_segs is 0, the first part of the condition will always be true.
while (retval.size() + 1 != max_segs &&
(pos = str.find(divider)) != string::npos) {
retval.push_back(str.substr(0, pos));
str = str.substr(pos + divider.length());
}
retval.push_back(str);
return retval;
}
// Like Split, but using a divider of arbitrary whitespace.
// Whitespace at the beginning and end is ignored.
inline vector<string> SplitOnWhiteSpace(const string& str, size_t max_segs) {
vector<string> retval;
size_t tokstart = string::npos;
for (size_t pos = 0; pos < str.size(); ++pos) {
if (isspace(str[pos])) {
if (tokstart != string::npos) {
retval.push_back(str.substr(tokstart, pos - tokstart));
if (retval.size() == max_segs) {
return retval;
}
tokstart = string::npos;
}
} else {
if (tokstart == string::npos) {
tokstart = pos;
}
}
}
if (tokstart != string::npos) {
retval.push_back(str.substr(tokstart));
}
return retval;
}
// Like SplitOnWhiteSpace, but double-quoted and bracketed strings are
// preserved. No error checking with respect to closing quotes is done.
inline vector<string> SplitOnWhiteSpacePreservingQuotes(
const string& str, size_t max_segs) {
vector<string> retval;
size_t tokstart = string::npos;
char closing_quote = '\0';
for (size_t pos = 0; pos < str.size(); ++pos) {
if (isspace(str[pos])) {
if (tokstart != string::npos && closing_quote == '\0') {
retval.push_back(str.substr(tokstart, pos - tokstart));
if (retval.size() == max_segs) {
return retval;
}
tokstart = string::npos;
}
} else {
if (tokstart == string::npos) {
tokstart = pos;
if (str[pos] == '"') {
closing_quote = '"';
} else if (str[pos] == '<') {
closing_quote = '>';
} else {
closing_quote = '\0';
}
} else if (str[pos] == closing_quote) {
closing_quote = '\0';
}
}
}
if (tokstart != string::npos) {
retval.push_back(str.substr(tokstart));
}
return retval;
}
} // namespace include_what_you_use
#endif // INCLUDE_WHAT_YOU_USE_IWYU_STRING_UTIL_H_