TestBufferList.cpp (13173B)
1 /* -*- Mode: C++; tab-width: 9; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // This is included first to ensure it doesn't implicitly depend on anything 8 // else. 9 #include "mozilla/BufferList.h" 10 #include "mozilla/CheckedArithmetic.h" 11 12 // It would be nice if we could use the InfallibleAllocPolicy from mozalloc, 13 // but MFBT cannot use mozalloc. 14 class InfallibleAllocPolicy { 15 public: 16 template <typename T> 17 T* pod_malloc(size_t aNumElems) { 18 size_t size; 19 if (!mozilla::SafeMul(aNumElems, sizeof(T), &size)) { 20 MOZ_CRASH("TestBufferList.cpp: overflow"); 21 } 22 T* rv = static_cast<T*>(malloc(size)); 23 if (!rv) { 24 MOZ_CRASH("TestBufferList.cpp: out of memory"); 25 } 26 return rv; 27 } 28 29 template <typename T> 30 void free_(T* aPtr, size_t aNumElems = 0) { 31 free(aPtr); 32 } 33 34 void reportAllocOverflow() const {} 35 36 bool checkSimulatedOOM() const { return true; } 37 }; 38 39 typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList; 40 41 int main(void) { 42 const size_t kInitialSize = 16; 43 const size_t kInitialCapacity = 24; 44 const size_t kStandardCapacity = 32; 45 46 BufferList bl(kInitialSize, kInitialCapacity, kStandardCapacity); 47 48 memset(bl.Start(), 0x0c, kInitialSize); 49 MOZ_RELEASE_ASSERT(bl.Size() == kInitialSize); 50 51 // Simple iteration and access. 52 53 BufferList::IterImpl iter(bl.Iter()); 54 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialSize); 55 MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialSize)); 56 MOZ_RELEASE_ASSERT(!iter.HasRoomFor(kInitialSize + 1)); 57 MOZ_RELEASE_ASSERT(!iter.HasRoomFor(size_t(-1))); 58 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0c); 59 MOZ_RELEASE_ASSERT(!iter.Done()); 60 61 iter.Advance(bl, 4); 62 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialSize - 4); 63 MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialSize - 4)); 64 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0c); 65 MOZ_RELEASE_ASSERT(!iter.Done()); 66 67 iter.Advance(bl, 11); 68 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialSize - 4 - 11); 69 MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialSize - 4 - 11)); 70 MOZ_RELEASE_ASSERT(!iter.HasRoomFor(kInitialSize - 4 - 11 + 1)); 71 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0c); 72 MOZ_RELEASE_ASSERT(!iter.Done()); 73 74 iter.Advance(bl, kInitialSize - 4 - 11); 75 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 0); 76 MOZ_RELEASE_ASSERT(!iter.HasRoomFor(1)); 77 MOZ_RELEASE_ASSERT(iter.Done()); 78 79 // Writing to the buffer. 80 81 const size_t kSmallWrite = 16; 82 83 char toWrite[kSmallWrite]; 84 memset(toWrite, 0x0a, kSmallWrite); 85 MOZ_ALWAYS_TRUE(bl.WriteBytes(toWrite, kSmallWrite)); 86 87 MOZ_RELEASE_ASSERT(bl.Size() == kInitialSize + kSmallWrite); 88 89 iter = bl.Iter(); 90 iter.Advance(bl, kInitialSize); 91 MOZ_RELEASE_ASSERT(!iter.Done()); 92 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 93 kInitialCapacity - kInitialSize); 94 MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialCapacity - kInitialSize)); 95 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a); 96 97 // AdvanceAcrossSegments. 98 99 iter = bl.Iter(); 100 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kInitialCapacity - 4)); 101 MOZ_RELEASE_ASSERT(!iter.Done()); 102 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 4); 103 MOZ_RELEASE_ASSERT(iter.HasRoomFor(4)); 104 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a); 105 106 iter = bl.Iter(); 107 MOZ_RELEASE_ASSERT( 108 iter.AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite - 4)); 109 MOZ_RELEASE_ASSERT(!iter.Done()); 110 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 4); 111 MOZ_RELEASE_ASSERT(iter.HasRoomFor(4)); 112 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a); 113 114 MOZ_RELEASE_ASSERT( 115 bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite - 1)); 116 MOZ_RELEASE_ASSERT( 117 bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite)); 118 MOZ_RELEASE_ASSERT( 119 !bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite + 1)); 120 MOZ_RELEASE_ASSERT(!bl.Iter().AdvanceAcrossSegments(bl, size_t(-1))); 121 122 // Reading non-contiguous bytes. 123 124 char toRead[kSmallWrite]; 125 iter = bl.Iter(); 126 iter.Advance(bl, kInitialSize); 127 bl.ReadBytes(iter, toRead, kSmallWrite); 128 MOZ_RELEASE_ASSERT(memcmp(toRead, toWrite, kSmallWrite) == 0); 129 MOZ_RELEASE_ASSERT(iter.Done()); 130 131 // Make sure reading up to the end of a segment advances the iter to the next 132 // segment. 133 iter = bl.Iter(); 134 bl.ReadBytes(iter, toRead, kInitialSize); 135 MOZ_RELEASE_ASSERT(!iter.Done()); 136 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 137 kInitialCapacity - kInitialSize); 138 139 const size_t kBigWrite = 1024; 140 141 char* toWriteBig = static_cast<char*>(malloc(kBigWrite)); 142 for (unsigned i = 0; i < kBigWrite; i++) { 143 toWriteBig[i] = i % 37; 144 } 145 MOZ_ALWAYS_TRUE(bl.WriteBytes(toWriteBig, kBigWrite)); 146 147 char* toReadBig = static_cast<char*>(malloc(kBigWrite)); 148 iter = bl.Iter(); 149 MOZ_RELEASE_ASSERT( 150 iter.AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite)); 151 bl.ReadBytes(iter, toReadBig, kBigWrite); 152 MOZ_RELEASE_ASSERT(memcmp(toReadBig, toWriteBig, kBigWrite) == 0); 153 MOZ_RELEASE_ASSERT(iter.Done()); 154 155 free(toReadBig); 156 free(toWriteBig); 157 158 // Currently bl contains these segments: 159 // #0: offset 0, [0x0c]*16 + [0x0a]*8, size 24 160 // #1: offset 24, [0x0a]*8 + [i%37 for i in 0..24], size 32 161 // #2: offset 56, [i%37 for i in 24..56, size 32 162 // ... 163 // #32: offset 1016, [i%37 for i in 984..1016], size 32 164 // #33: offset 1048, [i%37 for i in 1016..1024], size 8 165 166 static size_t kTotalSize = kInitialSize + kSmallWrite + kBigWrite; 167 168 MOZ_RELEASE_ASSERT(bl.Size() == kTotalSize); 169 170 static size_t kLastSegmentSize = 171 (kTotalSize - kInitialCapacity) % kStandardCapacity; 172 173 iter = bl.Iter(); 174 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments( 175 bl, kTotalSize - kLastSegmentSize - kStandardCapacity)); 176 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kStandardCapacity); 177 iter.Advance(bl, kStandardCapacity); 178 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kLastSegmentSize); 179 MOZ_RELEASE_ASSERT( 180 unsigned(*iter.Data()) == 181 (kTotalSize - kLastSegmentSize - kInitialSize - kSmallWrite) % 37); 182 183 // Clear. 184 185 bl.Clear(); 186 MOZ_RELEASE_ASSERT(bl.Size() == 0); 187 MOZ_RELEASE_ASSERT(bl.Iter().Done()); 188 189 // Move assignment. 190 191 const size_t kSmallCapacity = 8; 192 193 BufferList bl2(0, kSmallCapacity, kSmallCapacity); 194 MOZ_ALWAYS_TRUE(bl2.WriteBytes(toWrite, kSmallWrite)); 195 MOZ_ALWAYS_TRUE(bl2.WriteBytes(toWrite, kSmallWrite)); 196 MOZ_ALWAYS_TRUE(bl2.WriteBytes(toWrite, kSmallWrite)); 197 198 bl = std::move(bl2); 199 MOZ_RELEASE_ASSERT(bl2.Size() == 0); 200 MOZ_RELEASE_ASSERT(bl2.Iter().Done()); 201 202 iter = bl.Iter(); 203 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3)); 204 MOZ_RELEASE_ASSERT(iter.Done()); 205 206 // MoveFallible 207 208 bool success; 209 bl2 = bl.MoveFallible<InfallibleAllocPolicy>(&success); 210 MOZ_RELEASE_ASSERT(success); 211 MOZ_RELEASE_ASSERT(bl.Size() == 0); 212 MOZ_RELEASE_ASSERT(bl.Iter().Done()); 213 MOZ_RELEASE_ASSERT(bl2.Size() == kSmallWrite * 3); 214 215 iter = bl2.Iter(); 216 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kSmallWrite * 3)); 217 MOZ_RELEASE_ASSERT(iter.Done()); 218 219 bl = bl2.MoveFallible<InfallibleAllocPolicy>(&success); 220 221 // Borrowing. 222 223 const size_t kBorrowStart = 4; 224 const size_t kBorrowSize = 24; 225 226 iter = bl.Iter(); 227 iter.Advance(bl, kBorrowStart); 228 bl2 = bl.Borrow<InfallibleAllocPolicy>(iter, kBorrowSize, &success); 229 MOZ_RELEASE_ASSERT(success); 230 MOZ_RELEASE_ASSERT(bl2.Size() == kBorrowSize); 231 232 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments( 233 bl, kSmallWrite * 3 - kBorrowSize - kBorrowStart)); 234 MOZ_RELEASE_ASSERT(iter.Done()); 235 236 iter = bl2.Iter(); 237 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kBorrowSize)); 238 MOZ_RELEASE_ASSERT(iter.Done()); 239 240 BufferList::IterImpl iter1(bl.Iter()), iter2(bl2.Iter()); 241 iter1.Advance(bl, kBorrowStart); 242 MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data()); 243 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl, kBorrowSize - 5)); 244 MOZ_RELEASE_ASSERT(iter2.AdvanceAcrossSegments(bl2, kBorrowSize - 5)); 245 MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data()); 246 247 // RangeLength. 248 249 BufferList bl12(0, 0, 8); 250 MOZ_ALWAYS_TRUE(bl12.WriteBytes("abcdefgh", 8)); 251 MOZ_ALWAYS_TRUE(bl12.WriteBytes("12345678", 8)); 252 253 // |iter| is at position 0 (1st segment). 254 iter = bl12.Iter(); 255 iter1 = bl12.Iter(); 256 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0); 257 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 258 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4); 259 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 260 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 8); 261 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 262 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 12); 263 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 3)); 264 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 15); 265 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1)); 266 MOZ_RELEASE_ASSERT(iter1.Done()); 267 268 // |iter| is at position 1 (1st segment). 269 iter = bl12.Iter(); 270 iter1 = bl12.Iter(); 271 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl12, 1)); 272 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1)); 273 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0); 274 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 275 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4); 276 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 277 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 8); 278 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 279 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 12); 280 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 2)); 281 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 14); 282 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1)); 283 MOZ_RELEASE_ASSERT(iter1.Done()); 284 285 // |iter| is at position 8 (2nd segment). 286 iter = bl12.Iter(); 287 iter1 = bl12.Iter(); 288 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl12, 8)); 289 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 8)); 290 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0); 291 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 292 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4); 293 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 3)); 294 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 7); 295 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1)); 296 MOZ_RELEASE_ASSERT(iter1.Done()); 297 298 // |iter| is at position 9 (2nd segment). 299 iter = bl12.Iter(); 300 iter1 = bl12.Iter(); 301 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl12, 9)); 302 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 9)); 303 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0); 304 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4)); 305 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4); 306 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 2)); 307 MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 6); 308 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1)); 309 MOZ_RELEASE_ASSERT(iter1.Done()); 310 311 BufferList bl13(0, 0, 8); 312 MOZ_ALWAYS_TRUE(bl13.WriteBytes("abcdefgh", 8)); 313 MOZ_ALWAYS_TRUE(bl13.WriteBytes("12345678", 8)); 314 MOZ_ALWAYS_TRUE(bl13.WriteBytes("ABCDEFGH", 8)); 315 MOZ_RELEASE_ASSERT(bl13.Size() == 24); 316 317 // At segment border 318 iter = bl13.Iter(); 319 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 8)); 320 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 16); 321 MOZ_RELEASE_ASSERT(iter.Done()); 322 MOZ_RELEASE_ASSERT(bl13.Size() == 8); 323 324 // Restore state 325 MOZ_ALWAYS_TRUE(bl13.WriteBytes("12345678", 8)); 326 MOZ_ALWAYS_TRUE(bl13.WriteBytes("ABCDEFGH", 8)); 327 MOZ_RELEASE_ASSERT(bl13.Size() == 24); 328 329 // Before segment border 330 iter = bl13.Iter(); 331 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 7)); 332 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 17); 333 MOZ_RELEASE_ASSERT(iter.Done()); 334 MOZ_RELEASE_ASSERT(bl13.Size() == 7); 335 336 // Restore state 337 MOZ_ALWAYS_TRUE(bl13.WriteBytes("h", 1)); 338 MOZ_ALWAYS_TRUE(bl13.WriteBytes("12345678", 8)); 339 MOZ_ALWAYS_TRUE(bl13.WriteBytes("ABCDEFGH", 8)); 340 MOZ_RELEASE_ASSERT(bl13.Size() == 24); 341 342 // In last segment 343 iter = bl13.Iter(); 344 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 20)); 345 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 4); 346 MOZ_RELEASE_ASSERT(iter.Done()); 347 MOZ_RELEASE_ASSERT(bl13.Size() == 20); 348 349 // No-op truncate 350 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 0); 351 MOZ_RELEASE_ASSERT(iter.Done()); 352 MOZ_RELEASE_ASSERT(bl13.Size() == 20); 353 354 // No-op truncate with fresh iterator 355 iter = bl13.Iter(); 356 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 20)); 357 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 0); 358 MOZ_RELEASE_ASSERT(iter.Done()); 359 MOZ_RELEASE_ASSERT(bl13.Size() == 20); 360 361 // Truncate at start of buffer 362 iter = bl13.Iter(); 363 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 20); 364 MOZ_RELEASE_ASSERT(iter.Done()); 365 MOZ_RELEASE_ASSERT(bl13.Size() == 0); 366 367 // No-op truncate at start of buffer 368 iter = bl13.Iter(); 369 MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 0); 370 MOZ_RELEASE_ASSERT(iter.Done()); 371 MOZ_RELEASE_ASSERT(bl13.Size() == 0); 372 373 return 0; 374 }