www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - D: Convert/parse uint integer to string. ( nogc)

reply BoQsc <vaidas.boqsc gmail.com> writes:
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
next sibling parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
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
parent kdevel <kdevel vogtner.de> writes:
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
prev sibling next sibling parent reply Nick Treleaven <nick geany.org> writes:
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
parent Nick Treleaven <nick geany.org> writes:
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
prev sibling next sibling parent reply Mark Davies <markd trap10.net> writes:
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
next sibling parent reply Dom DiSc <dominikus scherkl.de> writes:
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
parent kdevel <kdevel vogtner.de> writes:
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.
Nov 30 2023
prev sibling parent Julian Fondren <julian.fondren gmail.com> writes:
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
prev sibling parent Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
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