Re: D: Convert/parse uint integer to string. (@nogc)

2023-11-30 Thread Siarhei Siamashka via Digitalmars-d-learn

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)

2023-11-30 Thread kdevel via Digitalmars-d-learn

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)

2023-11-30 Thread kdevel via Digitalmars-d-learn
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)

2023-11-28 Thread Julian Fondren via Digitalmars-d-learn

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)

2023-11-28 Thread Dom DiSc via Digitalmars-d-learn

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)

2023-11-28 Thread Mark Davies via Digitalmars-d-learn

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)

2023-11-27 Thread Nick Treleaven via Digitalmars-d-learn

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)

2023-11-27 Thread Nick Treleaven via Digitalmars-d-learn

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)

2023-11-24 Thread Ferhat Kurtulmuş via Digitalmars-d-learn

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)

2023-11-24 Thread BoQsc via Digitalmars-d-learn

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?