osb/source/core/StarString.cpp
Kai Blaschke 431a9c00a5
Fixed a huge amount of Clang warnings
On Linux and macOS, using Clang to compile OpenStarbound produces about 400 MB worth of warnings during the build, making the compiler output unreadable and slowing the build down considerably.

99% of the warnings were unqualified uses of std::move and std::forward, which are now all properly qualified.

Fixed a few other minor warnings about non-virtual destructors and some uses of std::move preventing copy elision on temporary objects.

Most remaining warnings are now unused parameters.
2024-02-19 16:55:19 +01:00

1142 lines
23 KiB
C++

#include "StarString.hpp"
#include "StarStringView.hpp"
#include "StarBytes.hpp"
#include "StarFormat.hpp"
#include <cctype>
#include <regex>
namespace Star {
bool String::isSpace(Char c) {
return
c == 0x20 || // space
c == 0x09 || // horizontal tab
c == 0x0a || // newline
c == 0x0d || // carriage return
c == 0xfeff; // BOM or ZWNBSP
}
bool String::isAsciiNumber(Char c) {
return c >= '0' && c <= '9';
}
bool String::isAsciiLetter(Char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
String::Char String::toLower(Char c) {
if (c >= 'A' && c <= 'Z')
return c + 32;
else
return c;
}
String::Char String::toUpper(Char c) {
if (c >= 'a' && c <= 'z')
return c - 32;
else
return c;
}
bool String::charEqual(Char c1, Char c2, CaseSensitivity cs) {
if (cs == CaseInsensitive)
return toLower(c1) == toLower(c2);
else
return c1 == c2;
}
String String::joinWith(String const& join, String const& left, String const& right) {
if (left.empty())
return right;
if (right.empty())
return left;
if (left.endsWith(join)) {
if (right.beginsWith(join)) {
return left + right.substr(join.size());
}
return left + right;
} else {
if (right.beginsWith(join)) {
return left + right;
}
return left + join + right;
}
}
String::String() {}
String::String(String const& s) : m_string(s.m_string) {}
String::String(String&& s) : m_string(std::move(s.m_string)) {}
String::String(char const* s) : m_string(s) {}
String::String(char const* s, size_t n) : m_string(s, n) {}
String::String(std::string const& s) : m_string(s) {}
String::String(std::string&& s) : m_string(std::move(s)) {}
String::String(std::wstring const& s) {
reserve(s.length());
for (Char c : s)
append(c);
}
String::String(Char const* s) {
while (*s) {
append(*s);
++s;
}
}
String::String(Char const* s, size_t n) {
reserve(n);
for (size_t idx = 0; idx < n; ++idx) {
append(*s);
++s;
}
}
String::String(Char c, size_t n) {
reserve(n);
for (size_t i = 0; i < n; ++i)
append(c);
}
String::String(Char c) {
append(c);
}
std::string const& String::utf8() const {
return m_string;
}
std::string String::takeUtf8() {
return take(m_string);
}
ByteArray String::utf8Bytes() const {
return ByteArray(m_string.c_str(), m_string.size());
}
char const* String::utf8Ptr() const {
return m_string.c_str();
}
size_t String::utf8Size() const {
return m_string.size();
}
std::wstring String::wstring() const {
std::wstring string;
for (Char c : *this)
string.push_back(c);
return string;
}
String::WideString String::wideString() const {
WideString string;
string.reserve(m_string.size());
for (Char c : *this)
string.push_back(c);
return string;
}
String::const_iterator String::begin() const {
return const_iterator(m_string.begin());
}
String::const_iterator String::end() const {
return const_iterator(m_string.end());
}
size_t String::size() const {
return utf8Length(m_string.c_str(), m_string.size());
}
size_t String::length() const {
return size();
}
void String::clear() {
m_string.clear();
}
void String::reserve(size_t n) {
m_string.reserve(n);
}
bool String::empty() const {
return m_string.empty();
}
String::Char String::operator[](size_t index) const {
auto it = begin();
for (size_t i = 0; i < index; ++i)
++it;
return *it;
}
size_t CaseInsensitiveStringHash::operator()(String const& s) const {
PLHasher hash;
for (auto c : s)
hash.put(String::toLower(c));
return hash.hash();
}
bool CaseInsensitiveStringCompare::operator()(String const& lhs, String const& rhs) const {
return lhs.equalsIgnoreCase(rhs);
}
String::Char String::at(size_t i) const {
if (i > size())
throw OutOfRangeException(strf("Out of range in String::at({})", i));
return operator[](i);
}
String String::toUpper() const {
String s;
s.reserve(m_string.length());
for (Char c : *this)
s.append(toUpper(c));
return s;
}
String String::toLower() const {
String s;
s.reserve(m_string.length());
for (Char c : *this)
s.append(toLower(c));
return s;
}
String String::titleCase() const {
String s;
s.reserve(m_string.length());
bool capNext = true;
for (Char c : *this) {
if (capNext)
s.append(toUpper(c));
else
s.append(toLower(c));
capNext = !std::isalpha(c);
}
return s;
}
bool String::endsWith(String const& end, CaseSensitivity cs) const {
auto endsize = end.size();
if (endsize == 0)
return true;
auto mysize = size();
if (endsize > mysize)
return false;
return compare(mysize - endsize, NPos, end, 0, NPos, cs) == 0;
}
bool String::endsWith(Char end, CaseSensitivity cs) const {
if (size() == 0)
return false;
return charEqual(end, operator[](size() - 1), cs);
}
bool String::beginsWith(String const& beg, CaseSensitivity cs) const {
auto begSize = beg.size();
if (begSize == 0)
return true;
auto mysize = size();
if (begSize > mysize)
return false;
return compare(0, begSize, beg, 0, NPos, cs) == 0;
}
bool String::beginsWith(Char beg, CaseSensitivity cs) const {
if (size() == 0)
return false;
return charEqual(beg, operator[](0), cs);
}
String String::reverse() const {
String ret;
ret.reserve(m_string.length());
auto i = end();
while (i != begin()) {
--i;
ret.append(*i);
}
return ret;
}
String String::rot13() const {
String ret;
ret.reserve(m_string.length());
for (auto c : *this) {
if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
c += 13;
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
c -= 13;
ret.append(c);
}
return ret;
}
StringList String::split(Char c, size_t maxSplit) const {
return split(String(c), maxSplit);
}
StringList String::split(String const& pattern, size_t maxSplit) const {
StringList ret;
if (pattern.empty())
return StringList(1, *this);
size_t beg = 0;
while (true) {
if (ret.size() == maxSplit) {
ret.append(m_string.substr(beg));
break;
}
size_t end = m_string.find(pattern.m_string, beg);
if (end == NPos) {
ret.append(m_string.substr(beg));
break;
}
ret.append(m_string.substr(beg, end - beg));
beg = end + pattern.m_string.size();
}
starAssert(maxSplit == NPos || ret.size() <= maxSplit + 1);
return ret;
}
StringList String::rsplit(Char c, size_t maxSplit) const {
return rsplitAny(String(c), maxSplit);
}
StringList String::rsplit(String const& pattern, size_t maxSplit) const {
// This is really inefficient!
String v = reverse();
String p = pattern.reverse();
StringList l = v.split(p, maxSplit);
for (auto& s : l)
s = s.reverse();
Star::reverse(l);
return l;
}
StringList String::splitAny(String const& chars, size_t maxSplit) const {
StringList ret;
String next;
bool doneSplitting = false;
for (auto c : *this) {
if (!doneSplitting && chars.hasCharOrWhitespace(c)) {
if (!next.empty())
ret.append(take(next));
} else {
if (ret.size() == maxSplit)
doneSplitting = true;
next.append(c);
}
}
if (!next.empty())
ret.append(std::move(next));
return ret;
}
StringList String::rsplitAny(String const& chars, size_t maxSplit) const {
// This is really inefficient!
String v = reverse();
StringList l = v.splitAny(chars, maxSplit);
for (auto& s : l)
s = s.reverse();
Star::reverse(l);
return l;
}
StringList String::splitLines(size_t maxSplit) const {
return splitAny("\r\n", maxSplit);
}
StringList String::splitWhitespace(size_t maxSplit) const {
return splitAny("", maxSplit);
}
String String::extract(String const& chars) {
StringList l = splitAny(chars, 1);
if (l.size() == 0) {
return String();
} else if (l.size() == 1) {
clear();
return l.at(0);
} else {
*this = l.at(1);
return l.at(0);
}
}
String String::rextract(String const& chars) {
if (empty())
return String();
StringList l = rsplitAny(chars, 1);
if (l.size() == 1) {
clear();
return l.at(0);
} else {
*this = l.at(0);
return l.at(1);
}
}
bool String::hasChar(Char c) const {
for (Char ch : *this)
if (ch == c)
return true;
return false;
}
bool String::hasCharOrWhitespace(Char c) const {
if (empty())
return isSpace(c);
else
return hasChar(c);
}
String String::replace(String const& rplc, String const& val) const {
size_t index;
size_t sz = size();
size_t rsz = rplc.size();
String ret;
ret.reserve(m_string.length());
if (rplc.empty())
return *this;
index = find(rplc);
if (index == NPos)
return *this;
auto it = begin();
for (size_t i = 0; i < index; ++i)
ret.append(*it++);
while (index < sz) {
ret.append(val);
index += rsz;
for (size_t i = 0; i < rsz; ++i)
++it;
size_t nindex = find(rplc, index);
for (size_t i = index; i < nindex && i < sz; ++i)
ret.append(*it++);
index = nindex;
}
return ret;
}
String String::trimEnd(String const& pattern) const {
size_t end;
for (end = size(); end > 0; --end) {
Char ec = (*this)[end - 1];
if (!pattern.hasCharOrWhitespace(ec))
break;
}
return substr(0, end);
}
String String::trimBeg(String const& pattern) const {
size_t beg;
for (beg = 0; beg < size(); ++beg) {
Char bc = (*this)[beg];
if (!pattern.hasCharOrWhitespace(bc))
break;
}
return substr(beg);
}
String String::trim(String const& pattern) const {
return trimEnd(pattern).trimBeg(pattern);
}
size_t String::find(Char c, size_t pos, CaseSensitivity cs) const {
auto it = begin();
for (size_t i = 0; i < pos; ++i) {
if (it == end())
break;
++it;
}
while (it != end()) {
if (charEqual(c, *it, cs))
return pos;
++pos;
++it;
}
return NPos;
}
size_t String::find(String const& str, size_t pos, CaseSensitivity cs) const {
if (str.empty())
return 0;
auto it = begin();
for (size_t i = 0; i < pos; ++i) {
if (it == end())
break;
++it;
}
const_iterator sit = str.begin();
const_iterator mit = it;
while (it != end()) {
if (charEqual(*sit, *mit, cs)) {
do {
++mit;
++sit;
if (sit == str.end())
return pos;
else if (mit == end())
break;
} while (charEqual(*sit, *mit, cs));
sit = str.begin();
}
++pos;
mit = ++it;
}
return NPos;
}
size_t String::findLast(Char c, CaseSensitivity cs) const {
auto it = begin();
size_t found = NPos;
size_t pos = 0;
while (it != end()) {
if (charEqual(c, *it, cs))
found = pos;
++pos;
++it;
}
return found;
}
size_t String::findLast(String const& str, CaseSensitivity cs) const {
if (str.empty())
return 0;
size_t pos = 0;
auto it = begin();
size_t result = NPos;
const_iterator sit = str.begin();
const_iterator mit = it;
while (it != end()) {
if (charEqual(*sit, *mit, cs)) {
do {
++mit;
++sit;
if (sit == str.end()) {
result = pos;
break;
}
if (mit == end())
break;
} while (charEqual(*sit, *mit, cs));
sit = str.begin();
}
++pos;
mit = ++it;
}
return result;
}
size_t String::findFirstOf(String const& pattern, size_t beg) const {
auto it = begin();
size_t i;
for (i = 0; i < beg; ++i)
++it;
while (it != end()) {
if (pattern.hasCharOrWhitespace(*it))
return i;
++it;
++i;
}
return NPos;
}
size_t String::findFirstNotOf(String const& pattern, size_t beg) const {
auto it = begin();
size_t i;
for (i = 0; i < beg; ++i)
++it;
while (it != end()) {
if (!pattern.hasCharOrWhitespace(*it))
return i;
++it;
++i;
}
return NPos;
}
size_t String::findNextBoundary(size_t index, bool backwards) const {
starAssert(index <= size());
if (!backwards && (index == size()))
return index;
if (backwards) {
if (index == 0)
return 0;
index--;
}
Char c = this->at(index);
while (!isSpace(c)) {
if (backwards && (index == 0))
return 0;
index += backwards ? -1 : 1;
if (index == size())
return size();
c = this->at(index);
}
while (isSpace(c)) {
if (backwards && (index == 0))
return 0;
index += backwards ? -1 : 1;
if (index == size())
return size();
c = this->at(index);
}
if (backwards && !(index == size()))
return index + 1;
return index;
}
String String::slice(SliceIndex a, SliceIndex b, int i) const {
auto wide = wideString();
wide = Star::slice(wide, a, b, i);
return String(wide.c_str());
}
void String::append(String const& string) {
m_string.append(string.m_string);
}
void String::append(std::string const& s) {
m_string.append(s);
}
void String::append(Char const* s) {
while (s)
append(*s++);
}
void String::append(Char const* s, size_t n) {
for (size_t i = 0; i < n; ++i)
append(s[i]);
}
void String::append(char const* s) {
m_string.append(s);
}
void String::append(char const* s, size_t n) {
m_string.append(s, n);
}
void String::append(Char c) {
char conv[6];
size_t size = utf8EncodeChar(conv, c, 6);
append(conv, size);
}
void String::prepend(String const& s) {
auto ns = s;
ns.append(*this);
*this = std::move(ns);
}
void String::prepend(std::string const& s) {
auto ns = String(s);
ns.append(*this);
*this = std::move(ns);
}
void String::prepend(Char const* s) {
auto ns = String(s);
ns.append(*this);
*this = std::move(ns);
}
void String::prepend(Char const* s, size_t n) {
auto ns = String(s, n);
ns.append(*this);
*this = std::move(ns);
}
void String::prepend(char const* s) {
auto ns = String(s);
ns.append(*this);
*this = std::move(ns);
}
void String::prepend(char const* s, size_t n) {
auto ns = String(s, n);
ns.append(*this);
*this = std::move(ns);
}
void String::prepend(Char c) {
auto ns = String(c, 1);
ns.append(*this);
*this = std::move(ns);
}
void String::push_back(Char c) {
append(c);
}
void String::push_front(Char c) {
prepend(c);
}
bool String::contains(String const& s, CaseSensitivity cs) const {
return find(s, 0, cs) != NPos;
}
bool String::regexMatch(String const& regex, bool full, bool caseSensitive) const {
if (full) {
if (caseSensitive)
return std::regex_match(utf8(), std::regex(regex.utf8()));
else
return std::regex_match(utf8(), std::regex(regex.utf8(), std::regex::icase));
} else {
if (caseSensitive)
return std::regex_search(utf8(), std::regex(regex.utf8()));
else
return std::regex_search(utf8(), std::regex(regex.utf8(), std::regex::icase));
}
}
int String::compare(String const& s, CaseSensitivity cs) const {
if (cs == CaseSensitive)
return m_string.compare(s.m_string);
else
return compare(0, NPos, s, 0, NPos, cs);
}
bool String::equals(String const& s, CaseSensitivity cs) const {
return compare(s, cs) == 0;
}
bool String::equalsIgnoreCase(String const& s) const {
return compare(s, CaseInsensitive) == 0;
}
String String::substr(size_t position, size_t n) const {
auto len = size();
if (position > len)
throw OutOfRangeException(strf("out of range in String::substr({}, {})", position, n));
if (position == 0 && n >= len)
return *this;
String ret;
ret.reserve(std::min(n, len - position));
auto it = begin();
std::advance(it, position);
for (size_t i = 0; i < n; ++i) {
if (it == end())
break;
ret.append(*it);
++it;
}
return ret;
}
void String::erase(size_t pos, size_t n) {
String ns;
ns.reserve(m_string.size() - std::min(n, m_string.size()));
auto it = begin();
for (size_t i = 0; i < pos; ++i)
ns.append(*it++);
for (size_t i = 0; i < n; ++i) {
if (it == end())
break;
++it;
}
while (it != end())
ns.append(*it++);
*this = ns;
}
String String::padLeft(size_t size, String const& filler) const {
if (!filler.length())
return *this;
String rs;
while (rs.length() + length() < size) {
rs.append(filler);
}
if (rs.length())
return rs + *this;
return *this;
}
String String::padRight(size_t size, String const& filler) const {
if (!filler.length())
return *this;
String rs = *this;
while (rs.length() < size) {
rs.append(filler);
}
return rs;
}
String& String::operator=(String const& s) {
m_string = s.m_string;
return *this;
}
String& String::operator=(String&& s) {
m_string = std::move(s.m_string);
return *this;
}
String& String::operator+=(String const& s) {
append(s);
return *this;
}
String& String::operator+=(std::string const& s) {
append(s);
return *this;
}
String& String::operator+=(Char const* s) {
append(s);
return *this;
}
String& String::operator+=(char const* s) {
append(s);
return *this;
}
String& String::operator+=(Char c) {
append(c);
return *this;
}
bool operator==(String const& s1, String const& s2) {
return s1.m_string == s2.m_string;
}
bool operator==(String const& s1, std::string const& s2) {
return s1.m_string == s2;
}
bool operator==(String const& s1, String::Char const* s2) {
return s1 == String(s2);
}
bool operator==(String const& s1, char const* s2) {
return s1.m_string == s2;
}
bool operator==(std::string const& s1, String const& s2) {
return s1 == s2.m_string;
}
bool operator==(String::Char const* s1, String const& s2) {
return String(s1) == s2;
}
bool operator==(char const* s1, String const& s2) {
return s1 == s2.m_string;
}
bool operator!=(String const& s1, String const& s2) {
return s1.m_string != s2.m_string;
}
bool operator!=(String const& s1, std::string const& s2) {
return s1.m_string != s2;
}
bool operator!=(String const& s1, String::Char const* s2) {
return s1 != String(s2);
}
bool operator!=(String const& s1, char const* s2) {
return s1.m_string != s2;
}
bool operator!=(std::string const& s1, String const& s2) {
return s1 != s2.m_string;
}
bool operator!=(String::Char const* s1, String const& s2) {
return String(s1) != s2;
}
bool operator!=(char const* s1, String const& s2) {
return s1 != s2.m_string;
}
bool operator<(String const& s1, String const& s2) {
return s1.m_string < s2.m_string;
}
bool operator<(String const& s1, std::string const& s2) {
return s1.m_string < s2;
}
bool operator<(String const& s1, String::Char const* s2) {
return s1 < String(s2);
}
bool operator<(String const& s1, char const* s2) {
return s1.m_string < s2;
}
bool operator<(std::string const& s1, String const& s2) {
return s1 < s2.m_string;
}
bool operator<(String::Char const* s1, String const& s2) {
return String(s1) < s2;
}
bool operator<(char const* s1, String const& s2) {
return s1 < s2.m_string;
}
String operator+(String s1, String const& s2) {
s1.append(s2);
return s1;
}
String operator+(String s1, std::string const& s2) {
s1.append(s2);
return s1;
}
String operator+(String s1, String::Char const* s2) {
s1.append(s2);
return s1;
}
String operator+(String s1, char const* s2) {
s1.append(s2);
return s1;
}
String operator+(std::string const& s1, String const& s2) {
return s1 + s2.m_string;
}
String operator+(String::Char const* s1, String const& s2) {
return String(s1) + s2;
}
String operator+(char const* s1, String const& s2) {
return s1 + s2.m_string;
}
String operator+(String s, String::Char c) {
s.append(c);
return s;
}
String operator+(String::Char c, String const& s) {
String res(c);
res.append(s);
return res;
}
String operator*(String const& s, unsigned times) {
String res;
for (unsigned i = 0; i < times; ++i)
res.append(s);
return res;
}
String operator*(unsigned times, String const& s) {
return s * times;
}
std::ostream& operator<<(std::ostream& os, String const& s) {
os << s.utf8();
return os;
}
std::istream& operator>>(std::istream& is, String& s) {
std::string temp;
is >> temp;
s = String(std::move(temp));
return is;
}
int String::compare(size_t selfOffset, size_t selfLen, String const& other,
size_t otherOffset, size_t otherLen, CaseSensitivity cs) const {
auto selfIt = begin();
auto otherIt = other.begin();
while (selfOffset > 0 && selfIt != end()) {
++selfIt;
--selfOffset;
}
while (otherOffset > 0 && otherIt != other.end()) {
++otherIt;
--otherLen;
}
while (true) {
if ((selfIt == end() || selfLen == 0) && (otherIt == other.end() || otherLen == 0))
return 0;
else if (selfIt == end() || selfLen == 0)
return -1;
else if (otherIt == other.end() || otherLen == 0)
return 1;
auto c1 = *selfIt;
auto c2 = *otherIt;
if (cs == CaseInsensitive) {
c1 = toLower(c1);
c2 = toLower(c2);
}
if (c1 < c2)
return -1;
else if (c2 < c1)
return 1;
++selfIt;
++otherIt;
--selfLen;
--otherLen;
}
}
StringList::StringList() : Base() {}
StringList::StringList(Base const& l) : Base(l) {}
StringList::StringList(Base&& l) : Base(std::move(l)) {}
StringList::StringList(StringList const& l) : Base(l) {}
StringList::StringList(StringList&& l) : Base(std::move(l)) {}
StringList::StringList(size_t n, String::Char const* const* list) {
for (size_t i = 0; i < n; ++i)
append(String(list[i]));
}
StringList::StringList(size_t n, char const* const* list) {
for (size_t i = 0; i < n; ++i)
append(String(list[i]));
}
StringList::StringList(size_t len, String const& s1) : Base(len, s1) {}
StringList::StringList(std::initializer_list<String> list) : Base(list) {}
StringList& StringList::operator=(Base const& rhs) {
Base::operator=(rhs);
return *this;
}
StringList& StringList::operator=(Base&& rhs) {
Base::operator=(std::move(rhs));
return *this;
}
StringList& StringList::operator=(StringList const& rhs) {
Base::operator=(rhs);
return *this;
}
StringList& StringList::operator=(StringList&& rhs) {
Base::operator=(std::move(rhs));
return *this;
}
StringList& StringList::operator=(initializer_list<String> list) {
Base::operator=(std::move(list));
return *this;
}
bool StringList::contains(String const& s, String::CaseSensitivity cs) const {
for (const_iterator i = begin(); i != end(); ++i) {
if (s.compare(*i, cs) == 0)
return true;
}
return false;
}
StringList StringList::trimAll(String const& pattern) const {
StringList r;
for (auto const& s : *this)
r.append(s.trim(pattern));
return r;
}
String StringList::join(String const& separator) const {
String joinedString;
for (const_iterator i = begin(); i != end(); ++i) {
if (i != begin())
joinedString += separator;
joinedString += *i;
}
return joinedString;
}
StringList StringList::slice(SliceIndex a, SliceIndex b, int i) const {
return Star::slice(*this, a, b, i);
}
StringList StringList::sorted() const {
StringList l = *this;
l.sort();
return l;
}
std::ostream& operator<<(std::ostream& os, const StringList& list) {
os << "(";
for (auto i = list.begin(); i != list.end(); ++i) {
if (i != list.begin())
os << ", ";
os << '\'' << *i << '\'';
}
os << ")";
return os;
}
size_t hash<StringList>::operator()(StringList const& sl) const {
size_t h = 0;
for (auto const& s : sl)
hashCombine(h, hashOf(s));
return h;
}
}
fmt::appender fmt::formatter<Star::String>::format(Star::String const& s, format_context& ctx) const {
return formatter<std::string>::format(s.utf8(), ctx);
};