Thread overview
toChars buffer access?
Jun 09, 2022
Salih Dincer
Jun 09, 2022
bauss
Jun 10, 2022
Salih Dincer
Jun 10, 2022
Salih Dincer
Jun 10, 2022
Salih Dincer
August 23, 2020
I was about to reach for core.internal.string.signedToTempString [1] to convert a number into a temp string yet again. And I thought, maybe there's something in Phobos by now.

And lo and behold! There's std.conv.toChars [2]

But... it just gives me a range of char, and not an actual string. So my intended purpose (to use it as a string key for an associative array) means I have to copy it to a local buffer anyway.

No matter, right? It probably just stores the number and gives me access to each character as it parses. Oh wait, no. It actually stores it as a char[20], but doesn't give me access.

Which leaves me with the only option of doing:

auto s = someNumber.toChars;
char[20] buf;
import std.algorithm : copy;
copy(s.save, buf[0 .. s.length]);

auto v = aa[buf[0 .. s.length]];

But my goodness, it would just be so easy if it gave access to the buffer:

auto s = someNumber.toChars;
auto v = aa[s.data]; // @system access to buffer, unsafe!

And this is discounting the fact that I not only am copying the buffer *again*, but doing it one character at a time.

So would it be a problem to allow this accessor, even if it's @system? Or should I just keep importing core.internal?

-Steve

[1] https://github.com/dlang/druntime/blob/9f0f6e49fb379841c7934b6049f87dab0adfe53c/src/core/internal/string.d#L113

[2] https://dlang.org/phobos/std_conv.html#toChars
June 09, 2022

On Sunday, 23 August 2020 at 19:18:51 UTC, Steven Schveighoffer wrote:

>

I was about to reach for core.internal.string.signedToTempString [1] to convert a number into a temp string yet again. And I thought, maybe there's something in Phobos by now.

And lo and behold! There's std.conv.toChars [2]

But... it just gives me a range of char, and not an actual string. So my intended purpose (to use it as a string key for an associative array) means I have to copy it to a local buffer anyway.

No matter, right? It probably just stores the number and gives me access to each character as it parses. Oh wait, no. It actually stores it as a char[20], but doesn't give me access.

Which leaves me with the only option of doing:

auto s = someNumber.toChars;
char[20] buf;
import std.algorithm : copy;
copy(s.save, buf[0 .. s.length]);

auto v = aa[buf[0 .. s.length]];

But my goodness, it would just be so easy if it gave access to the buffer:

auto s = someNumber.toChars;
auto v = aa[s.data]; // @system access to buffer, unsafe!

And this is discounting the fact that I not only am copying the buffer again, but doing it one character at a time.

So would it be a problem to allow this accessor, even if it's @system? Or should I just keep importing core.internal?

-Steve

[1] https://github.com/dlang/druntime/blob/9f0f6e49fb379841c7934b6049f87dab0adfe53c/src/core/internal/string.d#L113

[2] https://dlang.org/phobos/std_conv.html#toChars

I also faced this problem. Anyone have a solution?

SDB@79

June 09, 2022

On Thursday, 9 June 2022 at 14:44:55 UTC, Salih Dincer wrote:

>

On Sunday, 23 August 2020 at 19:18:51 UTC, Steven Schveighoffer wrote:

>

I was about to reach for core.internal.string.signedToTempString [1] to convert a number into a temp string yet again. And I thought, maybe there's something in Phobos by now.

And lo and behold! There's std.conv.toChars [2]

But... it just gives me a range of char, and not an actual string. So my intended purpose (to use it as a string key for an associative array) means I have to copy it to a local buffer anyway.

No matter, right? It probably just stores the number and gives me access to each character as it parses. Oh wait, no. It actually stores it as a char[20], but doesn't give me access.

Which leaves me with the only option of doing:

auto s = someNumber.toChars;
char[20] buf;
import std.algorithm : copy;
copy(s.save, buf[0 .. s.length]);

