| 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. |
| 4 | module builtin |
| 5 | |
| 6 | pub struct VContext { |
| 7 | allocator int |
| 8 | } |
| 9 | |
| 10 | pub type byte = u8 |
| 11 | |
| 12 | // ptr_str returns a string with the address of `ptr`. |
| 13 | pub 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. |
| 19 | pub fn (x isize) str() string { |
| 20 | return i64(x).str() |
| 21 | } |
| 22 | |
| 23 | // str returns the string equivalent of x. |
| 24 | pub 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. |
| 29 | pub fn (cptr &char) str() string { |
| 30 | return u64(cptr).hex() |
| 31 | } |
| 32 | |
| 33 | // digit pairs in reverse order |
| 34 | const digit_pairs = '00102030405060708090011121314151617181910212223242526272829203132333435363738393041424344454647484940515253545556575859506162636465666768696071727374757677787970818283848586878889809192939495969798999' |
| 35 | |
| 36 | pub const min_i8 = i8(-128) |
| 37 | pub const max_i8 = i8(127) |
| 38 | |
| 39 | pub const min_i16 = i16(-32768) |
| 40 | pub const max_i16 = i16(32767) |
| 41 | |
| 42 | pub const min_i32 = i32(-2147483648) |
| 43 | pub 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 |
| 48 | pub const min_i64 = i64(-9223372036854775807 - 1) |
| 49 | pub const max_i64 = i64(9223372036854775807) |
| 50 | |
| 51 | pub const min_int = $if new_int ? && x64 { int(min_i64) } $else { int(min_i32) } |
| 52 | pub const max_int = $if new_int ? && x64 { int(max_i64) } $else { int(max_i32) } |
| 53 | |
| 54 | pub const min_u8 = u8(0) |
| 55 | pub const max_u8 = u8(255) |
| 56 | |
| 57 | pub const min_u16 = u16(0) |
| 58 | pub const max_u16 = u16(65535) |
| 59 | |
| 60 | pub const min_u32 = u32(0) |
| 61 | pub const max_u32 = u32(4294967295) |
| 62 | |
| 63 | pub const min_u64 = u64(0) |
| 64 | pub 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] |
| 68 | fn (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' |
| 127 | pub 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' |
| 133 | pub 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' |
| 139 | pub fn (n u16) str() string { |
| 140 | return int(n).str_l(6) |
| 141 | } |
| 142 | |
| 143 | pub fn (n i32) str() string { |
| 144 | return int(n).str_l(11) |
| 145 | } |
| 146 | |
| 147 | pub 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' |
| 153 | pub 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] |
| 164 | pub 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] |
| 199 | pub 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] |
| 206 | pub fn (nn i64) str() string { |
| 207 | return impl_i64_to_string(nn) |
| 208 | } |
| 209 | |
| 210 | @[direct_array_access] |
| 211 | fn 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] |
| 259 | pub 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' |
| 294 | pub 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] |
| 303 | fn 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] |
| 318 | fn 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' |
| 340 | pub 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' |
| 352 | pub 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' |
| 359 | pub 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' |
| 368 | pub 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' |
| 379 | pub 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' |
| 390 | pub 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' |
| 398 | pub 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' |
| 409 | pub 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' |
| 418 | pub 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' |
| 426 | pub 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' |
| 438 | pub 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. |
| 444 | pub 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. |
| 450 | pub 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 { |
| 457 | pub fn (nn byteptr) str() string { |
| 458 | return '0x' + u64(nn).hex() |
| 459 | } |
| 460 | |
| 461 | pub fn (nn charptr) str() string { |
| 462 | return '0x' + u64(nn).hex() |
| 463 | } |
| 464 | |
| 465 | pub fn (nn u8) hex_full() string { |
| 466 | return u64_to_hex(u64(nn), 2) |
| 467 | } |
| 468 | |
| 469 | pub fn (nn i8) hex_full() string { |
| 470 | return u64_to_hex(u64(nn), 2) |
| 471 | } |
| 472 | |
| 473 | pub fn (nn u16) hex_full() string { |
| 474 | return u64_to_hex(u64(nn), 4) |
| 475 | } |
| 476 | |
| 477 | pub fn (nn i16) hex_full() string { |
| 478 | return u64_to_hex(u64(nn), 4) |
| 479 | } |
| 480 | |
| 481 | pub fn (nn u32) hex_full() string { |
| 482 | return u64_to_hex(u64(nn), 8) |
| 483 | } |
| 484 | |
| 485 | pub fn (nn i64) hex_full() string { |
| 486 | return u64_to_hex(u64(nn), 16) |
| 487 | } |
| 488 | |
| 489 | pub fn (nn voidptr) hex_full() string { |
| 490 | return u64_to_hex(u64(nn), 16) |
| 491 | } |
| 492 | |
| 493 | pub 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' |
| 500 | pub 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' |
| 507 | pub 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' |
| 513 | pub 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] |
| 528 | pub 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] |
| 575 | pub 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. |
| 584 | pub 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. |
| 596 | pub 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. |
| 602 | pub 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 |
| 617 | fn _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] |
| 624 | pub 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] |
| 631 | pub fn int_max(a int, b int) int { |
| 632 | return if a > b { a } else { b } |
| 633 | } |
| 634 | |