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
11 // It would be nice if we could use the InfallibleAllocPolicy from mozalloc,
12 // but MFBT cannot use mozalloc.
13 class InfallibleAllocPolicy
14 {
15 public:
16 template <typename T>
pod_malloc(size_t aNumElems)17 T* pod_malloc(size_t aNumElems)
18 {
19 if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
20 MOZ_CRASH("TestBufferList.cpp: overflow");
21 }
22 T* rv = static_cast<T*>(malloc(aNumElems * sizeof(T)));
23 if (!rv) {
24 MOZ_CRASH("TestBufferList.cpp: out of memory");
25 }
26 return rv;
27 }
28
free_(void * aPtr)29 void free_(void* aPtr) { free(aPtr); }
30
reportAllocOverflow() const31 void reportAllocOverflow() const {}
32
checkSimulatedOOM() const33 bool checkSimulatedOOM() const { return true; }
34 };
35
36 typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
37
main(void)38 int main(void)
39 {
40 const size_t kInitialSize = 16;
41 const size_t kInitialCapacity = 24;
42 const size_t kStandardCapacity = 32;
43
44 BufferList bl(kInitialSize, kInitialCapacity, kStandardCapacity);
45
46 memset(bl.Start(), 0x0c, kInitialSize);
47 MOZ_RELEASE_ASSERT(bl.Size() == kInitialSize);
48
49 // Simple iteration and access.
50
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());
58
59 iter.Advance(bl, 4);
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());
64
65 iter.Advance(bl, 11);
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());
71
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());
76
77 // Writing to the buffer.
78
79 const size_t kSmallWrite = 16;
80
81 char toWrite[kSmallWrite];
82 memset(toWrite, 0x0a, kSmallWrite);
83 bl.WriteBytes(toWrite, kSmallWrite);
84
85 MOZ_RELEASE_ASSERT(bl.Size() == kInitialSize + kSmallWrite);
86
87 iter = bl.Iter();
88 iter.Advance(bl, kInitialSize);
89 MOZ_RELEASE_ASSERT(!iter.Done());
90 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialCapacity - kInitialSize);
91 MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialCapacity - kInitialSize));
92 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a);
93
94 // AdvanceAcrossSegments.
95
96 iter = bl.Iter();
97 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kInitialCapacity - 4));
98 MOZ_RELEASE_ASSERT(!iter.Done());
99 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 4);
100 MOZ_RELEASE_ASSERT(iter.HasRoomFor(4));
101 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a);
102
103 iter = bl.Iter();
104 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite - 4));
105 MOZ_RELEASE_ASSERT(!iter.Done());
106 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 4);
107 MOZ_RELEASE_ASSERT(iter.HasRoomFor(4));
108 MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a);
109
110 MOZ_RELEASE_ASSERT(bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite - 1));
111 MOZ_RELEASE_ASSERT(bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite));
112 MOZ_RELEASE_ASSERT(!bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite + 1));
113 MOZ_RELEASE_ASSERT(!bl.Iter().AdvanceAcrossSegments(bl, size_t(-1)));
114
115 // Reading non-contiguous bytes.
116
117 char toRead[kSmallWrite];
118 iter = bl.Iter();
119 iter.Advance(bl, kInitialSize);
120 bl.ReadBytes(iter, toRead, kSmallWrite);
121 MOZ_RELEASE_ASSERT(memcmp(toRead, toWrite, kSmallWrite) == 0);
122 MOZ_RELEASE_ASSERT(iter.Done());
123
124 // Make sure reading up to the end of a segment advances the iter to the next
125 // segment.
126 iter = bl.Iter();
127 bl.ReadBytes(iter, toRead, kInitialSize);
128 MOZ_RELEASE_ASSERT(!iter.Done());
129 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialCapacity - kInitialSize);
130
131 const size_t kBigWrite = 1024;
132
133 char* toWriteBig = static_cast<char*>(malloc(kBigWrite));
134 for (unsigned i = 0; i < kBigWrite; i++) {
135 toWriteBig[i] = i % 37;
136 }
137 bl.WriteBytes(toWriteBig, kBigWrite);
138
139 char* toReadBig = static_cast<char*>(malloc(kBigWrite));
140 iter = bl.Iter();
141 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite));
142 bl.ReadBytes(iter, toReadBig, kBigWrite);
143 MOZ_RELEASE_ASSERT(memcmp(toReadBig, toWriteBig, kBigWrite) == 0);
144 MOZ_RELEASE_ASSERT(iter.Done());
145
146 free(toReadBig);
147 free(toWriteBig);
148
149 // Currently bl contains these segments:
150 // #0: offset 0, [0x0c]*16 + [0x0a]*8, size 24
151 // #1: offset 24, [0x0a]*8 + [i%37 for i in 0..24], size 32
152 // #2: offset 56, [i%37 for i in 24..56, size 32
153 // ...
154 // #32: offset 1016, [i%37 for i in 984..1016], size 32
155 // #33: offset 1048, [i%37 for i in 1016..1024], size 8
156
157 static size_t kTotalSize = kInitialSize + kSmallWrite + kBigWrite;
158
159 MOZ_RELEASE_ASSERT(bl.Size() == kTotalSize);
160
161 static size_t kLastSegmentSize = (kTotalSize - kInitialCapacity) % kStandardCapacity;
162
163 iter = bl.Iter();
164 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kTotalSize - kLastSegmentSize - kStandardCapacity));
165 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kStandardCapacity);
166 iter.Advance(bl, kStandardCapacity);
167 MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kLastSegmentSize);
168 MOZ_RELEASE_ASSERT(unsigned(*iter.Data()) == (kTotalSize - kLastSegmentSize - kInitialSize - kSmallWrite) % 37);
169
170 // Clear.
171
172 bl.Clear();
173 MOZ_RELEASE_ASSERT(bl.Size() == 0);
174 MOZ_RELEASE_ASSERT(bl.Iter().Done());
175
176 // Move assignment.
177
178 const size_t kSmallCapacity = 8;
179
180 BufferList bl2(0, kSmallCapacity, kSmallCapacity);
181 bl2.WriteBytes(toWrite, kSmallWrite);
182 bl2.WriteBytes(toWrite, kSmallWrite);
183 bl2.WriteBytes(toWrite, kSmallWrite);
184
185 bl = mozilla::Move(bl2);
186 MOZ_RELEASE_ASSERT(bl2.Size() == 0);
187 MOZ_RELEASE_ASSERT(bl2.Iter().Done());
188
189 iter = bl.Iter();
190 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3));
191 MOZ_RELEASE_ASSERT(iter.Done());
192
193 // MoveFallible
194
195 bool success;
196 bl2 = bl.MoveFallible<InfallibleAllocPolicy>(&success);
197 MOZ_RELEASE_ASSERT(success);
198 MOZ_RELEASE_ASSERT(bl.Size() == 0);
199 MOZ_RELEASE_ASSERT(bl.Iter().Done());
200 MOZ_RELEASE_ASSERT(bl2.Size() == kSmallWrite * 3);
201
202 iter = bl2.Iter();
203 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kSmallWrite * 3));
204 MOZ_RELEASE_ASSERT(iter.Done());
205
206 bl = bl2.MoveFallible<InfallibleAllocPolicy>(&success);
207
208 // Borrowing.
209
210 const size_t kBorrowStart = 4;
211 const size_t kBorrowSize = 24;
212
213 iter = bl.Iter();
214 iter.Advance(bl, kBorrowStart);
215 bl2 = bl.Borrow<InfallibleAllocPolicy>(iter, kBorrowSize, &success);
216 MOZ_RELEASE_ASSERT(success);
217 MOZ_RELEASE_ASSERT(bl2.Size() == kBorrowSize);
218
219 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kBorrowSize - kBorrowStart));
220 MOZ_RELEASE_ASSERT(iter.Done());
221
222 iter = bl2.Iter();
223 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kBorrowSize));
224 MOZ_RELEASE_ASSERT(iter.Done());
225
226 BufferList::IterImpl iter1(bl.Iter()), iter2(bl2.Iter());
227 iter1.Advance(bl, kBorrowStart);
228 MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data());
229 MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl, kBorrowSize - 5));
230 MOZ_RELEASE_ASSERT(iter2.AdvanceAcrossSegments(bl2, kBorrowSize - 5));
231 MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data());
232
233 // Extracting.
234
235 const size_t kExtractStart = 8;
236 const size_t kExtractSize = 24;
237 const size_t kExtractOverSize = 1000;
238
239 iter = bl.Iter();
240 iter.Advance(bl, kExtractStart);
241 bl2 = bl.Extract(iter, kExtractSize, &success);
242 MOZ_RELEASE_ASSERT(success);
243 MOZ_RELEASE_ASSERT(bl2.Size() == kExtractSize);
244
245 BufferList bl3 = bl.Extract(iter, kExtractOverSize, &success);
246 MOZ_RELEASE_ASSERT(!success);
247
248 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kExtractSize - kExtractStart));
249 MOZ_RELEASE_ASSERT(iter.Done());
250
251 iter = bl2.Iter();
252 MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kExtractSize));
253 MOZ_RELEASE_ASSERT(iter.Done());
254
255 return 0;
256 }
257