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