pioneer/src/StringRange.h

191 lines
4.7 KiB
C++

// Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#ifndef _STRINGRANGE_H
#define _STRINGRANGE_H
#include <cassert>
#include <cctype>
#include <string>
struct StringRange {
StringRange() :
begin(0),
end(0) {}
StringRange(const char *begin_, const char *end_) :
begin(begin_),
end(end_)
{
assert(begin_ && end_);
assert((end_ - begin_) >= 0);
}
StringRange(const char *begin_, size_t size) :
begin(begin_),
end(begin_ + size)
{
assert(begin_);
}
const char *begin;
const char *end;
bool Empty() const { return (begin == end); }
size_t Size() const { return (end - begin); }
const char &operator[](size_t idx) const { return begin[idx]; }
const char &operator*() const { return *begin; }
std::string ToString() const { return begin ? std::string(begin, Size()) : std::string(); }
int Compare(const char *b) const;
friend bool operator==(const StringRange &a, const char *b) { return (a.Compare(b) == 0); }
friend bool operator!=(const StringRange &a, const char *b) { return (a.Compare(b) != 0); }
friend bool operator<=(const StringRange &a, const char *b) { return (a.Compare(b) <= 0); }
friend bool operator>=(const StringRange &a, const char *b) { return (a.Compare(b) >= 0); }
friend bool operator<(const StringRange &a, const char *b) { return (a.Compare(b) < 0); }
friend bool operator>(const StringRange &a, const char *b) { return (a.Compare(b) > 0); }
friend bool operator==(const char *a, const StringRange &b) { return (b.Compare(a) == 0); }
friend bool operator!=(const char *a, const StringRange &b) { return (b.Compare(a) != 0); }
friend bool operator<=(const char *a, const StringRange &b) { return (b.Compare(a) >= 0); }
friend bool operator>=(const char *a, const StringRange &b) { return (b.Compare(a) <= 0); }
friend bool operator<(const char *a, const StringRange &b) { return (b.Compare(a) > 0); }
friend bool operator>(const char *a, const StringRange &b) { return (b.Compare(a) < 0); }
const char *FindChar(char c) const;
const char *RFindChar(char c) const;
const char *FindSpace() const;
const char *RFindSpace() const;
const char *FindNewline() const;
const char *FindNonSpace() const;
const char *RFindNonSpace() const;
const char *FindNextLine() const;
StringRange StripUTF8BOM() const;
StringRange StripSpace() const;
StringRange ReadLine();
private:
static bool is_space(char c)
{
// MSVC's isspace() apparently asserts if you give it non-ASCII chars
// (maybe changing locale would help)
return (c == ' ') || (c == '\t') || (c == '\v') || (c == '\r') || (c == '\n');
}
};
inline StringRange StringRange::ReadLine()
{
StringRange line(begin, FindNextLine());
begin = line.end;
return line;
}
inline int StringRange::Compare(const char *b) const
{
const char *a = begin;
while (a != end && *b && *a == *b) {
++a;
++b;
}
if (a != end && *b) {
return (*a < *b ? -1 : 1);
}
if (a != end) {
return 1;
}
if (*b) {
return -1;
}
return 0;
}
inline const char *StringRange::FindChar(char c) const
{
const char *x = begin, *y = end;
while ((x != y) && (*x != c))
++x;
return x;
}
inline const char *StringRange::RFindChar(char c) const
{
const char *x = begin, *y = end;
while ((x != y) && (*--y != c)) {
}
return y;
}
inline const char *StringRange::FindSpace() const
{
const char *x = begin, *y = end;
while ((x != y) && !isspace(*x))
++x;
return x;
}
inline const char *StringRange::RFindSpace() const
{
const char *x = begin, *y = end;
while ((x != y) && !isspace(*--y)) {
}
return y;
}
inline const char *StringRange::FindNewline() const
{
const char *x = begin, *y = end;
while ((x != y) && (*x != '\r') && (*x != '\n'))
++x;
return x;
}
inline const char *StringRange::FindNextLine() const
{
const char *x = FindNewline(), *y = end;
if ((x != y) && (*x == '\r')) ++x;
if ((x != y) && (*x == '\n')) ++x;
return x;
}
inline const char *StringRange::FindNonSpace() const
{
const char *x = begin, *y = end;
while ((x != y) && is_space(*x))
++x;
return x;
}
inline const char *StringRange::RFindNonSpace() const
{
const char *x = begin, *y = end;
while ((x != y) && is_space(*--y)) {
}
return (y == end ? y : y + 1);
}
inline StringRange StringRange::StripUTF8BOM() const
{
if (Size() >= 3 && begin[0] == '\xEF' && begin[1] == '\xBB' && begin[2] == '\xBF')
return StringRange(begin + 3, end);
else
return *this;
}
inline StringRange StringRange::StripSpace() const
{
// can't just do StringRange(FindNonSpace(), RFindNonSpace())
// because if the string is *all* space then that will break the
// invariant that begin <= end
StringRange ss(FindNonSpace(), end);
ss.end = ss.RFindNonSpace();
return ss;
}
#endif