StringData* StringData::reserve(size_t cap) { assert(!isImmutable() && !hasMultipleRefs()); assert(isFlat()); if (cap <= capacity()) return this; cap = std::min(cap + cap / 4, size_t(MaxSize) + 1); auto const allocRet = allocFlatForLen(cap); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); // request-allocated StringData are always aligned at 16 bytes, thus it is // safe to copy in 16-byte groups. This copies m_lenAndHash (8 bytes), the // characters (m_len bytes), add the trailing zero (1 byte). memcpy16_inline(&sd->m_lenAndHash, &m_lenAndHash, (m_len + 8 + 1 + 15) & ~0xF); assertx(reinterpret_cast<uintptr_t>(&m_lenAndHash) + 8 == reinterpret_cast<uintptr_t>(m_data)); assertx(reinterpret_cast<uintptr_t>(&m_lenAndHash) % 16 == 0); assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(const StringData* s, CopyStringMode) { auto const allocRet = allocFlatForLen(s->m_len); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = s->m_lenAndHash; *memcpy8(data, s->m_data, s->m_len) = 0; assert(sd->same(s)); return sd; }
StringData* StringData::Make(size_t reserveLen) { auto const allocRet = allocFlatForLen(reserveLen); auto const sd = allocRet.first; auto const capCode = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); data[0] = 0; sd->m_data = data; sd->m_capAndCount = HeaderKind::String << 24 | capCode; // count=0 sd->m_lenAndHash = 0; // len=hash=0 assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(size_t reserveLen) { auto const allocRet = allocFlatForLen(reserveLen); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); data[0] = 0; sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = 0; // len=hash=0 assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
// State transition from Mode::Shared to Mode::Flat. StringData* StringData::escalate(size_t cap) { assert(isShared() && !isStatic() && cap >= m_len); auto const allocRet = allocFlatForLen(cap); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = m_lenAndHash; *memcpy8(data, m_data, m_len) = 0; assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(StringSlice r1, StringSlice r2) { auto const len = r1.len + r2.len; auto const allocRet = allocFlatForLen(len); auto const sd = allocRet.first; auto const capCode = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_capAndCount = HeaderKind::String << 24 | capCode; // count=0 sd->m_lenAndHash = len; // hash=0 memcpy(data, r1.ptr, r1.len); memcpy(data + r1.len, r2.ptr, r2.len); data[len] = 0; assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(StringSlice r1, StringSlice r2) { auto const len = r1.len + r2.len; auto const allocRet = allocFlatForLen(len); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = len; // hash=0 memcpy(data, r1.ptr, r1.len); memcpy(data + r1.len, r2.ptr, r2.len); data[len] = 0; assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(const StringData* s1, const StringData* s2) { auto const len = s1->m_len + s2->m_len; // `memcpy8()` could overrun the buffer by at most 7 bytes, so we allocate 6 // more bytes here, which (together with the trailing 0) makes it safe. auto const allocRet = allocFlatForLen(len + 6); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = len; // hash=0 auto next = memcpy8(data, s1->m_data, s1->m_len); *memcpy8(next, s2->m_data, s2->m_len) = 0; assert(sd->getCount() == 1); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(StringSlice sl, CopyStringMode) { auto const allocRet = allocFlatForLen(sl.len); auto const sd = allocRet.first; auto const cc = allocRet.second; auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = sl.len; // hash=0 data[sl.len] = 0; auto const mcret = memcpy(data, sl.ptr, sl.len); auto const ret = reinterpret_cast<StringData*>(mcret) - 1; // Recalculating ret from mcret avoids a spill. assert(ret == sd); assert(ret->m_len == sl.len); assert(ret->hasExactlyOneRef()); assert(ret->m_hash == 0); assert(ret->isFlat()); assert(ret->checkSane()); return ret; }