v2 / vlib / builtin / int.v
633 lines · 564 sloc · 14.49 KB · 0832a68bd714695d292aef2ca9b08d16b9a86516
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module builtin
5
6pub struct VContext {
7 allocator int
8}
9
10pub type byte = u8
11
12// ptr_str returns a string with the address of `ptr`.
13pub fn ptr_str(ptr voidptr) string {
14 buf1 := u64_to_hex_no_leading_zeros(u64(ptr), 16)
15 return buf1
16}
17
18// str returns the string equivalent of x.
19pub fn (x isize) str() string {
20 return i64(x).str()
21}
22
23// str returns the string equivalent of x.
24pub fn (x usize) str() string {
25 return u64(x).str()
26}
27
28// str returns a string with the address stored in the pointer cptr.
29pub fn (cptr &char) str() string {
30 return u64(cptr).hex()
31}
32
33// digit pairs in reverse order
34const digit_pairs = '00102030405060708090011121314151617181910212223242526272829203132333435363738393041424344454647484940515253545556575859506162636465666768696071727374757677787970818283848586878889809192939495969798999'
35
36pub const min_i8 = i8(-128)
37pub const max_i8 = i8(127)
38
39pub const min_i16 = i16(-32768)
40pub const max_i16 = i16(32767)
41
42pub const min_i32 = i32(-2147483648)
43pub const max_i32 = i32(2147483647)
44
45// -9223372036854775808 is wrong, because C compilers parse literal values
46// without sign first, and 9223372036854775808 overflows i64, hence the
47// consecutive subtraction by 1
48pub const min_i64 = i64(-9223372036854775807 - 1)
49pub const max_i64 = i64(9223372036854775807)
50
51pub const min_int = $if new_int ? && x64 { int(min_i64) } $else { int(min_i32) }
52pub const max_int = $if new_int ? && x64 { int(max_i64) } $else { int(max_i32) }
53
54pub const min_u8 = u8(0)
55pub const max_u8 = u8(255)
56
57pub const min_u16 = u16(0)
58pub const max_u16 = u16(65535)
59
60pub const min_u32 = u32(0)
61pub const max_u32 = u32(4294967295)
62
63pub const min_u64 = u64(0)
64pub const max_u64 = u64(18446744073709551615)
65
66// str_l returns the string representation of the integer nn with max chars.
67@[direct_array_access; inline]
68fn (nn int) str_l(max int) string {
69 // This implementation is the quickest with gcc -O2
70 unsafe {
71 mut n := i64(nn)
72 mut d := 0
73 if n == 0 {
74 return '0'
75 }
76
77 // overflow protect
78 $if new_int ? && x64 {
79 if n == min_i64 {
80 return '-9223372036854775808'
81 }
82 } $else {
83 if n == min_i32 {
84 return '-2147483648'
85 }
86 }
87
88 mut is_neg := false
89 if n < 0 {
90 n = -n
91 is_neg = true
92 }
93 mut index := max
94 mut buf := malloc_noscan(max + 1)
95 buf[index] = 0
96 index--
97
98 for n > 0 {
99 n1 := int(n / 100)
100 // calculate the digit_pairs start index
101 d = int(u32(int(n) - (n1 * 100)) << 1)
102 n = n1
103 buf[index] = digit_pairs.str[d]
104 index--
105 d++
106 buf[index] = digit_pairs.str[d]
107 index--
108 }
109 index++
110 // remove head zero
111 if d < 20 {
112 index++
113 }
114 // Prepend - if it's negative
115 if is_neg {
116 index--
117 buf[index] = `-`
118 }
119 diff := max - index
120 vmemmove(buf, voidptr(buf + index), diff + 1)
121 return tos(buf, diff)
122 }
123}
124
125// str returns the value of the `i8` as a `string`.
126// Example: assert i8(-2).str() == '-2'
127pub fn (n i8) str() string {
128 return int(n).str_l(4)
129}
130
131// str returns the value of the `i16` as a `string`.
132// Example: assert i16(-20).str() == '-20'
133pub fn (n i16) str() string {
134 return int(n).str_l(6)
135}
136
137// str returns the value of the `u16` as a `string`.
138// Example: assert u16(20).str() == '20'
139pub fn (n u16) str() string {
140 return int(n).str_l(6)
141}
142
143pub fn (n i32) str() string {
144 return int(n).str_l(11)
145}
146
147pub fn (nn int) hex_full() string {
148 return u64_to_hex(u64(nn), 8)
149}
150
151// str returns the value of the `int` as a `string`.
152// Example: assert int(-2020).str() == '-2020'
153pub fn (n int) str() string {
154 $if new_int ? {
155 return impl_i64_to_string(n)
156 } $else {
157 return n.str_l(11)
158 }
159}
160
161// str returns the value of the `u32` as a `string`.
162// Example: assert u32(20000).str() == '20000'
163@[direct_array_access; inline]
164pub fn (nn u32) str() string {
165 unsafe {
166 mut n := nn
167 mut d := u32(0)
168 if n == 0 {
169 return '0'
170 }
171 max := 10
172 mut buf := malloc_noscan(max + 1)
173 mut index := max
174 buf[index] = 0
175 index--
176 for n > 0 {
177 n1 := n / u32(100)
178 d = ((n - (n1 * u32(100))) << u32(1))
179 n = n1
180 buf[index] = digit_pairs[int(d)]
181 index--
182 d++
183 buf[index] = digit_pairs[int(d)]
184 index--
185 }
186 index++
187 // remove head zero
188 if d < u32(20) {
189 index++
190 }
191 diff := max - index
192 vmemmove(buf, voidptr(buf + index), diff + 1)
193 return tos(buf, diff)
194 }
195}
196
197// str returns the value of the `int_literal` as a `string`.
198@[inline]
199pub fn (n int_literal) str() string {
200 return impl_i64_to_string(n)
201}
202
203// str returns the value of the `i64` as a `string`.
204// Example: assert i64(-200000).str() == '-200000'
205@[inline]
206pub fn (nn i64) str() string {
207 return impl_i64_to_string(nn)
208}
209
210@[direct_array_access]
211fn impl_i64_to_string(nn i64) string {
212 unsafe {
213 mut n := nn
214 mut d := i64(0)
215 if n == 0 {
216 return '0'
217 } else if n == min_i64 {
218 return '-9223372036854775808'
219 }
220 max := 20
221 mut buf := malloc_noscan(max + 1)
222 mut is_neg := false
223 if n < 0 {
224 n = -n
225 is_neg = true
226 }
227 mut index := max
228 buf[index] = 0
229 index--
230 for n > 0 {
231 n1 := n / i64(100)
232 d = (u32(n - (n1 * i64(100))) << i64(1))
233 n = n1
234 buf[index] = digit_pairs[int(d)]
235 index--
236 d++
237 buf[index] = digit_pairs[int(d)]
238 index--
239 }
240 index++
241 // remove head zero
242 if d < i64(20) {
243 index++
244 }
245 // Prepend - if it's negative
246 if is_neg {
247 index--
248 buf[index] = `-`
249 }
250 diff := max - index
251 vmemmove(buf, voidptr(buf + index), diff + 1)
252 return tos(buf, diff)
253 }
254}
255
256// str returns the value of the `u64` as a `string`.
257// Example: assert u64(2000000).str() == '2000000'
258@[direct_array_access; inline]
259pub fn (nn u64) str() string {
260 unsafe {
261 mut n := nn
262 mut d := u64(0)
263 if n == 0 {
264 return '0'
265 }
266 max := 20
267 mut buf := malloc_noscan(max + 1)
268 mut index := max
269 buf[index] = 0
270 index--
271 for n > 0 {
272 n1 := n / 100
273 d = ((n - (n1 * 100)) << 1)
274 n = n1
275 buf[index] = digit_pairs[int(d)]
276 index--
277 d++
278 buf[index] = digit_pairs[int(d)]
279 index--
280 }
281 index++
282 // remove head zero
283 if d < 20 {
284 index++
285 }
286 diff := max - index
287 vmemmove(buf, voidptr(buf + index), diff + 1)
288 return tos(buf, diff)
289 }
290}
291
292// str returns the value of the `bool` as a `string`.
293// Example: assert (2 > 1).str() == 'true'
294pub fn (b bool) str() string {
295 if b {
296 return 'true'
297 }
298 return 'false'
299}
300
301// u64_to_hex converts the number `nn` to a (zero padded if necessary) hexadecimal `string`.
302@[direct_array_access; inline]
303fn u64_to_hex(nn u64, len u8) string {
304 mut n := nn
305 mut buf := [17]u8{}
306 buf[len] = 0
307 mut i := 0
308 for i = len - 1; i >= 0; i-- {
309 d := u8(n & 0xF)
310 buf[i] = if d < 10 { d + `0` } else { d + 87 }
311 n = n >> 4
312 }
313 return unsafe { tos(memdup(&buf[0], len + 1), len) }
314}
315
316// u64_to_hex_no_leading_zeros converts the number `nn` to hexadecimal `string`.
317@[direct_array_access; inline]
318fn u64_to_hex_no_leading_zeros(nn u64, len u8) string {
319 mut n := nn
320 mut buf := [17]u8{}
321 buf[len] = 0
322 mut i := 0
323 for i = len - 1; i >= 0; i-- {
324 d := u8(n & 0xF)
325 buf[i] = if d < 10 { d + `0` } else { d + 87 }
326 n = n >> 4
327 if n == 0 {
328 break
329 }
330 }
331 res_len := len - i
332 return unsafe { tos(memdup(&buf[i], res_len + 1), res_len) }
333}
334
335// hex returns the value of the `byte` as a hexadecimal `string`.
336// Note that the output is zero padded for values below 16.
337// Example: assert u8(2).hex() == '02'
338// Example: assert u8(15).hex() == '0f'
339// Example: assert u8(255).hex() == 'ff'
340pub fn (nn u8) hex() string {
341 if nn == 0 {
342 return '00'
343 }
344 return u64_to_hex(nn, 2)
345}
346
347// hex returns a hexadecimal representation of `c` (as an 8 bit unsigned number).
348// The output is zero padded for values below 16.
349// Example: assert char(`A`).hex() == '41'
350// Example: assert char(`Z`).hex() == '5a'
351// Example: assert char(` `).hex() == '20'
352pub fn (c char) hex() string {
353 return u8(c).hex()
354}
355
356// hex returns a hexadecimal representation of the rune `r` (as a 32 bit unsigned number).
357// Example: assert `A`.hex() == '41'
358// Example: assert `💣`.hex() == '1f4a3'
359pub fn (r rune) hex() string {
360 return u32(r).hex()
361}
362
363// hex returns the value of the `i8` as a hexadecimal `string`.
364// Note that the output is zero padded for values below 16.
365// Example: assert i8(8).hex() == '08'
366// Example: assert i8(10).hex() == '0a'
367// Example: assert i8(15).hex() == '0f'
368pub fn (nn i8) hex() string {
369 if nn == 0 {
370 return '00'
371 }
372 return u64_to_hex(u64(nn), 2)
373}
374
375// hex returns the value of the `u16` as a hexadecimal `string`.
376// Note that the output is ***not*** zero padded.
377// Example: assert u16(2).hex() == '2'
378// Example: assert u16(200).hex() == 'c8'
379pub fn (nn u16) hex() string {
380 if nn == 0 {
381 return '0'
382 }
383 return u64_to_hex_no_leading_zeros(nn, 4)
384}
385
386// hex returns the value of the `i16` as a hexadecimal `string`.
387// Note that the output is ***not*** zero padded.
388// Example: assert i16(2).hex() == '2'
389// Example: assert i16(200).hex() == 'c8'
390pub fn (nn i16) hex() string {
391 return u16(nn).hex()
392}
393
394// hex returns the value of the `u32` as a hexadecimal `string`.
395// Note that the output is ***not*** zero padded.
396// Example: assert u32(2).hex() == '2'
397// Example: assert u32(200).hex() == 'c8'
398pub fn (nn u32) hex() string {
399 if nn == 0 {
400 return '0'
401 }
402 return u64_to_hex_no_leading_zeros(nn, 8)
403}
404
405// hex returns the value of the `int` as a hexadecimal `string`.
406// Note that the output is ***not*** zero padded.
407// Example: assert int(2).hex() == '2'
408// Example: assert int(200).hex() == 'c8'
409pub fn (nn int) hex() string {
410 return u32(nn).hex()
411}
412
413// hex2 returns the value of the `int` as a `0x`-prefixed hexadecimal `string`.
414// Note that the output after `0x` is ***not*** zero padded.
415// Example: assert int(8).hex2() == '0x8'
416// Example: assert int(15).hex2() == '0xf'
417// Example: assert int(18).hex2() == '0x12'
418pub fn (n int) hex2() string {
419 return '0x' + n.hex()
420}
421
422// hex returns the value of the `u64` as a hexadecimal `string`.
423// Note that the output is ***not*** zero padded.
424// Example: assert u64(2).hex() == '2'
425// Example: assert u64(2000).hex() == '7d0'
426pub fn (nn u64) hex() string {
427 if nn == 0 {
428 return '0'
429 }
430 return u64_to_hex_no_leading_zeros(nn, 16)
431}
432
433// hex returns the value of the `i64` as a hexadecimal `string`.
434// Note that the output is ***not*** zero padded.
435// Example: assert i64(2).hex() == '2'
436// Example: assert i64(-200).hex() == 'ffffffffffffff38'
437// Example: assert i64(2021).hex() == '7e5'
438pub fn (nn i64) hex() string {
439 return u64(nn).hex()
440}
441
442// hex returns the value of the `int_literal` as a hexadecimal `string`.
443// Note that the output is ***not*** zero padded.
444pub fn (nn int_literal) hex() string {
445 return u64(nn).hex()
446}
447
448// hex returns the value of the `voidptr` as a hexadecimal `string`.
449// Note that the output is ***not*** zero padded.
450pub fn (nn voidptr) str() string {
451 return '0x' + u64(nn).hex()
452}
453
454// hex returns the value of the `byteptr` as a hexadecimal `string`.
455// Note that the output is ***not*** zero padded.
456// pub fn (nn byteptr) str() string {
457pub fn (nn byteptr) str() string {
458 return '0x' + u64(nn).hex()
459}
460
461pub fn (nn charptr) str() string {
462 return '0x' + u64(nn).hex()
463}
464
465pub fn (nn u8) hex_full() string {
466 return u64_to_hex(u64(nn), 2)
467}
468
469pub fn (nn i8) hex_full() string {
470 return u64_to_hex(u64(nn), 2)
471}
472
473pub fn (nn u16) hex_full() string {
474 return u64_to_hex(u64(nn), 4)
475}
476
477pub fn (nn i16) hex_full() string {
478 return u64_to_hex(u64(nn), 4)
479}
480
481pub fn (nn u32) hex_full() string {
482 return u64_to_hex(u64(nn), 8)
483}
484
485pub fn (nn i64) hex_full() string {
486 return u64_to_hex(u64(nn), 16)
487}
488
489pub fn (nn voidptr) hex_full() string {
490 return u64_to_hex(u64(nn), 16)
491}
492
493pub fn (nn int_literal) hex_full() string {
494 return u64_to_hex(u64(nn), 16)
495}
496
497// hex_full returns the value of the `u64` as a *full* 16-digit hexadecimal `string`.
498// Example: assert u64(2).hex_full() == '0000000000000002'
499// Example: assert u64(255).hex_full() == '00000000000000ff'
500pub fn (nn u64) hex_full() string {
501 return u64_to_hex(nn, 16)
502}
503
504// str returns the contents of `byte` as a zero terminated `string`.
505// See also: [`byte.ascii_str`](#byte.ascii_str)
506// Example: assert u8(111).str() == '111'
507pub fn (b u8) str() string {
508 return int(b).str_l(4)
509}
510
511// ascii_str returns the contents of `byte` as a zero terminated ASCII `string` character.
512// Example: assert u8(97).ascii_str() == 'a'
513pub fn (b u8) ascii_str() string {
514 mut str := string{
515 str: unsafe { malloc_noscan(2) }
516 len: 1
517 }
518 unsafe {
519 str.str[0] = b
520 str.str[1] = 0
521 }
522 return str
523}
524
525// str_escaped returns the contents of `byte` as an escaped `string`.
526// Example: assert u8(0).str_escaped() == r'`\0`'
527@[manualfree]
528pub fn (b u8) str_escaped() string {
529 str := match b {
530 0 {
531 r'`\0`'
532 }
533 7 {
534 r'`\a`'
535 }
536 8 {
537 r'`\b`'
538 }
539 9 {
540 r'`\t`'
541 }
542 10 {
543 r'`\n`'
544 }
545 11 {
546 r'`\v`'
547 }
548 12 {
549 r'`\f`'
550 }
551 13 {
552 r'`\r`'
553 }
554 27 {
555 r'`\e`'
556 }
557 32...126 {
558 b.ascii_str()
559 }
560 else {
561 xx := b.hex()
562 yy := '0x' + xx
563 unsafe { xx.free() }
564 yy
565 }
566 }
567
568 return str
569}
570
571// is_capital returns `true`, if the byte is a Latin capital letter.
572// Example: assert u8(`H`).is_capital() == true
573// Example: assert u8(`h`).is_capital() == false
574@[inline]
575pub fn (c u8) is_capital() bool {
576 return c >= `A` && c <= `Z`
577}
578
579// bytestr produces a string from *all* the bytes in the array.
580// Note: the returned string will have .len equal to the array.len,
581// even when some of the array bytes were `0`.
582// If you want to get a V string, that contains only the bytes till
583// the first `0` byte, use `tos_clone(&u8(array.data))` instead.
584pub fn (b []u8) bytestr() string {
585 unsafe {
586 buf := malloc_noscan(b.len + 1)
587 vmemcpy(buf, b.data, b.len)
588 buf[b.len] = 0
589 return tos(buf, b.len)
590 }
591}
592
593// byterune attempts to decode a sequence of bytes, from utf8 to utf32.
594// It return the result as a rune.
595// It will produce an error, if there are more than four bytes in the array.
596pub fn (b []u8) byterune() !rune {
597 r := b.utf8_to_utf32()!
598 return rune(r)
599}
600
601// repeat returns a new string with `count` number of copies of the byte it was called on.
602pub fn (b u8) repeat(count int) string {
603 if count <= 0 {
604 return ''
605 } else if count == 1 {
606 return b.ascii_str()
607 }
608 mut bytes := unsafe { malloc_noscan(count + 1) }
609 unsafe {
610 vmemset(bytes, b, count)
611 bytes[count] = 0
612 }
613 return unsafe { bytes.vstring_with_len(count) }
614}
615
616// for atomic ints, internal
617fn _Atomic__int_str(x int) string {
618 return x.str()
619}
620
621// int_min returns the smallest `int` of input `a` and `b`.
622// Example: assert int_min(2,3) == 2
623@[inline]
624pub fn int_min(a int, b int) int {
625 return if a < b { a } else { b }
626}
627
628// int_max returns the largest `int` of input `a` and `b`.
629// Example: assert int_max(2,3) == 3
630@[inline]
631pub fn int_max(a int, b int) int {
632 return if a > b { a } else { b }
633}
634