auto v = aa[buf[0 .. s.length]];

But my goodness, it would just be so easy if it gave access to the buffer:

auto s = someNumber.toChars;
auto v = aa[s.data]; // @system access to buffer, unsafe!

And this is discounting the fact that I not only am copying the buffer again, but doing it one character at a time.

So would it be a problem to allow this accessor, even if it's @system? Or should I just keep importing core.internal?

-Steve

[1] https://github.com/dlang/druntime/blob/9f0f6e49fb379841c7934b6049f87dab0adfe53c/src/core/internal/string.d#L113

[2] https://dlang.org/phobos/std_conv.html#toChars

I also faced this problem. Anyone have a solution?

SDB@79

.array on the result from .toChars perhaps?

Or is there a specific reason that cannot be done?

someNumber.toChars.array
June 09, 2022

On 6/9/22 4:31 PM, bauss wrote:

>

.array on the result from .toChars perhaps?

Or is there a specific reason that cannot be done?

someNumber.toChars.array

This allocates. For a temporary array, this is wasteful (it will be thrown away immediately).

My original example is to look up a key in an AA (not to store one).

-Steve

June 10, 2022

On Thursday, 9 June 2022 at 21:16:48 UTC, Steven Schveighoffer wrote:

>

My original example is to look up a key in an AA (not to store one).

I have a simple code that works perfectly as well. But I'm having problems to convert except string.

struct HexStack
{
  private
  {
    string[ubyte] convert;
    ubyte index;
    const ubyte first;
  }

  this(ubyte start)
  {
   this.index = start;
   this.first = start;
  }

  bool empty()
  {
    return index == first;
  }

  @property top()
  {
    return this.convert[first];
  }

  @property pop()
  {
    if(!empty) --this.index;
    return this.convert[this.index];
  }

  @property push(uint data)
  {
    import std.conv;
    this.convert[index] = toChars!(16, char,
                           LetterCase.upper)
                           (data).to!string;
    if(index < ubyte.max) this.index++;
    else this.index = ubyte.max;
  }
}

unittest
{
  HexStack foo = 'a';     // x'61'
           foo.push('A'); // x'41'
  assert(foo.top == "41");

  foo.push('B');
  foo.push('C');

  assert(foo.pop == "43");
  assert(foo.pop == "42");

  assert(foo.pop == "41");
  assert(foo.empty);

  assert(foo.pop == "41");
  assert(foo.pop == foo.top);

  HexStack bar = ubyte.max - 1;
           bar.push('A'); // x'41'
  assert(bar.top == "41");

  bar.push('B');
  bar.push('C');

  assert(bar.pop == "41");
  assert(bar.empty);

  assert(bar.pop == "41");
  assert(bar.pop == bar.top);
}

So hexstring is ok. When switching to other types, it converts each letter independently of each other and gives the following error:

>

ChArray(Reserved, T = char)
neme1234567
den
eme
9,8,7,6,5,4,3,2,1,e,m,e,n,e,d,
d,e,n,e,m,e,1,2,3,4,5,6,7,8,9,
std.conv.ConvException@/usr/src/dmd/linux/bin64/../../src/phobos/std/conv.d(1877): Unexpected '0' when converting from type Result to type char


??:? pure @safe char std.conv.toImpl!(char, std.conv.toChars!(16u, char, 0, uint).toChars(uint).Result).toImpl(std.conv.toChars!(16u, char, 0, uint).toChars(uint).Result) [0x55a583a8c4de]
??:? pure @safe char std.conv.to!(char).to!(std.conv.toChars!(16u, char, 0, uint).toChars(uint).Result).to(std.conv.toChars!(16u, char, 0, uint).toChars(uint).Result) [0x55a583a8c201]
??:? pure char (immutable(char)[], char).ChArray.toChar!(10u).toChar() [0x55a583a8bf01]
??:? _Dmain [0x55a583a8018d]
Process finished with exit code 1.

I also get this error when I use char[]:

>

