cfx_storage/impls/merkle_patricia_trie/
maybe_in_place_byte_array.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use std::{
6    marker::PhantomData,
7    ptr::{null_mut, NonNull},
8    slice,
9};
10
11/// Use FieldsOffsetMaybeInPlaceByteArrayMemoryManager and macro
12/// make_parallel_field_maybe_in_place_byte_array_memory_manager to manage
13/// construction / destruction of MaybeInPlaceByteArray.
14///
15/// The memory manager should be placed as a parallel field in the same struct
16/// as the MaybeInPlaceByteArray. See CompressedPathRaw for example.
17pub union MaybeInPlaceByteArray {
18    pub in_place: [u8; Self::MAX_INPLACE_SIZE],
19    /// Only raw pointer is 8B.
20    pub ptr: *mut u8,
21}
22
23impl MaybeInPlaceByteArray {
24    pub const MAX_INPLACE_SIZE: usize = 8;
25}
26
27#[test]
28fn test_maybe_inplace_byte_array_size_is_8_bytes() {
29    assert_eq!(
30        std::mem::size_of::<MaybeInPlaceByteArray>(),
31        MaybeInPlaceByteArray::MAX_INPLACE_SIZE
32    );
33}
34impl Default for MaybeInPlaceByteArray {
35    fn default() -> Self {
36        Self {
37            in_place: Default::default(),
38        }
39    }
40}
41
42/// Trait for managing construction / destruction of MaybeInPlaceByteArray.
43/// FieldsOffsetMaybeInPlaceByteArrayMemoryManager implements this trait.
44#[allow(drop_bounds)]
45pub trait MaybeInPlaceByteArrayMemoryManagerTrait: Drop {
46    /// Unsafe because the size isn't set to 0.
47    unsafe fn drop_value(&mut self) {
48        let size = self.get_size();
49        if size > MaybeInPlaceByteArray::MAX_INPLACE_SIZE {
50            self.get_in_place_byte_array_mut().ptr_into_vec(size);
51        }
52    }
53
54    fn get_size(&self) -> usize;
55    fn set_size(&mut self, size: usize);
56    fn get_in_place_byte_array(&self) -> &MaybeInPlaceByteArray;
57    fn get_in_place_byte_array_mut(&mut self) -> &mut MaybeInPlaceByteArray;
58
59    /// Unsafe because the destination may not be empty.
60    unsafe fn move_byte_array_dest_unchecked(
61        &mut self, free_dest: &mut MaybeInPlaceByteArray,
62    ) {
63        self.set_size(0);
64
65        std::ptr::copy_nonoverlapping(
66            self.get_in_place_byte_array(),
67            free_dest,
68            1,
69        );
70    }
71
72    fn move_to<T: MaybeInPlaceByteArrayMemoryManagerTrait>(
73        &mut self, dest: &mut T,
74    ) {
75        let size = self.get_size();
76
77        // Safe because the dest size is set right later.
78        unsafe {
79            dest.drop_value();
80            dest.set_size(size);
81        }
82        if size != 0 {
83            // Safe because the old content in destination is already freed.
84            unsafe {
85                self.move_byte_array_dest_unchecked(
86                    dest.get_in_place_byte_array_mut(),
87                );
88            }
89        }
90    }
91}
92
93#[derive(Default, Clone)]
94pub struct FieldsOffsetMaybeInPlaceByteArrayMemoryManager<
95    SizeFieldType,
96    SizeFieldGetterSetter: SizeFieldConverterTrait<SizeFieldType>,
97    ByteArrayOffsetAccessor: ParallelFieldOffsetAccessor<Self, MaybeInPlaceByteArray>,
98    SizeFieldOffsetAccessor: ParallelFieldOffsetAccessor<Self, SizeFieldType>,
99> {
100    _marker_size_type: PhantomData<SizeFieldType>,
101    _marker_size_field_getter_setter: PhantomData<SizeFieldGetterSetter>,
102    _marker_byte_array_accessor: PhantomData<ByteArrayOffsetAccessor>,
103    _marker_size_field_accessor: PhantomData<SizeFieldOffsetAccessor>,
104}
105
106impl<
107        SizeFieldType,
108        SizeFieldGetterSetter: SizeFieldConverterTrait<SizeFieldType>,
109        ByteArrayOffsetAccessor: ParallelFieldOffsetAccessor<Self, MaybeInPlaceByteArray>,
110        SizeFieldOffsetAccessor: ParallelFieldOffsetAccessor<Self, SizeFieldType>,
111    > Drop
112    for FieldsOffsetMaybeInPlaceByteArrayMemoryManager<
113        SizeFieldType,
114        SizeFieldGetterSetter,
115        ByteArrayOffsetAccessor,
116        SizeFieldOffsetAccessor,
117    >
118{
119    fn drop(&mut self) {
120        // Safe because on destruction it's not necessary to set size to 0
121        unsafe {
122            self.drop_value();
123        }
124    }
125}
126
127impl MaybeInPlaceByteArray {
128    /// Take ptr out and clear ptr.
129    pub unsafe fn ptr_into_vec(&mut self, size: usize) -> Vec<u8> {
130        debug_assert!(!self.ptr.is_null() || size == 0);
131        let ptr = if self.ptr.is_null() {
132            NonNull::dangling().as_ptr()
133        } else {
134            self.ptr
135        };
136        let vec = Vec::from_raw_parts(ptr, size, size);
137        self.ptr = null_mut();
138        vec
139    }
140
141    unsafe fn ptr_slice(&self, size: usize) -> &[u8] {
142        debug_assert!(!self.ptr.is_null() || size == 0);
143        slice::from_raw_parts(
144            if self.ptr.is_null() {
145                NonNull::dangling().as_ptr()
146            } else {
147                self.ptr
148            },
149            size,
150        )
151    }
152
153    unsafe fn ptr_slice_mut(&mut self, size: usize) -> &mut [u8] {
154        debug_assert!(!self.ptr.is_null() || size == 0);
155        slice::from_raw_parts_mut(
156            if self.ptr.is_null() {
157                NonNull::dangling().as_ptr()
158            } else {
159                self.ptr
160            },
161            size,
162        )
163    }
164
165    pub fn get_slice_mut(&mut self, size: usize) -> &mut [u8] {
166        let is_ptr = size > Self::MAX_INPLACE_SIZE;
167        unsafe {
168            if is_ptr {
169                self.ptr_slice_mut(size)
170            } else {
171                &mut self.in_place[0..size]
172            }
173        }
174    }
175
176    pub fn get_slice(&self, size: usize) -> &[u8] {
177        let is_ptr = size > Self::MAX_INPLACE_SIZE;
178        unsafe {
179            if is_ptr {
180                self.ptr_slice(size)
181            } else {
182                &self.in_place[0..size]
183            }
184        }
185    }
186
187    pub fn into_boxed_slice(&mut self, size: usize) -> Box<[u8]> {
188        let is_ptr = size > Self::MAX_INPLACE_SIZE;
189        unsafe {
190            if is_ptr {
191                self.ptr_into_vec(size)
192            } else {
193                Vec::from(&self.in_place[0..size])
194            }
195        }
196        .into_boxed_slice()
197    }
198
199    pub fn new(mut value: Box<[u8]>, size: usize) -> Self {
200        if size > Self::MAX_INPLACE_SIZE {
201            let ptr = value.as_mut_ptr();
202            let _ = Box::into_raw(value);
203            Self { ptr }
204        } else {
205            let mut in_place: [u8; Self::MAX_INPLACE_SIZE] = Default::default();
206            in_place[0..size].copy_from_slice(&*value);
207            Self { in_place }
208        }
209    }
210
211    pub fn new_zeroed(size: usize) -> Self {
212        Self::new(vec![0u8; size].into_boxed_slice(), size)
213    }
214
215    pub fn copy_from(value: &[u8], size: usize) -> Self {
216        if size > Self::MAX_INPLACE_SIZE {
217            let mut owned_copy = Box::<[u8]>::from(value);
218            let ptr = owned_copy.as_mut_ptr();
219            let _ = Box::into_raw(owned_copy);
220            Self { ptr }
221        } else {
222            let mut x: Self = Self {
223                in_place: Default::default(),
224            };
225            unsafe {
226                x.in_place[0..size].copy_from_slice(value);
227            }
228            x
229        }
230    }
231
232    pub fn clone(&self, size: usize) -> Self {
233        if size > Self::MAX_INPLACE_SIZE {
234            // Safety guaranteed by condition.
235            Self::copy_from(unsafe { self.ptr_slice(size) }, size)
236        } else {
237            Self {
238                in_place: unsafe { self.in_place }.clone(),
239            }
240        }
241    }
242}
243
244pub trait ParallelFieldOffsetAccessor<FromFieldType, TargetFieldType> {
245    fn get(m: &FromFieldType) -> &TargetFieldType;
246    fn get_mut(m: &mut FromFieldType) -> &mut TargetFieldType;
247}
248
249pub trait SizeFieldConverterTrait<SizeFieldType> {
250    fn max_size() -> usize;
251    fn is_size_over_limit(size: usize) -> bool;
252    fn get(size_field: &SizeFieldType) -> usize;
253    fn set(size_field: &mut SizeFieldType, size: usize);
254}
255
256#[derive(Default)]
257pub struct TrivialSizeFieldConverterU16 {}
258
259impl SizeFieldConverterTrait<u16> for TrivialSizeFieldConverterU16 {
260    fn max_size() -> usize { std::u16::MAX as usize }
261
262    fn is_size_over_limit(size: usize) -> bool { size > std::u16::MAX as usize }
263
264    fn get(size_field: &u16) -> usize { (*size_field) as usize }
265
266    fn set(size_field: &mut u16, size: usize) { *size_field = size as u16; }
267}
268
269impl<
270        SizeFieldType,
271        SizeFieldGetterSetter: SizeFieldConverterTrait<SizeFieldType>,
272        ByteArrayOffsetAccessor: ParallelFieldOffsetAccessor<Self, MaybeInPlaceByteArray>,
273        SizeFieldOffsetAccessor: ParallelFieldOffsetAccessor<Self, SizeFieldType>,
274    > MaybeInPlaceByteArrayMemoryManagerTrait
275    for FieldsOffsetMaybeInPlaceByteArrayMemoryManager<
276        SizeFieldType,
277        SizeFieldGetterSetter,
278        ByteArrayOffsetAccessor,
279        SizeFieldOffsetAccessor,
280    >
281{
282    fn get_size(&self) -> usize {
283        SizeFieldGetterSetter::get(SizeFieldOffsetAccessor::get(self))
284    }
285
286    fn set_size(&mut self, size: usize) {
287        SizeFieldGetterSetter::set(
288            SizeFieldOffsetAccessor::get_mut(self),
289            size,
290        );
291    }
292
293    fn get_in_place_byte_array(&self) -> &MaybeInPlaceByteArray {
294        ByteArrayOffsetAccessor::get(self)
295    }
296
297    fn get_in_place_byte_array_mut(&mut self) -> &mut MaybeInPlaceByteArray {
298        ByteArrayOffsetAccessor::get_mut(self)
299    }
300}