summaryrefslogtreecommitdiff
path: root/goo
diff options
context:
space:
mode:
authorAdam Reichold <adam.reichold@t-online.de>2018-10-06 12:04:04 +0200
committerAdam Reichold <adam.reichold@t-online.de>2018-10-29 19:19:18 +0100
commit48877b91db366293658a2561f08f110501872ce9 (patch)
treebc6cc314742c1a8261bab96630841cb1615e9cc3 /goo
parentebc05abc1dd0eed0f9a15fcc5a27195d141689ef (diff)
Replace the implementation of GooString by std::string but keep the exact interface intact.
The approach is slightly different to GooList as it reimplements GooString in terms of std::string but keeps its interface intact and does expose any std::string functionality as of now. This is done since GooString has a significantly larger API surface and exposing both API would be quite confusing with with some overloads from GooString and some from std::string being visible. But it does mean we can align the API (they are already pretty close) and expose new things like a reserve method piece by piece. It also already helps in that the implementation of GooString is gone except for the original parts, i.e. the formatting, and we have zero cost conversion from/to std::string which should help in making more use of it elsewhere. It also gives us do-nothing-access to optimizations done for the standard library, e.g. word-level implementations of cmp and friends. (Note that the resulting GooString.cc is a bit funny as the formatting helper are now local to the translation unit, but I had to redeclare them to keep the diff small as I did not change them at all. But if this is done, they could probably just be moved to where the declarations are to make the source file more readable.)
Diffstat (limited to 'goo')
-rw-r--r--goo/GooString.cc368
-rw-r--r--goo/GooString.h125
2 files changed, 128 insertions, 365 deletions
diff --git a/goo/GooString.cc b/goo/GooString.cc
index b1a7ae86..7e502435 100644
--- a/goo/GooString.cc
+++ b/goo/GooString.cc
@@ -35,19 +35,21 @@
#include <config.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <math.h>
+#include <cassert>
+#include <cctype>
+#include <cmath>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+
#include "gmem.h"
#include "GooString.h"
-static const int MAXIMUM_DOUBLE_PREC = 16;
-
//------------------------------------------------------------------------
+namespace
+{
+
union GooStringFormatArg {
int i;
Guint ui;
@@ -101,7 +103,7 @@ enum GooStringFormatType {
fmtSpace
};
-static const char *formatStrings[] = {
+const char *const formatStrings[] = {
"d", "x", "X", "o", "b", "ud", "ux", "uX", "uo", "ub",
"ld", "lx", "lX", "lo", "lb", "uld", "ulx", "ulX", "ulo", "ulb",
"lld", "llx", "llX", "llo", "llb",
@@ -114,176 +116,58 @@ static const char *formatStrings[] = {
nullptr
};
-//------------------------------------------------------------------------
-
-int inline GooString::roundedSize(int len) {
- int delta;
- if (len <= STR_STATIC_SIZE-1)
- return STR_STATIC_SIZE;
- delta = len < 256 ? 7 : 255;
- return ((len + 1) + delta) & ~delta;
-}
-
-// Make sure that the buffer is big enough to contain <newLength> characters
-// plus terminating 0.
-// We assume that if this is being called from the constructor, <s> was set
-// to NULL and <length> was set to 0 to indicate unused string before calling us.
-void inline GooString::resize(int newLength) {
- char *s1 = s;
-
- if (!s || (roundedSize(length) != roundedSize(newLength))) {
- // requires re-allocating data for string
- if (newLength < STR_STATIC_SIZE) {
- s1 = sStatic;
- } else {
- // allocate a rounded amount
- if (s == sStatic)
- s1 = (char*)gmalloc(roundedSize(newLength));
- else
- s1 = (char*)grealloc(s, roundedSize(newLength));
- }
- if (s == sStatic || s1 == sStatic) {
- // copy the minimum, we only need to if are moving to or
- // from sStatic.
- // assert(s != s1) the roundedSize condition ensures this
- if (newLength < length) {
- memcpy(s1, s, newLength);
- } else if (length > 0) {
- memcpy(s1, s, length);
- }
- if (s != sStatic)
- gfree(s);
- }
+void formatInt(long long x, char *buf, int bufSize,
+ bool zeroFill, int width, int base,
+ const char **p, int *len, bool upperCase = false);
- }
+void formatUInt(unsigned long long x, char *buf, int bufSize,
+ bool zeroFill, int width, int base,
+ const char **p, int *len, bool upperCase = false);
- s = s1;
- length = newLength;
- s[length] = '\0';
-}
+void formatDouble(double x, char *buf, int bufSize, int prec,
+ bool trim, const char **p, int *len);
-GooString* GooString::Set(const char *newStr, int newLen)
-{
- if (!newStr) {
- clear();
- return this;
- }
-
- if (newLen == CALC_STRING_LEN) {
- newLen = strlen(newStr);
- } else {
- assert(newLen >= 0);
- }
-
- resize(newLen);
- memmove(s, newStr, newLen);
-
- return this;
-}
-
-GooString::GooString() {
- s = nullptr;
- length = 0;
- Set(nullptr);
-
-#if __cplusplus >= 201103L
- static_assert(sizeof(GooString) == GooString::STR_FINAL_SIZE, "You should check memory alignment or STR_STATIC_SIZE calculation.");
-#endif
-}
-
-GooString::GooString(const char *sA) {
- s = nullptr;
- length = 0;
- Set(sA, CALC_STRING_LEN);
-}
+void formatDoubleSmallAware(double x, char *buf, int bufSize, int prec,
+ bool trim, const char **p, int *len);
-GooString::GooString(const char *sA, int lengthA) {
- s = nullptr;
- length = 0;
- Set(sA, lengthA);
}
-GooString::GooString(const GooString *str, int idx, int lengthA) {
- s = nullptr;
- length = 0;
- assert(idx + lengthA <= str->length);
- Set(str->getCString() + idx, lengthA);
-}
-
-GooString::GooString(const GooString *str) {
- s = nullptr;
- length = 0;
- Set(str->getCString(), str->length);
-}
-
-GooString::GooString(GooString *str1, GooString *str2) {
- s = nullptr;
- length = 0;
- resize(str1->length + str2->length);
- memcpy(s, str1->getCString(), str1->length);
- memcpy(s + str1->length, str2->getCString(), str2->length);
-}
+//------------------------------------------------------------------------
GooString *GooString::fromInt(int x) {
char buf[24]; // enough space for 64-bit ints plus a little extra
const char *p;
int len;
formatInt(x, buf, sizeof(buf), false, 0, 10, &p, &len);
- return new GooString(p, len);
+
+ return new GooString(buf, len);
}
GooString *GooString::format(const char *fmt, ...) {
- va_list argList;
- GooString *s;
+ auto *s = new GooString();
- s = new GooString();
+ va_list argList;
va_start(argList, fmt);
s->appendfv(fmt, argList);
va_end(argList);
+
return s;
}
GooString *GooString::formatv(const char *fmt, va_list argList) {
- GooString *s;
+ auto *s = new GooString();
- s = new GooString();
s->appendfv(fmt, argList);
- return s;
-}
-
-GooString::~GooString() {
- if (s != sStatic)
- gfree(s);
-}
-
-GooString *GooString::clear() {
- resize(0);
- return this;
-}
-GooString *GooString::append(char c) {
- return append((const char*)&c, 1);
-}
-
-GooString *GooString::append(const GooString *str) {
- return append(str->getCString(), str->getLength());
-}
-
-GooString *GooString::append(const char *str, int lengthA) {
- int prevLen = length;
- if (CALC_STRING_LEN == lengthA)
- lengthA = strlen(str);
- resize(length + lengthA);
- memcpy(s + prevLen, str, lengthA);
- return this;
+ return s;
}
GooString *GooString::appendf(const char *fmt, ...) {
va_list argList;
-
va_start(argList, fmt);
appendfv(fmt, argList);
va_end(argList);
+
return this;
}
@@ -615,12 +499,15 @@ GooString *GooString::appendfv(const char *fmt, va_list argList) {
return this;
}
-static const char lowerCaseDigits[17] = "0123456789abcdef";
-static const char upperCaseDigits[17] = "0123456789ABCDEF";
+namespace
+{
+
+const char lowerCaseDigits[17] = "0123456789abcdef";
+const char upperCaseDigits[17] = "0123456789ABCDEF";
-void GooString::formatInt(long long x, char *buf, int bufSize,
- bool zeroFill, int width, int base,
- const char **p, int *len, bool upperCase) {
+void formatInt(long long x, char *buf, int bufSize,
+ bool zeroFill, int width, int base,
+ const char **p, int *len, bool upperCase) {
const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
bool neg;
int start, i, j;
@@ -653,9 +540,9 @@ void GooString::formatInt(long long x, char *buf, int bufSize,
*len = bufSize - i;
}
-void GooString::formatUInt(unsigned long long x, char *buf, int bufSize,
- bool zeroFill, int width, int base,
- const char **p, int *len, bool upperCase) {
+void formatUInt(unsigned long long x, char *buf, int bufSize,
+ bool zeroFill, int width, int base,
+ const char **p, int *len, bool upperCase) {
const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
int i, j;
@@ -677,8 +564,8 @@ void GooString::formatUInt(unsigned long long x, char *buf, int bufSize,
*len = bufSize - i;
}
-void GooString::formatDouble(double x, char *buf, int bufSize, int prec,
- bool trim, const char **p, int *len) {
+void formatDouble(double x, char *buf, int bufSize, int prec,
+ bool trim, const char **p, int *len) {
bool neg, started;
double x2;
int d, i, j;
@@ -716,14 +603,14 @@ void GooString::formatDouble(double x, char *buf, int bufSize, int prec,
*len = bufSize - i;
}
-void GooString::formatDoubleSmallAware(double x, char *buf, int bufSize, int prec,
- bool trim, const char **p, int *len)
+void formatDoubleSmallAware(double x, char *buf, int bufSize, int prec,
+ bool trim, const char **p, int *len)
{
double absX = fabs(x);
if (absX >= 0.1) {
formatDouble(x, buf, bufSize, prec, trim, p, len);
} else {
- while (absX < 0.1 && prec < MAXIMUM_DOUBLE_PREC)
+ while (absX < 0.1 && prec < 16)
{
absX = absX * 10;
prec++;
@@ -732,190 +619,81 @@ void GooString::formatDoubleSmallAware(double x, char *buf, int bufSize, int pre
}
}
-GooString *GooString::insert(int i, char c) {
- return insert(i, (const char*)&c, 1);
-}
-
-GooString *GooString::insert(int i, const GooString *str) {
- return insert(i, str->getCString(), str->getLength());
-}
-
-GooString *GooString::insert(int i, const char *str, int lengthA) {
- int prevLen = length;
- if (CALC_STRING_LEN == lengthA)
- lengthA = strlen(str);
-
- resize(length + lengthA);
- memmove(s+i+lengthA, s+i, prevLen-i);
- memcpy(s+i, str, lengthA);
- return this;
}
-GooString *GooString::del(int i, int n) {
- int j;
-
- if (i >= 0 && n > 0 && i + n > 0) {
- if (i + n > length) {
- n = length - i;
- }
- for (j = i; j <= length - n; ++j) {
- s[j] = s[j + n];
+GooString *GooString::upperCase() {
+ for (auto& c : *this) {
+ if (std::islower(c)) {
+ c = std::toupper(c);
}
- resize(length - n);
}
- return this;
-}
-GooString *GooString::upperCase() {
- int i;
-
- for (i = 0; i < length; ++i) {
- if (islower(s[i]))
- s[i] = toupper(s[i]);
- }
return this;
}
GooString *GooString::lowerCase() {
- int i;
-
- for (i = 0; i < length; ++i) {
- if (isupper(s[i]))
- s[i] = tolower(s[i]);
- }
- return this;
-}
-
-int GooString::cmp(const GooString *str) const {
- int n1, n2, i, x;
- char *p1, *p2;
-
- n1 = length;
- n2 = str->length;
- for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
- x = *p1 - *p2;
- if (x != 0) {
- return x;
+ for (auto& c : *this) {
+ if (std::isupper(c)) {
+ c = std::tolower(c);
}
}
- return n1 - n2;
-}
-int GooString::cmpN(GooString *str, int n) const {
- int n1, n2, i, x;
- char *p1, *p2;
-
- n1 = length;
- n2 = str->length;
- for (i = 0, p1 = s, p2 = str->s;
- i < n1 && i < n2 && i < n;
- ++i, ++p1, ++p2) {
- x = *p1 - *p2;
- if (x != 0) {
- return x;
- }
- }
- if (i == n) {
- return 0;
- }
- return n1 - n2;
+ return this;
}
-int GooString::cmp(const char *sA) const {
- int n1, i, x;
- const char *p1, *p2;
-
- n1 = length;
- for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
- x = *p1 - *p2;
- if (x != 0) {
- return x;
- }
- }
- if (i < n1) {
- return 1;
- }
- if (*p2) {
- return -1;
- }
- return 0;
+void GooString::prependUnicodeMarker()
+{
+ insert(0, "\xFE\xFF", 2);
}
-int GooString::cmpN(const char *sA, int n) const {
- int n1, i, x;
- const char *p1, *p2;
+bool GooString::startsWith(const char *prefix) const {
+ const auto len = size();
+ const auto prefixLen = std::strlen(prefix);
- n1 = length;
- for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
- x = *p1 - *p2;
- if (x != 0) {
- return x;
- }
- }
- if (i == n) {
- return 0;
- }
- if (i < n1) {
- return 1;
- }
- if (*p2) {
- return -1;
- }
- return 0;
+ if (len < prefixLen)
+ return false;
+
+ return static_cast<const std::string&>(*this).compare(0, prefixLen, prefix) == 0;
}
bool GooString::endsWith(const char *suffix) const {
- int suffixLen = strlen(suffix);
+ const auto len = size();
+ const auto suffixLen = std::strlen(suffix);
- if (length < suffixLen)
+ if (len < suffixLen)
return false;
- return strcmp(s + length - suffixLen, suffix) == 0;
-}
-
-bool GooString::hasUnicodeMarker(void) const
-{
- return length > 1 && (s[0] & 0xff) == 0xfe && (s[1] & 0xff) == 0xff;
-}
-
-void GooString::prependUnicodeMarker()
-{
- insert(0, (char)0xff);
- insert(0, (char)0xfe);
+ return static_cast<const std::string&>(*this).compare(len - suffixLen, suffixLen, suffix) == 0;
}
GooString *GooString::sanitizedName(bool psmode) const
{
- GooString *name;
- char buf[8];
- int i;
- char c;
-
- name = new GooString();
+ auto *name = new GooString();
if (psmode)
{
// ghostscript chokes on names that begin with out-of-limits
// numbers, e.g., 1e4foo is handled correctly (as a name), but
// 1e999foo generates a limitcheck error
- c = getChar(0);
+ const auto c = getChar(0);
if (c >= '0' && c <= '9') {
name->append('f');
}
}
- for (i = 0; i < getLength(); ++i) {
- c = getChar(i);
+ for (const auto c : *this) {
if (c <= (char)0x20 || c >= (char)0x7f ||
c == ' ' ||
c == '(' || c == ')' || c == '<' || c == '>' ||
c == '[' || c == ']' || c == '{' || c == '}' ||
c == '/' || c == '%' || c == '#') {
+ char buf[8];
sprintf(buf, "#%02x", c & 0xff);
name->append(buf);
} else {
name->append(c);
}
}
+
return name;
}
diff --git a/goo/GooString.h b/goo/GooString.h
index 4b040942..b5160cf7 100644
--- a/goo/GooString.h
+++ b/goo/GooString.h
@@ -33,9 +33,9 @@
#ifndef GooString_H
#define GooString_H
-#include <stdarg.h>
-#include <stdlib.h> // for NULL
+#include <cstdarg>
#include <string>
+
#include "gtypes.h"
#ifdef __clang__
@@ -44,37 +44,52 @@
# define GOOSTRING_FORMAT
#endif
-class GooString {
+class GooString : private std::string {
public:
- // a special value telling that the length of the string is not given
- // so it must be calculated from the strings
- static const int CALC_STRING_LEN = -1;
-
// Create an empty string.
- GooString();
+ GooString() = default;
+
+ // Destructor.
+ ~GooString() = default;
+
+ GooString(GooString &&other) = default;
+ GooString& operator=(GooString &&other) = default;
+
+ GooString(const GooString &other) = delete;
+ GooString& operator=(const GooString &other) = delete;
// Create a string from a C string.
- explicit GooString(const char *sA);
+ explicit GooString(const char *sA) : std::string(sA) {}
+
+ // Zero-cost conversion from and to std::string
+ explicit GooString(const std::string& str) : std::string(str) {}
+ explicit GooString(std::string&& str) : std::string(std::move(str)) {}
+
+ const std::string& toStr() const { return *this; }
// Create a string from <lengthA> chars at <sA>. This string
// can contain null characters.
- GooString(const char *sA, int lengthA);
+ GooString(const char *sA, int lengthA) : std::string(sA, lengthA) {}
// Create a string from <lengthA> chars at <idx> in <str>.
- GooString(const GooString *str, int idx, int lengthA);
+ GooString(const GooString *str, int idx, int lengthA) : std::string(*str, idx, lengthA) {}
- // Set content of a string to <newStr>. If <newLen> is CALC_STRING_LEN, then
- // length of the string will be calculated with strlen(). Otherwise we assume
- // this is a valid length of <newStr> (or its substring)
- GooString* Set(const char *newStr, int newLen=CALC_STRING_LEN);
+ // Set content of a string to <newStr>.
+ GooString* Set(const GooString *newStr) { assign(*newStr); return this; }
+ GooString* Set(const char *newStr) { assign(newStr); return this; }
+ GooString* Set(const char *newStr, int newLen) { assign(newStr, newLen); return this; }
// Copy a string.
- explicit GooString(const GooString *str);
+ explicit GooString(const GooString *str) : std::string(*str) {}
GooString *copy() const { return new GooString(this); }
// Concatenate two strings.
- GooString(GooString *str1, GooString *str2);
+ GooString(const GooString *str1, const GooString *str2) {
+ reserve(str1->size() + str2->size());
+ static_cast<std::string&>(*this).append(*str1);
+ static_cast<std::string&>(*this).append(*str2);
+ }
// Convert an integer to a string.
static GooString *fromInt(int x);
@@ -109,95 +124,65 @@ public:
static GooString *format(const char *fmt, ...) GOOSTRING_FORMAT;
static GooString *formatv(const char *fmt, va_list argList);
- // Destructor.
- ~GooString();
-
// Get length.
- int getLength() const { return length; }
+ int getLength() const { return size(); }
// Get C string.
- const char *getCString() const { return s; }
+ const char *getCString() const { return c_str(); }
// Get <i>th character.
- char getChar(int i) const { return s[i]; }
+ char getChar(int i) const { return (*this)[i]; }
// Change <i>th character.
- void setChar(int i, char c) { s[i] = c; }
+ void setChar(int i, char c) { (*this)[i] = c; }
// Clear string to zero length.
- GooString *clear();
+ GooString *clear() { static_cast<std::string&>(*this).clear(); return this; }
// Append a character or string.
- GooString *append(char c);
- GooString *append(const GooString *str);
- GooString *append(const char *str, int lengthA=CALC_STRING_LEN);
+ GooString *append(char c) { push_back(c); return this; }
+ GooString *append(const GooString *str) { static_cast<std::string&>(*this).append(*str); return this; }
+ GooString *append(const char *str) { static_cast<std::string&>(*this).append(str); return this; }
+ GooString *append(const char *str, int lengthA) { static_cast<std::string&>(*this).append(str, lengthA); return this; }
// Append a formatted string.
GooString *appendf(const char *fmt, ...) GOOSTRING_FORMAT;
GooString *appendfv(const char *fmt, va_list argList);
// Insert a character or string.
- GooString *insert(int i, char c);
- GooString *insert(int i, const GooString *str);
- GooString *insert(int i, const char *str, int lengthA=CALC_STRING_LEN);
+ GooString *insert(int i, char c) { static_cast<std::string&>(*this).insert(i, 1, c); return this; }
+ GooString *insert(int i, const GooString *str) { static_cast<std::string&>(*this).insert(i, *str); return this; }
+ GooString *insert(int i, const char *str) { static_cast<std::string&>(*this).insert(i, str); return this; }
+ GooString *insert(int i, const char *str, int lengthA) { static_cast<std::string&>(*this).insert(i, str, lengthA); return this; }
// Delete a character or range of characters.
- GooString *del(int i, int n = 1);
+ GooString *del(int i, int n = 1) { erase(i, n); return this; }
// Convert string to all-upper/all-lower case.
GooString *upperCase();
GooString *lowerCase();
// Compare two strings: -1:< 0:= +1:>
- int cmp(const GooString *str) const;
- int cmpN(GooString *str, int n) const;
- int cmp(const char *sA) const;
- int cmpN(const char *sA, int n) const;
+ int cmp(const GooString *str) const { return compare(*str); }
+ int cmpN(GooString *str, int n) const { return compare(0, n, *str); }
+ int cmp(const char *sA) const { return compare(sA); }
+ int cmpN(const char *sA, int n) const { return compare(0, n, sA); }
+ // Return true if strings starts with prefix
+ bool startsWith(const char *prefix) const;
// Return true if string ends with suffix
bool endsWith(const char *suffix) const;
- bool hasUnicodeMarker(void) const;
+ bool hasUnicodeMarker() const { return size() >= 2 && (*this)[0] == char(0xfe) && (*this)[1] == char(0xff); }
+ bool hasJustUnicodeMarker() const { return size() == 2 && hasUnicodeMarker(); }
+
void prependUnicodeMarker();
- bool hasJustUnicodeMarker(void) const { return length == 2 && hasUnicodeMarker(); }
// Sanitizes the string so that it does
// not contain any ( ) < > [ ] { } / %
// The postscript mode also has some more strict checks
// The caller owns the return value
GooString *sanitizedName(bool psmode) const;
-
- // Conversion from and to std::string
- explicit GooString(const std::string& str) : GooString(str.data(), str.size()) {}
- std::string toStr() const { return std::string(getCString(), getLength()); }
-
-private:
- GooString(const GooString &other);
- GooString& operator=(const GooString &other);
-
- // You can tweak the final object size for different time/space tradeoffs.
- // In libc malloc(), rounding is 16 so it's best to choose a value that
- // is a multiple of 16.
- static const int STR_FINAL_SIZE = 32;
- static const int STR_STATIC_SIZE = STR_FINAL_SIZE - sizeof(int) - sizeof(char*);
-
- int roundedSize(int len);
-
- char sStatic[STR_STATIC_SIZE];
- int length;
- char *s;
-
- void resize(int newLength);
- static void formatInt(long long x, char *buf, int bufSize,
- bool zeroFill, int width, int base,
- const char **p, int *len, bool upperCase = false);
- static void formatUInt(unsigned long long x, char *buf, int bufSize,
- bool zeroFill, int width, int base,
- const char **p, int *len, bool upperCase = false);
- static void formatDouble(double x, char *buf, int bufSize, int prec,
- bool trim, const char **p, int *len);
- static void formatDoubleSmallAware(double x, char *buf, int bufSize, int prec,
- bool trim, const char **p, int *len);
};
#endif