ChArray.d(180): Error: only one index allowed to index char

Test Code:

  uint A = 65;
  auto result = A.toChars!16; //hex '41'
  auto myCodePage = HexStack('a');
       myCodePage.push(A);

  assert(myCodePage.top == result.to!string);
  auto test = result.to!char[];

The only solution is to use .array:

assert(result.array == ['4', '1']);

But I don't like this!

SDB@79

June 09, 2022

On 6/9/22 8:18 PM, Salih Dincer wrote:

>

  auto test = result.to!char[];

I'm not sure if I got all your code, but just to note, the operator precedence here means it's (result.to!char)[]

>

The only solution is to use .array:

assert(result.array == ['4', '1']);

Well, 2 things. First, you can compare a char[] to a string, so result.array == "41" should be fine.

Second, you can't use == to compare ranges, you need to use std.algorithm.equal:

import std.algorithm : equal;
assert(equal(result, "41"));

(and yes, this should work for different character types, even though a string is element type dchar).

Not sure if this helps, I feel like there was some code missing from your example.

-Steve

June 10, 2022

On Friday, 10 June 2022 at 01:49:25 UTC, Steven Schveighoffer wrote:

>

On 6/9/22 8:18 PM, Salih Dincer wrote:

>

  auto test = result.to!char[];

I'm not sure if I got all your code, but just to note, the operator precedence here means it's (result.to!char)[]
[...]

It's okay, the subject is clearer for me now.

But I wish I could change each character to hexString without dealing with conversions; I see below is the type of integer(uint) that toChars wants:

void main() {
  import std.algorithm, std.range;
  import std.conv, std.stdio;

  string str = "Hello World!";

  /* I'd like it to be as simple as a
   * comment line, but it's not working.
   */
  //str.toChars!(16, string).writeln;/*
  str.each!(c =>
    c.to!uint
     .toChars!(16, char, LetterCase.upper)
     .write("-")
  );

  writeln;

  str.each!((i, uint c) {
    c.to!string(16)
     .writeln(": ", i);
    }
  );//*/
} /* Print Out:
48-65-6C-6C-6F-20-57-6F-72-6C-64-21-
48: 0
65: 1
6C: 2
6C: 3
6F: 4
20: 5
57: 6
6F: 7
72: 8
6C: 9
64: 10
21: 11

//*/

SDB@79

June 10, 2022

On 6/10/22 1:07 AM, Salih Dincer wrote:

>

  /* I'd like it to be as simple as a
   * comment line, but it's not working.
   /
  //str.toChars!(16, string).writeln;/

  str.each!(c =>
    c.to!uint
     .toChars!(16, char, LetterCase.upper)
     .write("-")
  );

Ugh, it's not as easy as I thought but...

  import std.utf;
  // option 1 (if you want a range that's usable elsewhere)
  str.map!(c => uint(c).toChars!(16, char, LetterCase.upper))
      .joiner("-".byCodeUnit) // byCodeUnit needed because of autodecoding
      .writeln;

  // option 2 (if the point is just to print)
  writefln("%-(%02X-%)", str);

-Steve

June 10, 2022

On Friday, 10 June 2022 at 14:49:51 UTC, Steven Schveighoffer wrote:

>

// option 2 (if the point is just to print)
writefln("%-(%02X-%)", str);

Delicious!

  auto str = "Hello World!";

  import std.format, std.range : split;
  auto strArr = str.format!"%-(%02X %)".split;

  import std.stdio;
  strArr.writefln!"%-(%s-%)";

SDB@79

June 10, 2022

On 6/10/22 5:05 PM, Salih Dincer wrote:

>

On Friday, 10 June 2022 at 14:49:51 UTC, Steven Schveighoffer wrote:

>

  // option 2 (if the point is just to print)
  writefln("%-(%02X-%)", str);

Delicious!

   auto str = "Hello World!";

   import std.format, std.range : split;
   auto strArr = str.format!"%-(%02X %)".split;

This allocates ;)

-Steve