|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #ifndef Utils_h |
|
6 #define Utils_h |
|
7 |
|
8 #include <stdint.h> |
|
9 #include <stddef.h> |
|
10 #include <sys/mman.h> |
|
11 #include <unistd.h> |
|
12 #include "mozilla/Assertions.h" |
|
13 #include "mozilla/Scoped.h" |
|
14 |
|
15 /** |
|
16 * On architectures that are little endian and that support unaligned reads, |
|
17 * we can use direct type, but on others, we want to have a special class |
|
18 * to handle conversion and alignment issues. |
|
19 */ |
|
20 #if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__)) |
|
21 typedef uint16_t le_uint16; |
|
22 typedef uint32_t le_uint32; |
|
23 #else |
|
24 |
|
25 /** |
|
26 * Template that allows to find an unsigned int type from a (computed) bit size |
|
27 */ |
|
28 template <int s> struct UInt { }; |
|
29 template <> struct UInt<16> { typedef uint16_t Type; }; |
|
30 template <> struct UInt<32> { typedef uint32_t Type; }; |
|
31 |
|
32 /** |
|
33 * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing |
|
34 * conversion from little endian and avoiding alignment issues. |
|
35 */ |
|
36 template <typename T> |
|
37 class le_to_cpu |
|
38 { |
|
39 public: |
|
40 typedef typename UInt<16 * sizeof(T)>::Type Type; |
|
41 |
|
42 operator Type() const |
|
43 { |
|
44 return (b << (sizeof(T) * 8)) | a; |
|
45 } |
|
46 |
|
47 const le_to_cpu& operator =(const Type &v) |
|
48 { |
|
49 a = v & ((1 << (sizeof(T) * 8)) - 1); |
|
50 b = v >> (sizeof(T) * 8); |
|
51 return *this; |
|
52 } |
|
53 |
|
54 le_to_cpu() { } |
|
55 le_to_cpu(const Type &v) |
|
56 { |
|
57 operator =(v); |
|
58 } |
|
59 |
|
60 const le_to_cpu& operator +=(const Type &v) |
|
61 { |
|
62 return operator =(operator Type() + v); |
|
63 } |
|
64 |
|
65 const le_to_cpu& operator ++(int) |
|
66 { |
|
67 return operator =(operator Type() + 1); |
|
68 } |
|
69 |
|
70 private: |
|
71 T a, b; |
|
72 }; |
|
73 |
|
74 /** |
|
75 * Type definitions |
|
76 */ |
|
77 typedef le_to_cpu<unsigned char> le_uint16; |
|
78 typedef le_to_cpu<le_uint16> le_uint32; |
|
79 #endif |
|
80 |
|
81 |
|
82 /** |
|
83 * AutoCloseFD is a RAII wrapper for POSIX file descriptors |
|
84 */ |
|
85 struct AutoCloseFDTraits |
|
86 { |
|
87 typedef int type; |
|
88 static int empty() { return -1; } |
|
89 static void release(int fd) { if (fd != -1) close(fd); } |
|
90 }; |
|
91 typedef mozilla::Scoped<AutoCloseFDTraits> AutoCloseFD; |
|
92 |
|
93 /** |
|
94 * AutoCloseFILE is a RAII wrapper for POSIX streams |
|
95 */ |
|
96 struct AutoCloseFILETraits |
|
97 { |
|
98 typedef FILE *type; |
|
99 static FILE *empty() { return nullptr; } |
|
100 static void release(FILE *f) { if (f) fclose(f); } |
|
101 }; |
|
102 typedef mozilla::Scoped<AutoCloseFILETraits> AutoCloseFILE; |
|
103 |
|
104 /** |
|
105 * Page alignment helpers |
|
106 */ |
|
107 static inline size_t PageSize() |
|
108 { |
|
109 return 4096; |
|
110 } |
|
111 |
|
112 static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment) |
|
113 { |
|
114 return ptr & ~(alignment - 1); |
|
115 } |
|
116 |
|
117 template <typename T> |
|
118 static inline T *AlignedPtr(T *ptr, size_t alignment) |
|
119 { |
|
120 return reinterpret_cast<T *>( |
|
121 AlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment)); |
|
122 } |
|
123 |
|
124 template <typename T> |
|
125 static inline T PageAlignedPtr(T ptr) |
|
126 { |
|
127 return AlignedPtr(ptr, PageSize()); |
|
128 } |
|
129 |
|
130 static inline uintptr_t AlignedEndPtr(uintptr_t ptr, size_t alignment) |
|
131 { |
|
132 return AlignedPtr(ptr + alignment - 1, alignment); |
|
133 } |
|
134 |
|
135 template <typename T> |
|
136 static inline T *AlignedEndPtr(T *ptr, size_t alignment) |
|
137 { |
|
138 return reinterpret_cast<T *>( |
|
139 AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr), alignment)); |
|
140 } |
|
141 |
|
142 template <typename T> |
|
143 static inline T PageAlignedEndPtr(T ptr) |
|
144 { |
|
145 return AlignedEndPtr(ptr, PageSize()); |
|
146 } |
|
147 |
|
148 static inline size_t AlignedSize(size_t size, size_t alignment) |
|
149 { |
|
150 return (size + alignment - 1) & ~(alignment - 1); |
|
151 } |
|
152 |
|
153 static inline size_t PageAlignedSize(size_t size) |
|
154 { |
|
155 return AlignedSize(size, PageSize()); |
|
156 } |
|
157 |
|
158 static inline bool IsAlignedPtr(uintptr_t ptr, size_t alignment) |
|
159 { |
|
160 return ptr % alignment == 0; |
|
161 } |
|
162 |
|
163 template <typename T> |
|
164 static inline bool IsAlignedPtr(T *ptr, size_t alignment) |
|
165 { |
|
166 return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment); |
|
167 } |
|
168 |
|
169 template <typename T> |
|
170 static inline bool IsPageAlignedPtr(T ptr) |
|
171 { |
|
172 return IsAlignedPtr(ptr, PageSize()); |
|
173 } |
|
174 |
|
175 static inline bool IsAlignedSize(size_t size, size_t alignment) |
|
176 { |
|
177 return size % alignment == 0; |
|
178 } |
|
179 |
|
180 static inline bool IsPageAlignedSize(size_t size) |
|
181 { |
|
182 return IsAlignedSize(size, PageSize()); |
|
183 } |
|
184 |
|
185 static inline size_t PageNumber(size_t size) |
|
186 { |
|
187 return (size + PageSize() - 1) / PageSize(); |
|
188 } |
|
189 |
|
190 /** |
|
191 * MemoryRange stores a pointer, size pair. |
|
192 */ |
|
193 class MemoryRange |
|
194 { |
|
195 public: |
|
196 MemoryRange(void *buf, size_t length): buf(buf), length(length) { } |
|
197 |
|
198 void Assign(void *b, size_t len) { |
|
199 buf = b; |
|
200 length = len; |
|
201 } |
|
202 |
|
203 void Assign(const MemoryRange& other) { |
|
204 buf = other.buf; |
|
205 length = other.length; |
|
206 } |
|
207 |
|
208 void *get() const |
|
209 { |
|
210 return buf; |
|
211 } |
|
212 |
|
213 operator void *() const |
|
214 { |
|
215 return buf; |
|
216 } |
|
217 |
|
218 operator unsigned char *() const |
|
219 { |
|
220 return reinterpret_cast<unsigned char *>(buf); |
|
221 } |
|
222 |
|
223 bool operator ==(void *ptr) const { |
|
224 return buf == ptr; |
|
225 } |
|
226 |
|
227 bool operator ==(unsigned char *ptr) const { |
|
228 return buf == ptr; |
|
229 } |
|
230 |
|
231 void *operator +(off_t offset) const |
|
232 { |
|
233 return reinterpret_cast<char *>(buf) + offset; |
|
234 } |
|
235 |
|
236 /** |
|
237 * Returns whether the given address is within the mapped range |
|
238 */ |
|
239 bool Contains(void *ptr) const |
|
240 { |
|
241 return (ptr >= buf) && (ptr < reinterpret_cast<char *>(buf) + length); |
|
242 } |
|
243 |
|
244 /** |
|
245 * Returns the length of the mapped range |
|
246 */ |
|
247 size_t GetLength() const |
|
248 { |
|
249 return length; |
|
250 } |
|
251 |
|
252 static MemoryRange mmap(void *addr, size_t length, int prot, int flags, |
|
253 int fd, off_t offset) { |
|
254 return MemoryRange(::mmap(addr, length, prot, flags, fd, offset), length); |
|
255 } |
|
256 |
|
257 private: |
|
258 void *buf; |
|
259 size_t length; |
|
260 }; |
|
261 |
|
262 /** |
|
263 * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as |
|
264 * a simple void * or unsigned char *. |
|
265 * |
|
266 * It is defined as a derivative of a template that allows to use a |
|
267 * different unmapping strategy. |
|
268 */ |
|
269 template <typename T> |
|
270 class GenericMappedPtr: public MemoryRange |
|
271 { |
|
272 public: |
|
273 GenericMappedPtr(void *buf, size_t length): MemoryRange(buf, length) { } |
|
274 GenericMappedPtr(const MemoryRange& other): MemoryRange(other) { } |
|
275 GenericMappedPtr(): MemoryRange(MAP_FAILED, 0) { } |
|
276 |
|
277 void Assign(void *b, size_t len) { |
|
278 if (get() != MAP_FAILED) |
|
279 static_cast<T *>(this)->munmap(get(), GetLength()); |
|
280 MemoryRange::Assign(b, len); |
|
281 } |
|
282 |
|
283 void Assign(const MemoryRange& other) { |
|
284 Assign(other.get(), other.GetLength()); |
|
285 } |
|
286 |
|
287 ~GenericMappedPtr() |
|
288 { |
|
289 if (get() != MAP_FAILED) |
|
290 static_cast<T *>(this)->munmap(get(), GetLength()); |
|
291 } |
|
292 |
|
293 }; |
|
294 |
|
295 struct MappedPtr: public GenericMappedPtr<MappedPtr> |
|
296 { |
|
297 MappedPtr(void *buf, size_t length) |
|
298 : GenericMappedPtr<MappedPtr>(buf, length) { } |
|
299 MappedPtr(const MemoryRange& other) |
|
300 : GenericMappedPtr<MappedPtr>(other) { } |
|
301 MappedPtr(): GenericMappedPtr<MappedPtr>() { } |
|
302 |
|
303 private: |
|
304 friend class GenericMappedPtr<MappedPtr>; |
|
305 void munmap(void *buf, size_t length) |
|
306 { |
|
307 ::munmap(buf, length); |
|
308 } |
|
309 }; |
|
310 |
|
311 /** |
|
312 * UnsizedArray is a way to access raw arrays of data in memory. |
|
313 * |
|
314 * struct S { ... }; |
|
315 * UnsizedArray<S> a(buf); |
|
316 * UnsizedArray<S> b; b.Init(buf); |
|
317 * |
|
318 * This is roughly equivalent to |
|
319 * const S *a = reinterpret_cast<const S *>(buf); |
|
320 * const S *b = nullptr; b = reinterpret_cast<const S *>(buf); |
|
321 * |
|
322 * An UnsizedArray has no known length, and it's up to the caller to make |
|
323 * sure the accessed memory is mapped and makes sense. |
|
324 */ |
|
325 template <typename T> |
|
326 class UnsizedArray |
|
327 { |
|
328 public: |
|
329 typedef size_t idx_t; |
|
330 |
|
331 /** |
|
332 * Constructors and Initializers |
|
333 */ |
|
334 UnsizedArray(): contents(nullptr) { } |
|
335 UnsizedArray(const void *buf): contents(reinterpret_cast<const T *>(buf)) { } |
|
336 |
|
337 void Init(const void *buf) |
|
338 { |
|
339 MOZ_ASSERT(contents == nullptr); |
|
340 contents = reinterpret_cast<const T *>(buf); |
|
341 } |
|
342 |
|
343 /** |
|
344 * Returns the nth element of the array |
|
345 */ |
|
346 const T &operator[](const idx_t index) const |
|
347 { |
|
348 MOZ_ASSERT(contents); |
|
349 return contents[index]; |
|
350 } |
|
351 |
|
352 operator const T *() const |
|
353 { |
|
354 return contents; |
|
355 } |
|
356 /** |
|
357 * Returns whether the array points somewhere |
|
358 */ |
|
359 operator bool() const |
|
360 { |
|
361 return contents != nullptr; |
|
362 } |
|
363 private: |
|
364 const T *contents; |
|
365 }; |
|
366 |
|
367 /** |
|
368 * Array, like UnsizedArray, is a way to access raw arrays of data in memory. |
|
369 * Unlike UnsizedArray, it has a known length, and is enumerable with an |
|
370 * iterator. |
|
371 * |
|
372 * struct S { ... }; |
|
373 * Array<S> a(buf, len); |
|
374 * UnsizedArray<S> b; b.Init(buf, len); |
|
375 * |
|
376 * In the above examples, len is the number of elements in the array. It is |
|
377 * also possible to initialize an Array with the buffer size: |
|
378 * |
|
379 * Array<S> c; c.InitSize(buf, size); |
|
380 * |
|
381 * It is also possible to initialize an Array in two steps, only providing |
|
382 * one data at a time: |
|
383 * |
|
384 * Array<S> d; |
|
385 * d.Init(buf); |
|
386 * d.Init(len); // or d.InitSize(size); |
|
387 * |
|
388 */ |
|
389 template <typename T> |
|
390 class Array: public UnsizedArray<T> |
|
391 { |
|
392 public: |
|
393 typedef typename UnsizedArray<T>::idx_t idx_t; |
|
394 |
|
395 /** |
|
396 * Constructors and Initializers |
|
397 */ |
|
398 Array(): UnsizedArray<T>(), length(0) { } |
|
399 Array(const void *buf, const idx_t length) |
|
400 : UnsizedArray<T>(buf), length(length) { } |
|
401 |
|
402 void Init(const void *buf) |
|
403 { |
|
404 UnsizedArray<T>::Init(buf); |
|
405 } |
|
406 |
|
407 void Init(const idx_t len) |
|
408 { |
|
409 MOZ_ASSERT(length == 0); |
|
410 length = len; |
|
411 } |
|
412 |
|
413 void InitSize(const idx_t size) |
|
414 { |
|
415 Init(size / sizeof(T)); |
|
416 } |
|
417 |
|
418 void Init(const void *buf, const idx_t len) |
|
419 { |
|
420 UnsizedArray<T>::Init(buf); |
|
421 Init(len); |
|
422 } |
|
423 |
|
424 void InitSize(const void *buf, const idx_t size) |
|
425 { |
|
426 UnsizedArray<T>::Init(buf); |
|
427 InitSize(size); |
|
428 } |
|
429 |
|
430 /** |
|
431 * Returns the nth element of the array |
|
432 */ |
|
433 const T &operator[](const idx_t index) const |
|
434 { |
|
435 MOZ_ASSERT(index < length); |
|
436 MOZ_ASSERT(operator bool()); |
|
437 return UnsizedArray<T>::operator[](index); |
|
438 } |
|
439 |
|
440 /** |
|
441 * Returns the number of elements in the array |
|
442 */ |
|
443 idx_t numElements() const |
|
444 { |
|
445 return length; |
|
446 } |
|
447 |
|
448 /** |
|
449 * Returns whether the array points somewhere and has at least one element. |
|
450 */ |
|
451 operator bool() const |
|
452 { |
|
453 return (length > 0) && UnsizedArray<T>::operator bool(); |
|
454 } |
|
455 |
|
456 /** |
|
457 * Iterator for an Array. Use is similar to that of STL const_iterators: |
|
458 * |
|
459 * struct S { ... }; |
|
460 * Array<S> a(buf, len); |
|
461 * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) { |
|
462 * // Do something with *it. |
|
463 * } |
|
464 */ |
|
465 class iterator |
|
466 { |
|
467 public: |
|
468 iterator(): item(nullptr) { } |
|
469 |
|
470 const T &operator *() const |
|
471 { |
|
472 return *item; |
|
473 } |
|
474 |
|
475 const T *operator ->() const |
|
476 { |
|
477 return item; |
|
478 } |
|
479 |
|
480 iterator &operator ++() |
|
481 { |
|
482 ++item; |
|
483 return *this; |
|
484 } |
|
485 |
|
486 bool operator<(const iterator &other) const |
|
487 { |
|
488 return item < other.item; |
|
489 } |
|
490 protected: |
|
491 friend class Array<T>; |
|
492 iterator(const T &item): item(&item) { } |
|
493 |
|
494 private: |
|
495 const T *item; |
|
496 }; |
|
497 |
|
498 /** |
|
499 * Returns an iterator pointing at the beginning of the Array |
|
500 */ |
|
501 iterator begin() const { |
|
502 if (length) |
|
503 return iterator(UnsizedArray<T>::operator[](0)); |
|
504 return iterator(); |
|
505 } |
|
506 |
|
507 /** |
|
508 * Returns an iterator pointing past the end of the Array |
|
509 */ |
|
510 iterator end() const { |
|
511 if (length) |
|
512 return iterator(UnsizedArray<T>::operator[](length)); |
|
513 return iterator(); |
|
514 } |
|
515 |
|
516 /** |
|
517 * Reverse iterator for an Array. Use is similar to that of STL |
|
518 * const_reverse_iterators: |
|
519 * |
|
520 * struct S { ... }; |
|
521 * Array<S> a(buf, len); |
|
522 * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) { |
|
523 * // Do something with *it. |
|
524 * } |
|
525 */ |
|
526 class reverse_iterator |
|
527 { |
|
528 public: |
|
529 reverse_iterator(): item(nullptr) { } |
|
530 |
|
531 const T &operator *() const |
|
532 { |
|
533 const T *tmp = item; |
|
534 return *--tmp; |
|
535 } |
|
536 |
|
537 const T *operator ->() const |
|
538 { |
|
539 return &operator*(); |
|
540 } |
|
541 |
|
542 reverse_iterator &operator ++() |
|
543 { |
|
544 --item; |
|
545 return *this; |
|
546 } |
|
547 |
|
548 bool operator<(const reverse_iterator &other) const |
|
549 { |
|
550 return item > other.item; |
|
551 } |
|
552 protected: |
|
553 friend class Array<T>; |
|
554 reverse_iterator(const T &item): item(&item) { } |
|
555 |
|
556 private: |
|
557 const T *item; |
|
558 }; |
|
559 |
|
560 /** |
|
561 * Returns a reverse iterator pointing at the end of the Array |
|
562 */ |
|
563 reverse_iterator rbegin() const { |
|
564 if (length) |
|
565 return reverse_iterator(UnsizedArray<T>::operator[](length)); |
|
566 return reverse_iterator(); |
|
567 } |
|
568 |
|
569 /** |
|
570 * Returns a reverse iterator pointing past the beginning of the Array |
|
571 */ |
|
572 reverse_iterator rend() const { |
|
573 if (length) |
|
574 return reverse_iterator(UnsizedArray<T>::operator[](0)); |
|
575 return reverse_iterator(); |
|
576 } |
|
577 private: |
|
578 idx_t length; |
|
579 }; |
|
580 |
|
581 /** |
|
582 * Transforms a pointer-to-function to a pointer-to-object pointing at the |
|
583 * same address. |
|
584 */ |
|
585 template <typename T> |
|
586 void *FunctionPtr(T func) |
|
587 { |
|
588 union { |
|
589 void *ptr; |
|
590 T func; |
|
591 } f; |
|
592 f.func = func; |
|
593 return f.ptr; |
|
594 } |
|
595 |
|
596 #endif /* Utils_h */ |
|
597 |