Re: D: Convert/parse uint integer to string. (@nogc)
On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: I tried to look into https://dlang.org/phobos/std_conv.html Most of the functions inside `std.conv` seem to be dependant on [Garbage Collection](https://dlang.org/spec/garbage.html). And I couldn't find a straightforward way to produce a `string` value out of `uint` value. How to convert or parse `uint` value to a `string` in `@nogc` way? There are various tricks to do such conversion very fast. For example, the following article is essential for implementing it: https://lemire.me/blog/2021/06/03/computing-the-number-of-digits-of-an-integer-even-faster/ Rather than doing conversion one digit at a time, it's much more efficient to process multiple digits per loop iteration. Consider an illustrative pseudocode like this: ```D while (x >= 100) { write(twodigits_lookup_table[x % 100]); // we can handle two digits at once x /= 100; } ``` I have a @nogc compatible DUB module, which implements fast formatted output to stdout: https://github.com/ssvb/speedy-stdio (cutting some corners allows to squeeze some extra performance out of it). The same code can be adapted to do formatted output to a memory buffer as well.
Re: D: Convert/parse uint integer to string. (@nogc)
On Tuesday, 28 November 2023 at 09:43:47 UTC, Dom DiSc wrote: On Tuesday, 28 November 2023 at 08:51:21 UTC, Mark Davies wrote: On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: ``` import std.stdio; char[10] longToString(long n) @nogc ``` For a 'long' 10 characters is likely to be not enough (long max is 9223372036854775808 [...] `long.max` is 9223372036854775807, `long.min` is -9223372036854775808. Besides from the too short buffer the `longToString` function neither converts 0 (zero) nor `long.min` correctly.
Re: D: Convert/parse uint integer to string. (@nogc)
On Friday, 24 November 2023 at 13:05:30 UTC, Ferhat Kurtulmuş wrote: [...] ``` import core.stdc.stdio : sprintf; import core.stdc.math : log10; import std.exception : assumeUnique; import std.stdio : writeln; size_t nod(int num){ return cast(size_t)((num==0)?1:log10(num)+1); } void main() { int myint = 23; char[80] str; sprintf(str.ptr, "%d", myint); string _dstring = str[0..nod(myint)].assumeUnique; writeln(_dstring); } ``` What happend to the indentation? Anyway ``` $ ./inttostr -1 $ ./inttostr -2147483648 ``` I like `snprintf`: ```d import core.stdc.stdio : snprintf; import std.exception : assumeUnique, enforce; import std.stdio; import std.conv; import core.stdc.locale; import std.format; void main (string [] args) { setlocale (LC_NUMERIC, ""); auto myint = args[1].to!long; char[27] str; auto n = snprintf(str.ptr, str.sizeof, "%'ld", myint); enforce (n < str.sizeof, "buffer too small"); string _dstring = str[0..n].assumeUnique; writeln(_dstring); } ``` ``` $ ./l2s -9223372036854775808 -9.223.372.036.854.775.808 ```
Re: D: Convert/parse uint integer to string. (@nogc)
On Tuesday, 28 November 2023 at 08:51:21 UTC, Mark Davies wrote: I did it this way ... You always print the full array of bytes this way. Output piped to `od -c` is ``` 000 1 2 3 4 5 377 377 377 377 377 \n - 1 2 3 4 020 5 377 377 377 377 \n ``` Those 377s are `char.init`, 0xFF. On Tuesday, 28 November 2023 at 09:43:47 UTC, Dom DiSc wrote: For a 'long' 10 characters is likely to be not enough (long max is 9223372036854775808 which has 19 chars, and you should reserve additional one for the sign and one for the terminating null), so I would at least recommend using char[21]. Signed max is all bits but the sign bit set, so 7FFF..., so signed max is always an odd number. d can confirm: ``` $ rdmd --eval 'writeln(long.max)' 9223372036854775807 $ rdmd --eval 'writeln(2+to!string(long.max).length)' 21 ``` There's no terminating NUL here, which might be an oversight. with char[10] your function becomes a big hole in your security, as it can easily be misused to write 10 bytes of freely selectable garbage behind your allocated memory. This is D though, so without separately disabling bounds checks, there's an error: ``` core.exception.ArrayIndexError@d1.d(22): index [18] is out of bounds for array of length 10 ``` or with -betterC: ``` d1: d1.d:21: Assertion `array index out of bounds' failed. Aborted ``` Here's a minimal edit to fix the `char.init` output: ```d char[] longToString(long n) @nogc { static char[21] x; size_t length; ulong power; x[0] = '-'*(n<0); long t = (n<0)*-n + (n>0)*n ; while (n != 0) { power++; n /= 10; } length = power; power -= (x[0] != '-'); while (t > 0) { x[power] = (t % 10) + '0'; power--; t /= 10; } return x[0 .. length]; } ``` As you can see, slices from this longToString are good until the next call to it. The other C-like way to manage memory is to pass in the buffer to use, which in D can be a slice of a static array on the caller's stack. You'll probably have a much better time with manual memory management if you use custom allocators.
Re: D: Convert/parse uint integer to string. (@nogc)
On Tuesday, 28 November 2023 at 08:51:21 UTC, Mark Davies wrote: On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: ``` import std.stdio; char[10] longToString(long n) @nogc ``` For a 'long' 10 characters is likely to be not enough (long max is 9223372036854775808 which has 19 chars, and you should reserve additional one for the sign and one for the terminating null), so I would at least recommend using char[21]. with char[10] your function becomes a big hole in your security, as it can easily be misused to write 10 bytes of freely selectable garbage behind your allocated memory. But as you want to avoid the gc, security might not be a goal for you, so continue living in the 1970's.
Re: D: Convert/parse uint integer to string. (@nogc)
On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: I tried to look into https://dlang.org/phobos/std_conv.html Most of the functions inside `std.conv` seem to be dependant on [Garbage Collection](https://dlang.org/spec/garbage.html). And I couldn't find a straightforward way to produce a `string` value out of `uint` value. How to convert or parse `uint` value to a `string` in `@nogc` way? I did it this way ... ``` import std.stdio; char[10] longToString(long n) @nogc { char[10] x; ulong power; x[0] = '-'*(n<0); long t = (n<0)*-n + (n>0)*n ; while (n != 0) { power++; n /= 10; } power -= (x[0] != '-'); while (t > 0) { x[power] = (t % 10) + '0'; power--; t /= 10; } return x; } int main() { long p = 12345; char[10] r = longToString(p); writeln(r); p = -12345; r = longToString(p); writeln(r); return 0; } ```
Re: D: Convert/parse uint integer to string. (@nogc)
On Monday, 27 November 2023 at 12:34:30 UTC, Nick Treleaven wrote: On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: You can use std.conv.toChars: ```d void main() @nogc { int n = 515; import std.conv; char[10] s = 0; auto r = n.toChars(); assert(r.length < s.length); size_t i; foreach (c; r) s[i++] = c; import core.stdc.stdio; puts(s.ptr); } ``` Or, using std.experimental.allocator: ```d void main() @nogc { int n = 515; import std.conv; import std.experimental.allocator; import std.experimental.allocator.mallocator; alias a = Mallocator.instance; auto s = a.makeArray(n.toChars); assert(s == "515"); a.dispose(s); } ```
Re: D: Convert/parse uint integer to string. (@nogc)
On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: I tried to look into https://dlang.org/phobos/std_conv.html Most of the functions inside `std.conv` seem to be dependant on [Garbage Collection](https://dlang.org/spec/garbage.html). And I couldn't find a straightforward way to produce a `string` value out of `uint` value. How to convert or parse `uint` value to a `string` in `@nogc` way? You can use std.conv.toChars: ```d void main() @nogc { int n = 515; import std.conv; char[10] s = 0; auto r = n.toChars(); assert(r.length < s.length); size_t i; foreach (c; r) s[i++] = c; import core.stdc.stdio; puts(s.ptr); } ```
Re: D: Convert/parse uint integer to string. (@nogc)
On Friday, 24 November 2023 at 09:35:00 UTC, BoQsc wrote: I tried to look into https://dlang.org/phobos/std_conv.html Most of the functions inside `std.conv` seem to be dependant on [Garbage Collection](https://dlang.org/spec/garbage.html). And I couldn't find a straightforward way to produce a `string` value out of `uint` value. How to convert or parse `uint` value to a `string` in `@nogc` way? I guess there are third-party libraries doing this. One would use stdc functions such as sprintf. Probably, there should be a more d-ish way. ``` import core.stdc.stdio : sprintf; import core.stdc.math : log10; import std.exception : assumeUnique; import std.stdio : writeln; size_t nod(int num){ return cast(size_t)((num==0)?1:log10(num)+1); } void main() { int myint = 23; char[80] str; sprintf(str.ptr, "%d", myint); string _dstring = str[0..nod(myint)].assumeUnique; writeln(_dstring); } ```
D: Convert/parse uint integer to string. (@nogc)
I tried to look into https://dlang.org/phobos/std_conv.html Most of the functions inside `std.conv` seem to be dependant on [Garbage Collection](https://dlang.org/spec/garbage.html). And I couldn't find a straightforward way to produce a `string` value out of `uint` value. How to convert or parse `uint` value to a `string` in `@nogc` way?