Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions std/conv.d
Original file line number Diff line number Diff line change
Expand Up @@ -6031,6 +6031,10 @@ Params:

Returns:
a `string`, a `wstring` or a `dstring`, according to the type of hexData.

References:
Prefer using $(LREF hexData) instead, especially if the `hexData` string is long
because it does not use templates.
*/
template hexString(string hexData)
if (hexData.isHexLiteral)
Expand Down Expand Up @@ -6136,6 +6140,88 @@ private auto hexStrLiteral(String)(scope String hexData)
assert(hexString!"ab cd" == hexString!"ABCD");
}

/************************************************
* Convert string of `[0-9A-Fa-f]` characters to an array of ubytes.
*
* Other characters in the string are considered separators.
* Adjacent pairs of characters form the nibbles of the ubyte.
* Non-pairing characters form the low nibble of the ubyte.
* The returned array does not have a terminating zero appended.
* The GC is used because `hexData()` is intended to be used
* at compile time to, for example, initialize manifest constants
* and statically initialize global variables.
* Params:
* s = string of data to convert
* Returns:
* unique array of ubytes allocated on the GC heap
* References:
* $(LREF hexString)
*/
ubyte[] hexData(const(char)[] s) pure nothrow @safe
{
ubyte[] result;
result.length = (s.length + 1) / 2;
size_t i;

void append(ubyte u)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems a bit much, it's called from three places

{
result[i++] = u;
}

ubyte u;
uint digits;
foreach (char c; s)
{
if ('0' <= c && c <= '9')
c -= '0';
else if ('a' <= c && c <= 'f')
c -= 'a' - 10;
else if ('A' <= c && c <= 'F')
c -= 'A' - 10;
else
{
if (digits)
append(u);
u = 0;
digits = 0;
continue;
}


Comment on lines +6189 to +6190
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One line space will suffice.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use two lines to separate one function from the next unrelated one.

if (++digits == 2)
{
append(cast(ubyte)((u << 4) + c));
digits = 0;
}
else
u = c;
}
if (digits)
append(u);

return result[0 .. i];
}

///
@safe nothrow unittest
{
static g1 = hexData("af,fa");
assert(g1 == [0xAF, 0xFA]);

enum a1 = hexData("AAbb");
assert(a1 == [0xAA, 0xBB]);
enum a2 = hexData("");
assert(a2 == []);
enum a3 = hexData(" \t\r\n");
assert(a3 == []);
enum a4 = hexData("f");
assert(a4 == [0xF]);
enum a5 = hexData(" f,");
assert(a5 == [0xF]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why support odd number of digits? This is probably going to almost always be an error or typo.

enum a6 = hexData("0BF ");
assert(a6 == [0x0B, 0x0F]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should probably be some tests to test the behavior with invalid inputs. Speaking of which, they seem to be ignored? Combined with the decision to support one-digit characters, this seems like a bad idea, e.g. in "54 32 1O" the last character is the letter O.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

G-Z should be an error, that's bug prone.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As currently specified there are no invalid inputs to this function.

}


/**
* Convert integer to a range of characters.
Expand Down