]>
Commit | Line | Data |
---|---|---|
83c7162d | 1 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
923072b8 FG |
2 | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
3 | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your | |
83c7162d XL |
4 | // option. This file may not be copied, modified, or distributed |
5 | // except according to those terms. | |
6 | ||
7 | //! Provides an unsafe owned buffer type, used in implementing `Tendril`. | |
8 | ||
923072b8 | 9 | use std::{mem, ptr, slice, u32}; |
83c7162d XL |
10 | |
11 | use OFLOW; | |
12 | ||
13 | pub const MIN_CAP: u32 = 16; | |
14 | ||
15 | pub const MAX_LEN: usize = u32::MAX as usize; | |
16 | ||
17 | /// A buffer points to a header of type `H`, which is followed by `MIN_CAP` or more | |
18 | /// bytes of storage. | |
19 | pub struct Buf32<H> { | |
20 | pub ptr: *mut H, | |
21 | pub len: u32, | |
22 | pub cap: u32, | |
23 | } | |
24 | ||
25 | #[inline(always)] | |
26 | fn bytes_to_vec_capacity<H>(x: u32) -> usize { | |
27 | let header = mem::size_of::<H>(); | |
28 | debug_assert!(header > 0); | |
29 | let x = (x as usize).checked_add(header).expect(OFLOW); | |
923072b8 | 30 | // Integer ceil https://stackoverflow.com/a/2745086/1162888 |
83c7162d XL |
31 | 1 + ((x - 1) / header) |
32 | } | |
33 | ||
34 | impl<H> Buf32<H> { | |
35 | #[inline] | |
36 | pub unsafe fn with_capacity(mut cap: u32, h: H) -> Buf32<H> { | |
37 | if cap < MIN_CAP { | |
38 | cap = MIN_CAP; | |
39 | } | |
40 | ||
41 | let mut vec = Vec::<H>::with_capacity(bytes_to_vec_capacity::<H>(cap)); | |
42 | let ptr = vec.as_mut_ptr(); | |
43 | mem::forget(vec); | |
44 | ptr::write(ptr, h); | |
45 | ||
46 | Buf32 { | |
47 | ptr: ptr, | |
48 | len: 0, | |
49 | cap: cap, | |
50 | } | |
51 | } | |
52 | ||
53 | #[inline] | |
54 | pub unsafe fn destroy(self) { | |
923072b8 FG |
55 | mem::drop(Vec::from_raw_parts( |
56 | self.ptr, | |
57 | 1, | |
58 | bytes_to_vec_capacity::<H>(self.cap), | |
59 | )); | |
83c7162d XL |
60 | } |
61 | ||
62 | #[inline(always)] | |
63 | pub unsafe fn data_ptr(&self) -> *mut u8 { | |
64 | (self.ptr as *mut u8).offset(mem::size_of::<H>() as isize) | |
65 | } | |
66 | ||
67 | #[inline(always)] | |
68 | pub unsafe fn data(&self) -> &[u8] { | |
69 | slice::from_raw_parts(self.data_ptr(), self.len as usize) | |
70 | } | |
71 | ||
72 | #[inline(always)] | |
73 | pub unsafe fn data_mut(&mut self) -> &mut [u8] { | |
74 | slice::from_raw_parts_mut(self.data_ptr(), self.len as usize) | |
75 | } | |
76 | ||
77 | /// Grow the capacity to at least `new_cap`. | |
78 | /// | |
79 | /// This will panic if the capacity calculation overflows `u32`. | |
80 | #[inline] | |
81 | pub unsafe fn grow(&mut self, new_cap: u32) { | |
82 | if new_cap <= self.cap { | |
83 | return; | |
84 | } | |
85 | ||
86 | let new_cap = new_cap.checked_next_power_of_two().expect(OFLOW); | |
87 | let mut vec = Vec::from_raw_parts(self.ptr, 0, bytes_to_vec_capacity::<H>(self.cap)); | |
88 | vec.reserve_exact(bytes_to_vec_capacity::<H>(new_cap)); | |
89 | self.ptr = vec.as_mut_ptr(); | |
90 | self.cap = new_cap; | |
91 | mem::forget(vec); | |
92 | } | |
93 | } | |
94 | ||
95 | #[cfg(test)] | |
96 | mod test { | |
97 | use super::Buf32; | |
98 | use std::ptr; | |
99 | ||
100 | #[test] | |
101 | fn smoke_test() { | |
102 | unsafe { | |
103 | let mut b = Buf32::with_capacity(0, 0u8); | |
104 | assert_eq!(b"", b.data()); | |
105 | ||
106 | b.grow(5); | |
107 | ptr::copy_nonoverlapping(b"Hello".as_ptr(), b.data_ptr(), 5); | |
108 | ||
109 | assert_eq!(b"", b.data()); | |
110 | b.len = 5; | |
111 | assert_eq!(b"Hello", b.data()); | |
112 | ||
113 | b.grow(1337); | |
114 | assert!(b.cap >= 1337); | |
115 | assert_eq!(b"Hello", b.data()); | |
116 | ||
117 | b.destroy(); | |
118 | } | |
119 | } | |
120 | } |