"Fossies" - the Fresh Open Source Software Archive 
Member "xdelta3-3.0.11/testing/file.h" (8 Jan 2016, 7767 Bytes) of package /linux/misc/xdelta3-3.0.11.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* -*- Mode: C++ -*- */
2 class Block;
3 class BlockIterator;
4 class TmpFile;
5
6 class Block {
7 public:
8 Block()
9 : data_(NULL),
10 data_size_(0),
11 size_(0) { }
12
13 ~Block() {
14 if (data_) {
15 delete [] data_;
16 }
17 }
18
19 size_t Size() const {
20 return size_;
21 }
22
23 uint8_t operator[](size_t i) const {
24 CHECK_LT(i, size_);
25 return data_[i];
26 }
27
28 uint8_t* Data() const {
29 if (data_ == NULL) {
30 CHECK_EQ(0, size_);
31 data_size_ = 1;
32 data_ = new uint8_t[1];
33 }
34 return data_;
35 }
36
37 // For writing to blocks
38 void Append(const uint8_t *data, size_t size) {
39 if (data_ == NULL) {
40 CHECK_EQ(0, size_);
41 CHECK_EQ(0, data_size_);
42 data_ = new uint8_t[Constants::BLOCK_SIZE];
43 data_size_ = Constants::BLOCK_SIZE;
44 }
45
46 if (size_ + size > data_size_) {
47 uint8_t *tmp = data_;
48 while (size_ + size > data_size_) {
49 data_size_ *= 2;
50 }
51 data_ = new uint8_t[data_size_];
52 memcpy(data_, tmp, size_);
53 delete [] tmp;
54 }
55
56 memcpy(data_ + size_, data, size);
57 size_ += size;
58 }
59
60 // For cleaing a block
61 void Reset() {
62 size_ = 0;
63 }
64
65 void Print() const {
66 xoff_t pos = 0;
67 for (size_t i = 0; i < Size(); i++) {
68 if (pos % 16 == 0) {
69 DP(RINT "%5"Q"x: ", pos);
70 }
71 DP(RINT "%02x ", (*this)[i]);
72 if (pos % 16 == 15) {
73 DP(RINT "\n");
74 }
75 pos++;
76 }
77 DP(RINT "\n");
78 }
79
80 void WriteTmpFile(TmpFile *f) const {
81 f->Append(this);
82 }
83
84 void SetSize(size_t size) {
85 uint8_t *t = NULL;
86 if (data_size_ < size) {
87 if (data_) {
88 t = data_;
89 }
90 data_ = new uint8_t[size];
91 data_size_ = size;
92 }
93 if (t && size < size_) {
94 memcpy(data_, t, size);
95 }
96 delete [] t;
97 size_ = size;
98 }
99
100 private:
101 friend class BlockIterator;
102
103 mutable uint8_t *data_;
104 mutable size_t data_size_;
105 size_t size_;
106 };
107
108 class FileSpec {
109 public:
110 FileSpec(MTRandom *rand)
111 : rand_(rand) {
112 }
113
114 // Generates a file with a known size
115 void GenerateFixedSize(xoff_t size) {
116 Reset();
117
118 for (xoff_t p = 0; p < size; ) {
119 xoff_t t = min(Constants::BLOCK_SIZE, size - p);
120 table_.insert(make_pair(p, Segment(t, rand_)));
121 p += t;
122 }
123 }
124
125 // Generates a file with exponential-random distributed size
126 void GenerateRandomSize(xoff_t mean) {
127 GenerateFixedSize(rand_->ExpRand(mean));
128 }
129
130 // Returns the size of the file
131 xoff_t Size() const {
132 if (table_.empty()) {
133 return 0;
134 }
135 ConstSegmentMapIterator i = --table_.end();
136 return i->first + i->second.Size();
137 }
138
139 // Returns the number of blocks
140 xoff_t Blocks(size_t blksize = Constants::BLOCK_SIZE) const {
141 if (table_.empty()) {
142 return 0;
143 }
144 return ((Size() - 1) / blksize) + 1;
145 }
146
147 // Returns the number of segments
148 xoff_t Segments() const {
149 return table_.size();
150 }
151
152 // Create a mutation according to "what".
153 void ModifyTo(const Mutator &mutator,
154 FileSpec *modify) const {
155 modify->Reset();
156 mutator.Mutate(&modify->table_, &table_, rand_);
157 modify->CheckSegments();
158 }
159
160 void CheckSegments() const {
161 for (ConstSegmentMapIterator iter(table_.begin());
162 iter != table_.end(); ) {
163 ConstSegmentMapIterator iter0(iter++);
164 if (iter == table_.end()) {
165 break;
166 }
167 CHECK_EQ(iter0->first + iter0->second.Size(), iter->first);
168 }
169 }
170
171 void Reset() {
172 table_.clear();
173 }
174
175 void Print() const {
176 for (ConstSegmentMapIterator iter(table_.begin());
177 iter != table_.end();
178 ++iter) {
179 const Segment &seg = iter->second;
180 cerr << "Segment at " << iter->first
181 << " (" << seg.ToString() << ")" << endl;
182 }
183 }
184
185 void PrintData() const {
186 Block block;
187 for (BlockIterator iter(*this); !iter.Done(); iter.Next()) {
188 iter.Get(&block);
189 block.Print();
190 }
191 }
192
193 void WriteTmpFile(TmpFile *f) const {
194 Block block;
195 for (BlockIterator iter(*this); !iter.Done(); iter.Next()) {
196 iter.Get(&block);
197 f->Append(&block);
198 }
199 }
200
201 void Get(Block *block, xoff_t offset, size_t size) const {
202 size_t got = 0;
203 block->SetSize(size);
204
205 ConstSegmentMapIterator pos = table_.upper_bound(offset);
206 if (pos == table_.begin()) {
207 CHECK_EQ(0, Size());
208 return;
209 }
210 --pos;
211
212 while (got < size) {
213 CHECK(pos != table_.end());
214 CHECK_GE(offset, pos->first);
215
216 const Segment &seg = pos->second;
217
218 // The position of this segment may start before this block starts,
219 // and then the position of the data may be offset from the seeding
220 // position.
221 size_t seg_offset = offset - pos->first;
222 size_t advance = min(seg.Size() - seg_offset,
223 size - got);
224
225 seg.Fill(seg_offset, advance, block->Data() + got);
226
227 got += advance;
228 offset += advance;
229 ++pos;
230 }
231 }
232
233 typedef BlockIterator iterator;
234
235 private:
236 friend class BlockIterator;
237
238 MTRandom *rand_;
239 SegmentMap table_;
240 };
241
242 class BlockIterator {
243 public:
244 explicit BlockIterator(const FileSpec& spec)
245 : spec_(spec),
246 blkno_(0),
247 blksize_(Constants::BLOCK_SIZE) { }
248
249 BlockIterator(const FileSpec& spec,
250 size_t blksize)
251 : spec_(spec),
252 blkno_(0),
253 blksize_(blksize) { }
254
255 bool Done() const {
256 return blkno_ >= spec_.Blocks(blksize_);
257 }
258
259 void Next() {
260 blkno_++;
261 }
262
263 xoff_t Blkno() const {
264 return blkno_;
265 }
266
267 xoff_t Blocks() const {
268 return spec_.Blocks(blksize_);
269 }
270
271 xoff_t Offset() const {
272 return blkno_ * blksize_;
273 }
274
275 void SetBlock(xoff_t blkno) {
276 CHECK_LE(blkno, Blocks());
277 blkno_ = blkno;
278 }
279
280 void Get(Block *block) const {
281 spec_.Get(block, blkno_ * blksize_, BytesOnBlock());
282 }
283
284 size_t BytesOnBlock() const {
285 xoff_t blocks = spec_.Blocks(blksize_);
286 xoff_t size = spec_.Size();
287
288 DCHECK((blkno_ < blocks) ||
289 (blkno_ == blocks && size % blksize_ == 0));
290
291 if (blkno_ == blocks) {
292 return 0;
293 }
294 if (blkno_ + 1 == blocks) {
295 return ((size - 1) % blksize_) + 1;
296 }
297 return blksize_;
298 }
299
300 size_t BlockSize() const {
301 return blksize_;
302 }
303
304 private:
305 const FileSpec& spec_;
306 xoff_t blkno_;
307 size_t blksize_;
308 };
309
310 class ExtFile {
311 public:
312 ExtFile() {
313 static int static_counter = 0;
314 pid_t pid = getpid();
315 char buf[64];
316 xoff_t xpid = pid;
317 snprintf(buf, 64, "/tmp/regtest.%" Q "u.%d", xpid, static_counter++);
318 filename_.append(buf);
319 unlink(filename_.c_str());
320 }
321
322 ~ExtFile() {
323 unlink(filename_.c_str());
324 }
325
326 const char* Name() const {
327 return filename_.c_str();
328 }
329
330 // Check whether a real file matches a file spec.
331 bool EqualsSpec(const FileSpec &spec) const {
332 main_file t;
333 main_file_init(&t);
334 CHECK_EQ(0, main_file_open(&t, Name(), XO_READ));
335
336 Block tblock;
337 Block sblock;
338 for (BlockIterator iter(spec); !iter.Done(); iter.Next()) {
339 iter.Get(&sblock);
340 tblock.SetSize(sblock.Size());
341 size_t tread;
342 CHECK_EQ(0, main_file_read(&t,
343 tblock.Data(),
344 tblock.Size(), &tread, "read failed"));
345 CHECK_EQ(0, CmpDifferentBlockBytes(tblock, sblock));
346 }
347
348 CHECK_EQ(0, main_file_close(&t));
349 main_file_cleanup(&t);
350 return true;
351 }
352
353 protected:
354 string filename_;
355 };
356
357 class TmpFile : public ExtFile {
358 public:
359 TmpFile() {
360 main_file_init(&file_);
361 CHECK_EQ(0, main_file_open(&file_, Name(), XO_WRITE));
362 }
363
364 ~TmpFile() {
365 main_file_cleanup(&file_);
366 }
367
368 void Append(const Block *block) {
369 CHECK_EQ(0, main_file_write(&file_,
370 block->Data(), block->Size(),
371 "tmpfile write failed"));
372 }
373
374 const char* Name() const {
375 if (main_file_isopen(&file_)) {
376 CHECK_EQ(0, main_file_close(&file_));
377 }
378 return ExtFile::Name();
379 }
380
381 private:
382 mutable main_file file_;
383 };