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/. */
7 // This is included first to ensure it doesn't implicitly depend on anything
9 #include "mozilla/BufferList.h"
11 // It would be nice if we could use the InfallibleAllocPolicy from mozalloc,
12 // but MFBT cannot use mozalloc.
13 class InfallibleAllocPolicy
{
16 T
* pod_malloc(size_t aNumElems
) {
17 if (aNumElems
& mozilla::tl::MulOverflowMask
<sizeof(T
)>::value
) {
18 MOZ_CRASH("TestBufferList.cpp: overflow");
20 T
* rv
= static_cast<T
*>(malloc(aNumElems
* sizeof(T
)));
22 MOZ_CRASH("TestBufferList.cpp: out of memory");
28 void free_(T
* aPtr
, size_t aNumElems
= 0) {
32 void reportAllocOverflow() const {}
34 bool checkSimulatedOOM() const { return true; }
37 typedef mozilla::BufferList
<InfallibleAllocPolicy
> BufferList
;
40 const size_t kInitialSize
= 16;
41 const size_t kInitialCapacity
= 24;
42 const size_t kStandardCapacity
= 32;
44 BufferList
bl(kInitialSize
, kInitialCapacity
, kStandardCapacity
);
46 memset(bl
.Start(), 0x0c, kInitialSize
);
47 MOZ_RELEASE_ASSERT(bl
.Size() == kInitialSize
);
49 // Simple iteration and access.
51 BufferList::IterImpl
iter(bl
.Iter());
52 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == kInitialSize
);
53 MOZ_RELEASE_ASSERT(iter
.HasRoomFor(kInitialSize
));
54 MOZ_RELEASE_ASSERT(!iter
.HasRoomFor(kInitialSize
+ 1));
55 MOZ_RELEASE_ASSERT(!iter
.HasRoomFor(size_t(-1)));
56 MOZ_RELEASE_ASSERT(*iter
.Data() == 0x0c);
57 MOZ_RELEASE_ASSERT(!iter
.Done());
60 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == kInitialSize
- 4);
61 MOZ_RELEASE_ASSERT(iter
.HasRoomFor(kInitialSize
- 4));
62 MOZ_RELEASE_ASSERT(*iter
.Data() == 0x0c);
63 MOZ_RELEASE_ASSERT(!iter
.Done());
66 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == kInitialSize
- 4 - 11);
67 MOZ_RELEASE_ASSERT(iter
.HasRoomFor(kInitialSize
- 4 - 11));
68 MOZ_RELEASE_ASSERT(!iter
.HasRoomFor(kInitialSize
- 4 - 11 + 1));
69 MOZ_RELEASE_ASSERT(*iter
.Data() == 0x0c);
70 MOZ_RELEASE_ASSERT(!iter
.Done());
72 iter
.Advance(bl
, kInitialSize
- 4 - 11);
73 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == 0);
74 MOZ_RELEASE_ASSERT(!iter
.HasRoomFor(1));
75 MOZ_RELEASE_ASSERT(iter
.Done());
77 // Writing to the buffer.
79 const size_t kSmallWrite
= 16;
81 char toWrite
[kSmallWrite
];
82 memset(toWrite
, 0x0a, kSmallWrite
);
83 MOZ_ALWAYS_TRUE(bl
.WriteBytes(toWrite
, kSmallWrite
));
85 MOZ_RELEASE_ASSERT(bl
.Size() == kInitialSize
+ kSmallWrite
);
88 iter
.Advance(bl
, kInitialSize
);
89 MOZ_RELEASE_ASSERT(!iter
.Done());
90 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() ==
91 kInitialCapacity
- kInitialSize
);
92 MOZ_RELEASE_ASSERT(iter
.HasRoomFor(kInitialCapacity
- kInitialSize
));
93 MOZ_RELEASE_ASSERT(*iter
.Data() == 0x0a);
95 // AdvanceAcrossSegments.
98 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl
, kInitialCapacity
- 4));
99 MOZ_RELEASE_ASSERT(!iter
.Done());
100 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == 4);
101 MOZ_RELEASE_ASSERT(iter
.HasRoomFor(4));
102 MOZ_RELEASE_ASSERT(*iter
.Data() == 0x0a);
106 iter
.AdvanceAcrossSegments(bl
, kInitialSize
+ kSmallWrite
- 4));
107 MOZ_RELEASE_ASSERT(!iter
.Done());
108 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == 4);
109 MOZ_RELEASE_ASSERT(iter
.HasRoomFor(4));
110 MOZ_RELEASE_ASSERT(*iter
.Data() == 0x0a);
113 bl
.Iter().AdvanceAcrossSegments(bl
, kInitialSize
+ kSmallWrite
- 1));
115 bl
.Iter().AdvanceAcrossSegments(bl
, kInitialSize
+ kSmallWrite
));
117 !bl
.Iter().AdvanceAcrossSegments(bl
, kInitialSize
+ kSmallWrite
+ 1));
118 MOZ_RELEASE_ASSERT(!bl
.Iter().AdvanceAcrossSegments(bl
, size_t(-1)));
120 // Reading non-contiguous bytes.
122 char toRead
[kSmallWrite
];
124 iter
.Advance(bl
, kInitialSize
);
125 bl
.ReadBytes(iter
, toRead
, kSmallWrite
);
126 MOZ_RELEASE_ASSERT(memcmp(toRead
, toWrite
, kSmallWrite
) == 0);
127 MOZ_RELEASE_ASSERT(iter
.Done());
129 // Make sure reading up to the end of a segment advances the iter to the next
132 bl
.ReadBytes(iter
, toRead
, kInitialSize
);
133 MOZ_RELEASE_ASSERT(!iter
.Done());
134 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() ==
135 kInitialCapacity
- kInitialSize
);
137 const size_t kBigWrite
= 1024;
139 char* toWriteBig
= static_cast<char*>(malloc(kBigWrite
));
140 for (unsigned i
= 0; i
< kBigWrite
; i
++) {
141 toWriteBig
[i
] = i
% 37;
143 MOZ_ALWAYS_TRUE(bl
.WriteBytes(toWriteBig
, kBigWrite
));
145 char* toReadBig
= static_cast<char*>(malloc(kBigWrite
));
148 iter
.AdvanceAcrossSegments(bl
, kInitialSize
+ kSmallWrite
));
149 bl
.ReadBytes(iter
, toReadBig
, kBigWrite
);
150 MOZ_RELEASE_ASSERT(memcmp(toReadBig
, toWriteBig
, kBigWrite
) == 0);
151 MOZ_RELEASE_ASSERT(iter
.Done());
156 // Currently bl contains these segments:
157 // #0: offset 0, [0x0c]*16 + [0x0a]*8, size 24
158 // #1: offset 24, [0x0a]*8 + [i%37 for i in 0..24], size 32
159 // #2: offset 56, [i%37 for i in 24..56, size 32
161 // #32: offset 1016, [i%37 for i in 984..1016], size 32
162 // #33: offset 1048, [i%37 for i in 1016..1024], size 8
164 static size_t kTotalSize
= kInitialSize
+ kSmallWrite
+ kBigWrite
;
166 MOZ_RELEASE_ASSERT(bl
.Size() == kTotalSize
);
168 static size_t kLastSegmentSize
=
169 (kTotalSize
- kInitialCapacity
) % kStandardCapacity
;
172 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(
173 bl
, kTotalSize
- kLastSegmentSize
- kStandardCapacity
));
174 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == kStandardCapacity
);
175 iter
.Advance(bl
, kStandardCapacity
);
176 MOZ_RELEASE_ASSERT(iter
.RemainingInSegment() == kLastSegmentSize
);
178 unsigned(*iter
.Data()) ==
179 (kTotalSize
- kLastSegmentSize
- kInitialSize
- kSmallWrite
) % 37);
184 MOZ_RELEASE_ASSERT(bl
.Size() == 0);
185 MOZ_RELEASE_ASSERT(bl
.Iter().Done());
189 const size_t kSmallCapacity
= 8;
191 BufferList
bl2(0, kSmallCapacity
, kSmallCapacity
);
192 MOZ_ALWAYS_TRUE(bl2
.WriteBytes(toWrite
, kSmallWrite
));
193 MOZ_ALWAYS_TRUE(bl2
.WriteBytes(toWrite
, kSmallWrite
));
194 MOZ_ALWAYS_TRUE(bl2
.WriteBytes(toWrite
, kSmallWrite
));
197 MOZ_RELEASE_ASSERT(bl2
.Size() == 0);
198 MOZ_RELEASE_ASSERT(bl2
.Iter().Done());
201 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl
, kSmallWrite
* 3));
202 MOZ_RELEASE_ASSERT(iter
.Done());
207 bl2
= bl
.MoveFallible
<InfallibleAllocPolicy
>(&success
);
208 MOZ_RELEASE_ASSERT(success
);
209 MOZ_RELEASE_ASSERT(bl
.Size() == 0);
210 MOZ_RELEASE_ASSERT(bl
.Iter().Done());
211 MOZ_RELEASE_ASSERT(bl2
.Size() == kSmallWrite
* 3);
214 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl2
, kSmallWrite
* 3));
215 MOZ_RELEASE_ASSERT(iter
.Done());
217 bl
= bl2
.MoveFallible
<InfallibleAllocPolicy
>(&success
);
221 const size_t kBorrowStart
= 4;
222 const size_t kBorrowSize
= 24;
225 iter
.Advance(bl
, kBorrowStart
);
226 bl2
= bl
.Borrow
<InfallibleAllocPolicy
>(iter
, kBorrowSize
, &success
);
227 MOZ_RELEASE_ASSERT(success
);
228 MOZ_RELEASE_ASSERT(bl2
.Size() == kBorrowSize
);
230 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(
231 bl
, kSmallWrite
* 3 - kBorrowSize
- kBorrowStart
));
232 MOZ_RELEASE_ASSERT(iter
.Done());
235 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl2
, kBorrowSize
));
236 MOZ_RELEASE_ASSERT(iter
.Done());
238 BufferList::IterImpl
iter1(bl
.Iter()), iter2(bl2
.Iter());
239 iter1
.Advance(bl
, kBorrowStart
);
240 MOZ_RELEASE_ASSERT(iter1
.Data() == iter2
.Data());
241 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl
, kBorrowSize
- 5));
242 MOZ_RELEASE_ASSERT(iter2
.AdvanceAcrossSegments(bl2
, kBorrowSize
- 5));
243 MOZ_RELEASE_ASSERT(iter1
.Data() == iter2
.Data());
247 const size_t kExtractStart
= 8;
248 const size_t kExtractSize
= 24;
249 const size_t kExtractOverSize
= 1000;
252 iter
.Advance(bl
, kExtractStart
);
253 bl2
= bl
.Extract(iter
, kExtractSize
, &success
);
254 MOZ_RELEASE_ASSERT(success
);
255 MOZ_RELEASE_ASSERT(bl2
.Size() == kExtractSize
);
257 BufferList bl3
= bl
.Extract(iter
, kExtractOverSize
, &success
);
258 MOZ_RELEASE_ASSERT(!success
);
261 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl2
, kExtractSize
));
262 MOZ_RELEASE_ASSERT(iter
.Done());
264 BufferList
bl4(8, 8, 8);
265 MOZ_ALWAYS_TRUE(bl4
.WriteBytes("abcd1234", 8));
267 iter
.Advance(bl4
, 8);
269 BufferList bl5
= bl4
.Extract(iter
, kExtractSize
, &success
);
270 MOZ_RELEASE_ASSERT(!success
);
272 BufferList
bl6(0, 0, 16);
273 MOZ_ALWAYS_TRUE(bl6
.WriteBytes("abcdefgh12345678", 16));
274 MOZ_ALWAYS_TRUE(bl6
.WriteBytes("ijklmnop87654321", 16));
276 iter
.Advance(bl6
, 8);
277 BufferList bl7
= bl6
.Extract(iter
, 16, &success
);
278 MOZ_RELEASE_ASSERT(success
);
280 MOZ_RELEASE_ASSERT(bl6
.ReadBytes(iter
, data
, 8));
281 MOZ_RELEASE_ASSERT(memcmp(data
, "87654321", 8) == 0);
283 MOZ_RELEASE_ASSERT(bl7
.ReadBytes(iter
, data
, 16));
284 MOZ_RELEASE_ASSERT(memcmp(data
, "12345678ijklmnop", 16) == 0);
286 BufferList
bl8(0, 0, 16);
287 MOZ_ALWAYS_TRUE(bl8
.WriteBytes("abcdefgh12345678", 16));
289 BufferList bl9
= bl8
.Extract(iter
, 8, &success
);
290 MOZ_RELEASE_ASSERT(success
);
291 MOZ_RELEASE_ASSERT(bl9
.Size() == 8);
292 MOZ_RELEASE_ASSERT(!iter
.Done());
294 BufferList
bl10(0, 0, 8);
295 MOZ_ALWAYS_TRUE(bl10
.WriteBytes("abcdefgh", 8));
296 MOZ_ALWAYS_TRUE(bl10
.WriteBytes("12345678", 8));
298 BufferList bl11
= bl10
.Extract(iter
, 16, &success
);
299 MOZ_RELEASE_ASSERT(success
);
300 MOZ_RELEASE_ASSERT(bl11
.Size() == 16);
301 MOZ_RELEASE_ASSERT(iter
.Done());
303 MOZ_RELEASE_ASSERT(bl11
.ReadBytes(iter
, data
, 16));
304 MOZ_RELEASE_ASSERT(memcmp(data
, "abcdefgh12345678", 16) == 0);
308 BufferList
bl12(0, 0, 8);
309 MOZ_ALWAYS_TRUE(bl12
.WriteBytes("abcdefgh", 8));
310 MOZ_ALWAYS_TRUE(bl12
.WriteBytes("12345678", 8));
312 // |iter| is at position 0 (1st segment).
315 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 0);
316 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
317 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 4);
318 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
319 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 8);
320 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
321 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 12);
322 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 3));
323 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 15);
324 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 1));
325 MOZ_RELEASE_ASSERT(iter1
.Done());
327 // |iter| is at position 1 (1st segment).
330 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl12
, 1));
331 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 1));
332 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 0);
333 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
334 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 4);
335 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
336 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 8);
337 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
338 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 12);
339 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 2));
340 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 14);
341 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 1));
342 MOZ_RELEASE_ASSERT(iter1
.Done());
344 // |iter| is at position 8 (2nd segment).
347 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl12
, 8));
348 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 8));
349 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 0);
350 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
351 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 4);
352 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 3));
353 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 7);
354 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 1));
355 MOZ_RELEASE_ASSERT(iter1
.Done());
357 // |iter| is at position 9 (2nd segment).
360 MOZ_RELEASE_ASSERT(iter
.AdvanceAcrossSegments(bl12
, 9));
361 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 9));
362 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 0);
363 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 4));
364 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 4);
365 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 2));
366 MOZ_RELEASE_ASSERT(bl12
.RangeLength(iter
, iter1
) == 6);
367 MOZ_RELEASE_ASSERT(iter1
.AdvanceAcrossSegments(bl12
, 1));
368 MOZ_RELEASE_ASSERT(iter1
.Done());