1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use libc;
use std::cmp;
use std::mem;
use crate::error::{ArrowError, Result};
const ALIGNMENT: usize = 64;
#[cfg(windows)]
#[link(name = "msvcrt")]
extern "C" {
fn _aligned_malloc(size: libc::size_t, alignment: libc::size_t) -> libc::size_t;
fn _aligned_free(prt: *const u8);
}
#[cfg(windows)]
pub fn allocate_aligned(size: usize) -> Result<*mut u8> {
let page = unsafe { _aligned_malloc(size as libc::size_t, ALIGNMENT as libc::size_t) };
match page {
0 => Err(ArrowError::MemoryError(
"Failed to allocate memory".to_string(),
)),
_ => Ok(unsafe { mem::transmute::<libc::size_t, *mut u8>(page) }),
}
}
#[cfg(not(windows))]
pub fn allocate_aligned(size: usize) -> Result<*mut u8> {
unsafe {
let mut page: *mut libc::c_void = mem::uninitialized();
let result = libc::posix_memalign(&mut page, ALIGNMENT, size);
match result {
0 => Ok(mem::transmute::<*mut libc::c_void, *mut u8>(page)),
_ => Err(ArrowError::MemoryError(
"Failed to allocate memory".to_string(),
)),
}
}
}
#[cfg(windows)]
pub fn free_aligned(p: *const u8) {
unsafe {
_aligned_free(p);
}
}
#[cfg(not(windows))]
pub fn free_aligned(p: *const u8) {
unsafe {
libc::free(mem::transmute::<*const u8, *mut libc::c_void>(p));
}
}
pub fn reallocate(old_size: usize, new_size: usize, pointer: *const u8) -> Result<*const u8> {
unsafe {
let old_src = mem::transmute::<*const u8, *mut libc::c_void>(pointer);
let result = allocate_aligned(new_size)?;
let dst = mem::transmute::<*const u8, *mut libc::c_void>(result);
libc::memcpy(dst, old_src, cmp::min(old_size, new_size));
free_aligned(pointer);
Ok(result)
}
}
pub unsafe fn memcpy(dst: *mut u8, src: *const u8, len: usize) {
let src = mem::transmute::<*const u8, *const libc::c_void>(src);
let dst = mem::transmute::<*mut u8, *mut libc::c_void>(dst);
libc::memcpy(dst, src, len);
}
extern "C" {
#[inline]
pub fn memcmp(p1: *const u8, p2: *const u8, len: usize) -> i32;
}
pub fn is_aligned<T>(p: *const T, a: usize) -> bool {
let a_minus_one = a.wrapping_sub(1);
let pmoda = p as usize & a_minus_one;
pmoda == 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_allocate() {
for _ in 0..10 {
let p = allocate_aligned(1024).unwrap();
assert_eq!(0, (p as usize) % 64);
}
}
#[test]
fn test_is_aligned() {
let mut ptr = allocate_aligned(10).unwrap();
assert_eq!(true, is_aligned::<u8>(ptr, 1));
assert_eq!(true, is_aligned::<u8>(ptr, 2));
assert_eq!(true, is_aligned::<u8>(ptr, 4));
ptr = unsafe { ptr.offset(1) };
assert_eq!(true, is_aligned::<u8>(ptr, 1));
assert_eq!(false, is_aligned::<u8>(ptr, 2));
assert_eq!(false, is_aligned::<u8>(ptr, 4));
}
}