Do copying with the AttachLiteral constructors.
And, remove the IsLiteral string kind. This removes the hazard of creating a string whose data is freed before the string. Callsites passing in a literal should use StaticString. Everything else can use CopyString or AttachString.
Esse commit está contido em:
@@ -166,25 +166,6 @@ Array StringData::GetConstants() {
|
||||
return a;
|
||||
}
|
||||
|
||||
void StringData::initLiteral(const char* data) {
|
||||
return initLiteral(data, strlen(data));
|
||||
}
|
||||
|
||||
void StringData::initLiteral(const char* data, int len) {
|
||||
if (uint32_t(len) > MaxSize) {
|
||||
throw InvalidArgumentException("len > 2^31-2", len);
|
||||
}
|
||||
// Do not copy literals, this StringData can have a shorter lifetime than
|
||||
// the literal, and the client can count on this->data() giving back
|
||||
// the literal ptr with the longer lifetime. Sketchy!
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_len = len;
|
||||
m_cdata = data;
|
||||
m_big.cap = len | IsLiteral;
|
||||
assert(checkSane());
|
||||
}
|
||||
|
||||
void StringData::enlist() {
|
||||
assert(isShared());
|
||||
SweepNode& head = MemoryManager::TheMemoryManager()->m_strings;
|
||||
@@ -403,7 +384,7 @@ void StringData::append(const char *s, int len) {
|
||||
// TODO: t1122987: in any of the cases below where we need a bigger buffer,
|
||||
// we can probably assume we're in a concat-loop and pick a good buffer
|
||||
// size to avoid O(N^2) copying cost.
|
||||
if (isShared() || isLiteral()) {
|
||||
if (isShared()) {
|
||||
// buffer is immutable, don't modify it.
|
||||
StringSlice r = slice();
|
||||
char* newdata = smart_concat(r.ptr, r.len, s, len);
|
||||
@@ -533,12 +514,8 @@ StringData *StringData::copy(bool sharedMemory /* = false */) const {
|
||||
// which will be freed at the end of the request, and so must be
|
||||
// copied.
|
||||
return new StringData(data(), size(), CopyMalloc);
|
||||
} else {
|
||||
if (isLiteral()) {
|
||||
return NEW(StringData)(data(), size(), AttachLiteral);
|
||||
}
|
||||
return NEW(StringData)(data(), size(), CopyString);
|
||||
}
|
||||
return NEW(StringData)(data(), size(), CopyString);
|
||||
}
|
||||
|
||||
MutableSlice StringData::escalate(uint32_t cap) {
|
||||
@@ -568,8 +545,7 @@ StringData *StringData::Escalate(StringData *in) {
|
||||
void StringData::dump() const {
|
||||
StringSlice s = slice();
|
||||
|
||||
printf("StringData(%d) (%s%s%s%d): [", _count,
|
||||
isLiteral() ? "literal " : "",
|
||||
printf("StringData(%d) (%s%s%d): [", _count,
|
||||
isShared() ? "shared " : "",
|
||||
isStatic() ? "static " : "",
|
||||
s.len);
|
||||
|
||||
@@ -50,12 +50,6 @@ struct Slice {
|
||||
typedef Slice<const char> StringSlice;
|
||||
typedef Slice<char> MutableSlice;
|
||||
|
||||
// const char* points to a string which must remain valid for the lifetime
|
||||
// of the StringData. It is fragile to rely on StringData.data() returning
|
||||
// the same pointer after construction -- this invariant will probably be
|
||||
// deprecated to enable copying of small strings.
|
||||
enum AttachLiteralMode { AttachLiteral };
|
||||
|
||||
// Aggressively copy small strings and free the passed-in buffer immediately;
|
||||
// otherwise keep the buffer for long strings, and free it when the string
|
||||
// is mutated or released.
|
||||
@@ -64,7 +58,7 @@ enum AttachStringMode { AttachString };
|
||||
// const char* points to client-owned memory, StringData will copy it
|
||||
// at construct-time using smart_malloc. This is only ok when the StringData
|
||||
// itself was smart-allocated.
|
||||
enum CopyStringMode { CopyString };
|
||||
enum CopyStringMode { CopyString, AttachLiteral = CopyString };
|
||||
|
||||
// reserve space for buffer that will be filled in by client.
|
||||
enum ReserveStringMode { ReserveString };
|
||||
@@ -89,7 +83,7 @@ enum CopyMallocMode { CopyMalloc };
|
||||
* big: m_data:8, _count:4, m_len:4, m_hash:4,
|
||||
* junk[12], node:16, shared:8, cap:8
|
||||
*
|
||||
* If the format is IsLiteral or IsShared, we always use the "big" layout.
|
||||
* If the format is IsShared, we always use the "big" layout.
|
||||
* resemblences to fbstring are not accidental.
|
||||
*/
|
||||
class StringData {
|
||||
@@ -99,10 +93,9 @@ class StringData {
|
||||
|
||||
enum Format {
|
||||
IsSmall = 0, // short str overlaps m_big
|
||||
IsLiteral = 0x1000000000000000, // literal string
|
||||
IsShared = 0x2000000000000000, // shared memory string
|
||||
IsMalloc = 0x3000000000000000, // m_big.data is malloc'd
|
||||
IsSmart = 0x4000000000000000, // m_big.data is smart_malloc'd
|
||||
IsShared = 0x1000000000000000, // shared memory string
|
||||
IsMalloc = 0x2000000000000000, // m_big.data is malloc'd
|
||||
IsSmart = 0x3000000000000000, // m_big.data is smart_malloc'd
|
||||
IsMask = 0xF000000000000000
|
||||
};
|
||||
|
||||
@@ -155,10 +148,7 @@ class StringData {
|
||||
* is actually only for SmartAllocator to pre-allocate the objects.
|
||||
*/
|
||||
explicit StringData(const char* data) {
|
||||
initLiteral(data);
|
||||
}
|
||||
StringData(const char *data, AttachLiteralMode) {
|
||||
initLiteral(data);
|
||||
initCopy(data);
|
||||
}
|
||||
StringData(const char *data, AttachStringMode) {
|
||||
initAttach(data);
|
||||
@@ -166,10 +156,6 @@ class StringData {
|
||||
StringData(const char *data, CopyStringMode) {
|
||||
initCopy(data);
|
||||
}
|
||||
|
||||
StringData(const char *data, int len, AttachLiteralMode) {
|
||||
initLiteral(data, len);
|
||||
}
|
||||
StringData(const char* data, int len, AttachStringMode) {
|
||||
initAttach(data, len);
|
||||
}
|
||||
@@ -263,13 +249,9 @@ public:
|
||||
return StringSlice(m_data, m_len);
|
||||
}
|
||||
bool empty() const { return size() == 0;}
|
||||
bool isLiteral() const { return format() == IsLiteral; }
|
||||
bool isShared() const { return format() == IsShared; }
|
||||
bool isSmall() const { return format() == IsSmall; }
|
||||
bool isImmutable() const {
|
||||
Format f = format();
|
||||
return f == IsLiteral || f == IsShared || isStatic();
|
||||
}
|
||||
bool isImmutable() const { return isShared() || isStatic(); }
|
||||
DataType isNumericWithVal(int64_t &lval, double &dval, int allow_errors) const;
|
||||
bool isNumeric() const;
|
||||
bool isInteger() const;
|
||||
@@ -407,10 +389,8 @@ public:
|
||||
/**
|
||||
* Helpers.
|
||||
*/
|
||||
void initLiteral(const char* data);
|
||||
void initAttach(const char* data);
|
||||
void initCopy(const char* data);
|
||||
void initLiteral(const char* data, int len);
|
||||
void initAttach(const char* data, int len);
|
||||
void initCopy(const char* data, int len);
|
||||
void initMalloc(const char* data, int len);
|
||||
|
||||
@@ -148,13 +148,6 @@ public:
|
||||
m_px = NEW(StringData)(s.data(), s.size(), CopyString);
|
||||
m_px->setRefCount(1);
|
||||
}
|
||||
// attach to null terminated string literal
|
||||
String(const char *s, AttachLiteralMode mode) {
|
||||
if (s) {
|
||||
m_px = NEW(StringData)(s, mode);
|
||||
m_px->setRefCount(1);
|
||||
}
|
||||
}
|
||||
// attach to null terminated malloc'ed string, maybe free it now.
|
||||
String(const char *s, AttachStringMode mode) {
|
||||
if (s) {
|
||||
@@ -169,13 +162,6 @@ public:
|
||||
m_px->setRefCount(1);
|
||||
}
|
||||
}
|
||||
// attach to binary string literal
|
||||
String(const char *s, int length, AttachLiteralMode mode) {
|
||||
if (s) {
|
||||
m_px = NEW(StringData)(s, length, mode);
|
||||
m_px->setRefCount(1);
|
||||
}
|
||||
}
|
||||
// attach to binary malloc'ed string
|
||||
String(const char *s, int length, AttachStringMode mode) {
|
||||
if (s) {
|
||||
@@ -261,9 +247,6 @@ public:
|
||||
bool isValidVariableName() const {
|
||||
return m_px ? m_px->isValidVariableName() : false;
|
||||
}
|
||||
bool isLiteral() const {
|
||||
return m_px ? m_px->isLiteral() : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a sub-string from start with specified length. Note, read
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário