File indexing completed on 2024-11-15 09:01:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
0016 #define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
0017
0018 #include <cassert>
0019 #include <cstddef>
0020 #include <cstdint>
0021 #include <memory>
0022
0023 #include "absl/base/config.h"
0024 #include "absl/base/macros.h"
0025 #include "absl/strings/internal/cord_internal.h"
0026
0027 namespace absl {
0028 ABSL_NAMESPACE_BEGIN
0029 namespace cord_internal {
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 static constexpr size_t kFlatOverhead = offsetof(CordRep, storage);
0043 static constexpr size_t kMinFlatSize = 32;
0044 static constexpr size_t kMaxFlatSize = 4096;
0045 static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
0046 static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
0047 static constexpr size_t kMaxLargeFlatSize = 256 * 1024;
0048 static constexpr size_t kMaxLargeFlatLength = kMaxLargeFlatSize - kFlatOverhead;
0049
0050
0051
0052 static constexpr uint8_t kTagBase = FLAT - 4;
0053
0054
0055 constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
0056 return static_cast<uint8_t>(size <= 512 ? kTagBase + size / 8
0057 : size <= 8192
0058 ? kTagBase + 512 / 8 + size / 64 - 512 / 64
0059 : kTagBase + 512 / 8 + ((8192 - 512) / 64) +
0060 size / 4096 - 8192 / 4096);
0061 }
0062
0063
0064 constexpr size_t TagToAllocatedSize(uint8_t tag) {
0065 return (tag <= kTagBase + 512 / 8) ? tag * 8 - kTagBase * 8
0066 : (tag <= kTagBase + (512 / 8) + ((8192 - 512) / 64))
0067 ? 512 + tag * 64 - kTagBase * 64 - 512 / 8 * 64
0068 : 8192 + tag * 4096 - kTagBase * 4096 -
0069 ((512 / 8) + ((8192 - 512) / 64)) * 4096;
0070 }
0071
0072 static_assert(AllocatedSizeToTagUnchecked(kMinFlatSize) == FLAT, "");
0073 static_assert(AllocatedSizeToTagUnchecked(kMaxLargeFlatSize) == MAX_FLAT_TAG,
0074 "");
0075
0076
0077
0078 constexpr size_t RoundUp(size_t n, size_t m) {
0079 return (n + m - 1) & (0 - m);
0080 }
0081
0082
0083
0084 inline size_t RoundUpForTag(size_t size) {
0085 return RoundUp(size, (size <= 512) ? 8 : (size <= 8192 ? 64 : 4096));
0086 }
0087
0088
0089
0090
0091
0092 inline uint8_t AllocatedSizeToTag(size_t size) {
0093 const uint8_t tag = AllocatedSizeToTagUnchecked(size);
0094 assert(tag <= MAX_FLAT_TAG);
0095 return tag;
0096 }
0097
0098
0099 constexpr size_t TagToLength(uint8_t tag) {
0100 return TagToAllocatedSize(tag) - kFlatOverhead;
0101 }
0102
0103
0104 static_assert(TagToAllocatedSize(MAX_FLAT_TAG) == kMaxLargeFlatSize,
0105 "Bad tag logic");
0106
0107 struct CordRepFlat : public CordRep {
0108
0109 struct Large {};
0110
0111
0112 template <size_t max_flat_size, typename... Args>
0113 static CordRepFlat* NewImpl(size_t len, Args... args ABSL_ATTRIBUTE_UNUSED) {
0114 if (len <= kMinFlatLength) {
0115 len = kMinFlatLength;
0116 } else if (len > max_flat_size - kFlatOverhead) {
0117 len = max_flat_size - kFlatOverhead;
0118 }
0119
0120
0121 const size_t size = RoundUpForTag(len + kFlatOverhead);
0122 void* const raw_rep = ::operator new(size);
0123
0124 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(13, 0)
0125 #pragma GCC diagnostic push
0126 #pragma GCC diagnostic ignored "-Wstringop-overflow"
0127 #endif
0128 CordRepFlat* rep = new (raw_rep) CordRepFlat();
0129 rep->tag = AllocatedSizeToTag(size);
0130 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(13, 0)
0131 #pragma GCC diagnostic pop
0132 #endif
0133 return rep;
0134 }
0135
0136 static CordRepFlat* New(size_t len) { return NewImpl<kMaxFlatSize>(len); }
0137
0138 static CordRepFlat* New(Large, size_t len) {
0139 return NewImpl<kMaxLargeFlatSize>(len);
0140 }
0141
0142
0143
0144
0145 static void Delete(CordRep*rep) {
0146 assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
0147
0148 #if defined(__cpp_sized_deallocation)
0149 size_t size = TagToAllocatedSize(rep->tag);
0150 rep->~CordRep();
0151 ::operator delete(rep, size);
0152 #else
0153 rep->~CordRep();
0154 ::operator delete(rep);
0155 #endif
0156 }
0157
0158
0159
0160
0161 static CordRepFlat* Create(absl::string_view data, size_t extra = 0) {
0162 assert(data.size() <= kMaxFlatLength);
0163 CordRepFlat* flat = New(data.size() + (std::min)(extra, kMaxFlatLength));
0164 memcpy(flat->Data(), data.data(), data.size());
0165 flat->length = data.size();
0166 return flat;
0167 }
0168
0169
0170 char* Data() { return reinterpret_cast<char*>(storage); }
0171 const char* Data() const { return reinterpret_cast<const char*>(storage); }
0172
0173
0174 size_t Capacity() const { return TagToLength(tag); }
0175
0176
0177 size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
0178 };
0179
0180
0181 inline CordRepFlat* CordRep::flat() {
0182 assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
0183 return reinterpret_cast<CordRepFlat*>(this);
0184 }
0185
0186 inline const CordRepFlat* CordRep::flat() const {
0187 assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
0188 return reinterpret_cast<const CordRepFlat*>(this);
0189 }
0190
0191 }
0192 ABSL_NAMESPACE_END
0193 }
0194
0195 #endif