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)); auto const sd = allocFlatForLenSmall(cap); // Request-allocated StringData are always aligned at 16 bytes, thus it is // safe to copy in 16-byte groups. #ifdef NO_M_DATA // layout: [m_lenAndHash][header][...data] sd->m_lenAndHash = m_lenAndHash; // This copies the characters (m_len bytes), and the trailing zero (1 byte) memcpy16_inline(sd+1, this+1, (m_len + 1 + 15) & ~0xF); assertx(reinterpret_cast<uintptr_t>(this+1) % 16 == 0); #else // layout: [m_data][header][m_lenAndHash][...data] // This copies m_lenAndHash (8 bytes), the characters (m_len bytes), // and 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); #endif assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(size_t reserveLen) { auto const sd = allocFlatForLenSmall(reserveLen); sd->setSize(0); assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(const StringData* s, CopyStringMode) { auto const sd = allocFlatForLenSmall(s->m_len); sd->m_lenAndHash = s->m_lenAndHash; auto const data = static_cast<void*>(sd + 1); *memcpy8(data, s->data(), s->m_len) = 0; assert(sd->same(s)); return sd; }
// State transition from Mode::Shared to Mode::Flat. StringData* StringData::escalate(size_t cap) { assert(isShared() && !isStatic() && cap >= m_len); auto const sd = allocFlatForLenSmall(cap); sd->m_lenAndHash = m_lenAndHash; auto const data = reinterpret_cast<char*>(sd + 1); *memcpy8(data, m_data, m_len) = 0; assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::shrinkImpl(size_t len) { assert(!isImmutable() && !hasMultipleRefs()); assert(isFlat()); assert(len <= capacity()); auto const sd = allocFlatForLenSmall(len); sd->m_lenAndHash = len; auto const src = static_cast<void*>(this + 1); auto const dst = static_cast<void*>(sd + 1); *memcpy8(dst, src, len) = 0; assert(sd->checkSane()); return sd; }
StringData* StringData::Make(StringSlice r1, StringSlice r2) { auto const len = r1.len + r2.len; auto const sd = allocFlatForLenSmall(len); sd->m_lenAndHash = len; // hash=0 auto const data = reinterpret_cast<char*>(sd + 1); 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(folly::StringPiece r1, folly::StringPiece r2) { auto const len = r1.size() + r2.size(); auto const sd = allocFlatForLenSmall(len); sd->m_lenAndHash = len; // hash=0 auto const data = reinterpret_cast<char*>(sd + 1); memcpy(data, r1.data(), r1.size()); memcpy(data + r1.size(), r2.data(), r2.size()); 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 sd = allocFlatForLenSmall(len + 6); sd->m_lenAndHash = len; // hash=0 auto const data = reinterpret_cast<char*>(sd + 1); auto const 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 r1, StringSlice r2, StringSlice r3) { auto const len = r1.len + r2.len + r3.len; auto const sd = allocFlatForLenSmall(len); sd->m_lenAndHash = len; // hash=0 char* p = reinterpret_cast<char*>(sd + 1); p = static_cast<char*>(memcpy(p, r1.ptr, r1.len)); p = static_cast<char*>(memcpy(p + r1.len, r2.ptr, r2.len)); p = static_cast<char*>(memcpy(p + r2.len, r3.ptr, r3.len)); p[r3.len] = 0; assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(folly::StringPiece r1, folly::StringPiece r2, folly::StringPiece r3) { auto const len = r1.size() + r2.size() + r3.size(); auto const sd = allocFlatForLenSmall(len); sd->m_lenAndHash = len; // hash=0 auto p = reinterpret_cast<char*>(sd + 1); p = static_cast<char*>(memcpy(p, r1.data(), r1.size())); p = static_cast<char*>(memcpy(p + r1.size(), r2.data(), r2.size())); p = static_cast<char*>(memcpy(p + r2.size(), r3.data(), r3.size())); p[r3.size()] = 0; assert(sd->hasExactlyOneRef()); assert(sd->isFlat()); assert(sd->checkSane()); return sd; }
StringData* StringData::Make(StringSlice sl, CopyStringMode) { auto const sd = allocFlatForLenSmall(sl.len); sd->m_lenAndHash = sl.len; // hash=0 auto const data = reinterpret_cast<char*>(sd + 1); 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; }