digitalmars.D.learn - D: Convert/parse uint integer to string. ( nogc)
- BoQsc (6/6) Nov 24 2023 I tried to look into https://dlang.org/phobos/std_conv.html
- Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= (21/28) Nov 24 2023 I guess there are third-party libraries doing this. One would use
- kdevel (30/48) Nov 30 2023 What happend to the indentation? Anyway
- Nick Treleaven (17/24) Nov 27 2023 You can use std.conv.toChars:
- Nick Treleaven (15/32) Nov 27 2023 Or, using std.experimental.allocator:
- Mark Davies (41/48) Nov 28 2023 I did it this way ...
- Dom DiSc (10/15) Nov 28 2023 For a 'long' 10 characters is likely to be not enough (long max
- kdevel (5/14) Nov 30 2023 `long.max` is 9223372036854775807, `long.min` is
- Julian Fondren (64/72) Nov 28 2023 You always print the full array of bytes this way. Output piped
- Siarhei Siamashka (20/27) Nov 30 2023 There are various tricks to do such conversion very fast. For
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?
Nov 24 2023
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); } ```
Nov 24 2023
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 ```
Nov 30 2023
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); } ```
Nov 27 2023
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); } ```
Nov 27 2023
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; } ```
Nov 28 2023
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.
Nov 28 2023
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:`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.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 [...]
Nov 30 2023
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 ``` 0000000 1 2 3 4 5 377 377 377 377 377 \n - 1 2 3 4 0000020 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...FFFF, 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.
Nov 28 2023
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.
Nov 30 2023