v2 / vlib / builtin / cfns_wrapper.c.v
179 lines · 169 sloc · 5.69 KB · 25d72fef689d2f0d18beaa6dceaef9f6b622d6b5
Raw
1module builtin
2
3// vstrlen returns the V length of the C string `s` (0 terminator is not counted).
4// The C string is expected to be a &u8 pointer.
5@[inline; unsafe]
6pub fn vstrlen(s &u8) int {
7 return int(unsafe { C.strlen(&char(s)) })
8}
9
10// vstrlen_char returns the V length of the C string `s` (0 terminator is not counted).
11// The C string is expected to be a &char pointer.
12@[inline; unsafe]
13pub fn vstrlen_char(s &char) int {
14 return int(unsafe { C.strlen(s) })
15}
16
17// vmemcpy copies n bytes from memory area src to memory area dest.
18// The memory areas *MUST NOT OVERLAP*. Use vmemmove, if the memory
19// areas do overlap. vmemcpy returns a pointer to `dest`.
20@[inline; unsafe]
21pub fn vmemcpy(dest voidptr, const_src voidptr, n isize) voidptr {
22 $if trace_vmemcpy ? {
23 C.fprintf(C.stderr, c'vmemcpy dest: %p src: %p n: %6ld\n', dest, const_src, n)
24 }
25 $if trace_vmemcpy_nulls ? {
26 if dest == unsafe { 0 } || const_src == unsafe { 0 } {
27 C.fprintf(C.stderr, c'vmemcpy null pointers passed, dest: %p src: %p n: %6ld\n', dest,
28 const_src, n)
29 print_backtrace()
30 }
31 }
32 if n == 0 || u64(dest) <= 0xFFFF || u64(const_src) <= 0xFFFF {
33 return dest
34 }
35 unsafe {
36 return C.memcpy(dest, const_src, n)
37 }
38}
39
40// vmemmove copies n bytes from memory area `src` to memory area `dest`.
41// The memory areas *MAY* overlap: copying takes place as though the bytes
42// in `src` are first copied into a temporary array that does not overlap
43// `src` or `dest`, and the bytes are then copied from the temporary array
44// to `dest`. vmemmove returns a pointer to `dest`.
45@[inline; unsafe]
46pub fn vmemmove(dest voidptr, const_src voidptr, n isize) voidptr {
47 $if trace_vmemmove ? {
48 C.fprintf(C.stderr, c'vmemmove dest: %p src: %p n: %6ld\n', dest, const_src, n)
49 }
50 if n == 0 || u64(dest) <= 0xFFFF || u64(const_src) <= 0xFFFF {
51 return dest
52 }
53 unsafe {
54 return C.memmove(dest, const_src, n)
55 }
56}
57
58// vmemcmp compares the first n bytes (each interpreted as unsigned char)
59// of the memory areas s1 and s2. It returns an integer less than, equal to,
60// or greater than zero, if the first n bytes of s1 is found, respectively,
61// to be less than, to match, or be greater than the first n bytes of s2.
62// For a nonzero return value, the sign is determined by the sign of the
63// difference between the first pair of bytes (interpreted as unsigned char)
64// that differ in s1 and s2.
65// If n is zero, the return value is zero.
66// Do NOT use vmemcmp to compare security critical data, such as cryptographic
67// secrets, because the required CPU time depends on the number of equal bytes.
68// You should use a function that performs comparisons in constant time for
69// this.
70@[inline; unsafe]
71pub fn vmemcmp(const_s1 voidptr, const_s2 voidptr, n isize) int {
72 $if trace_vmemcmp ? {
73 C.fprintf(C.stderr, c'vmemcmp s1: %p s2: %p n: %6ld\n', const_s1, const_s2, n)
74 }
75 if n == 0 || u64(const_s1) <= 0xFFFF || u64(const_s2) <= 0xFFFF {
76 return 0
77 }
78 unsafe {
79 return C.memcmp(const_s1, const_s2, n)
80 }
81}
82
83// vmemset fills the first `n` bytes of the memory area pointed to by `s`,
84// with the constant byte `c`. It returns a pointer to the memory area `s`.
85@[inline; unsafe]
86pub fn vmemset(s voidptr, c int, n isize) voidptr {
87 $if trace_vmemset ? {
88 C.fprintf(C.stderr, c'vmemset s: %p c: %d n: %6ld\n', s, c, n)
89 }
90 $if trace_vmemset_nulls ? {
91 if s == unsafe { 0 } {
92 C.fprintf(C.stderr, c'vmemset null pointers passed s: %p, c: %6d, n: %6ld\n', s, c, n)
93 print_backtrace()
94 }
95 }
96 if n == 0 || u64(s) <= 0xFFFF {
97 return s
98 }
99 unsafe {
100 return C.memset(s, c, n)
101 }
102}
103
104type FnSortCB = fn (const_a voidptr, const_b voidptr) int
105
106@[inline; unsafe]
107fn vsort_ptr_at(base voidptr, index usize, size usize) voidptr {
108 return unsafe { voidptr(&u8(base) + index * size) }
109}
110
111@[unsafe]
112fn vstable_sort_merge(source voidptr, dest voidptr, left usize, mid usize, right usize, size usize, sort_cb FnSortCB) {
113 mut left_index := left
114 mut right_index := mid
115 mut dest_index := left
116 for left_index < mid && right_index < right {
117 left_ptr := vsort_ptr_at(source, left_index, size)
118 right_ptr := vsort_ptr_at(source, right_index, size)
119 if sort_cb(left_ptr, right_ptr) <= 0 {
120 vmemcpy(vsort_ptr_at(dest, dest_index, size), left_ptr, isize(size))
121 left_index++
122 } else {
123 vmemcpy(vsort_ptr_at(dest, dest_index, size), right_ptr, isize(size))
124 right_index++
125 }
126 dest_index++
127 }
128 if left_index < mid {
129 vmemcpy(vsort_ptr_at(dest, dest_index, size), vsort_ptr_at(source, left_index, size),
130 isize((mid - left_index) * size))
131 }
132 if right_index < right {
133 vmemcpy(vsort_ptr_at(dest, dest_index, size), vsort_ptr_at(source, right_index, size),
134 isize((right - right_index) * size))
135 }
136}
137
138@[inline; unsafe]
139fn vqsort(base voidptr, nmemb usize, size usize, sort_cb FnSortCB) {
140 $if trace_vqsort ? {
141 C.fprintf(C.stderr, c'vqsort base: %p, nmemb: %6uld, size: %6uld, sort_cb: %p\n', base,
142 nmemb, size, sort_cb)
143 }
144 if nmemb < 2 || size == 0 {
145 return
146 }
147 $if trace_vqsort_nulls ? {
148 if base == unsafe { 0 } || voidptr(sort_cb) == unsafe { nil } {
149 C.fprintf(C.stderr,
150 c'vqsort null pointers passed base: %p, nmemb: %6uld, size: %6uld, sort_cb: %p\n',
151 base, nmemb, size, sort_cb)
152 print_backtrace()
153 }
154 }
155 total_size := isize(nmemb * size)
156 buffer := malloc(total_size)
157 defer {
158 free(buffer)
159 }
160 mut source := base
161 mut dest := voidptr(buffer)
162 mut width := usize(1)
163 for width < nmemb {
164 mut left := usize(0)
165 for left < nmemb {
166 mid := if left + width < nmemb { left + width } else { nmemb }
167 right := if left + width + width < nmemb { left + width + width } else { nmemb }
168 vstable_sort_merge(source, dest, left, mid, right, size, sort_cb)
169 left += width + width
170 }
171 mut tmp := source
172 source = dest
173 dest = tmp
174 width += width
175 }
176 if source != base {
177 vmemcpy(base, source, total_size)
178 }
179}
180