summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-06-05 20:23:39 +0200
committerEugen Wissner <belka@caraus.de>2018-06-07 07:23:39 +0200
commit7561b964d32ab9cfbd1543e78dd7292abb7b3d23 (patch)
tree897e532a6b5fdc1b97a735805c2cb078b5222763
parentc663703221779a4d271393030cce3735f6ac1441 (diff)
downloadtanya-7561b964d32ab9cfbd1543e78dd7292abb7b3d23.tar.gz
Make intToString -> readString more generic
Make readString work with any char range and unsigned integral type.
-rw-r--r--source/tanya/conv.d100
-rw-r--r--source/tanya/net/uri.d3
2 files changed, 89 insertions, 14 deletions
diff --git a/source/tanya/conv.d b/source/tanya/conv.d
index 2cd40b3..aa6f847 100644
--- a/source/tanya/conv.d
+++ b/source/tanya/conv.d
@@ -20,6 +20,8 @@ import tanya.memory;
import tanya.memory.op;
import tanya.meta.trait;
import tanya.meta.transform;
+import tanya.range.array;
+import tanya.range.primitive;
version (unittest)
{
@@ -264,28 +266,100 @@ final class ConvException : Exception
}
}
-package bool stringToInt(R)(R range, ref ushort n)
+package bool readString(T, R)(ref R range, out T n)
+if (isForwardRange!R && isSomeChar!(ElementType!R)
+ && isIntegral!T && isUnsigned!T)
{
- import tanya.encoding.ascii;
- import tanya.range.array;
+ import tanya.encoding.ascii : isDigit;
- size_t i = 1;
- uint lPort;
-
- for (; !range.empty && range.front.isDigit() && i <= 6; ++i, range.popFront())
+ enum T boundary = T.max / 10;
+ if (range.empty)
{
- lPort = lPort * 10 + (range.front - '0');
+ return false;
}
- if (i != 1 && (range.empty || range.front == '/'))
+
+ while (n <= boundary)
{
- if (lPort > ushort.max)
+ if (!range.front.isDigit)
{
return false;
}
- n = cast(ushort) lPort;
- return true;
+ n = cast(T) (n * 10 + (range.front - '0'));
+ range.popFront();
+
+ if (range.empty)
+ {
+ return true;
+ }
+ }
+ if (range.length > 1)
+ {
+ return false;
}
- return false;
+
+ int digit = range.front - '0';
+ if (n > cast(T) ((T.max - digit) / 10))
+ {
+ return false;
+ }
+ n = cast(T) (n * 10 + digit);
+
+ return true;
+}
+
+// reads ubyte.max
+@nogc nothrow pure @safe unittest
+{
+ ubyte n;
+ string number = "255";
+ assert(readString(number, n));
+ assert(n == 255);
+ assert(number.empty);
+}
+
+// detects integer overflow
+@nogc nothrow pure @safe unittest
+{
+ ubyte n;
+ string number = "500";
+ assert(!readString(number, n));
+ assert(number.front == '0');
+ assert(number.length == 1);
+}
+
+// stops on a non-digit
+@nogc nothrow pure @safe unittest
+{
+ ubyte n;
+ string number = "10-";
+ assert(!readString(number, n));
+ assert(number.front == '-');
+}
+
+// returns false if the number string is empty
+@nogc nothrow pure @safe unittest
+{
+ ubyte n;
+ string number = "";
+ assert(!readString(number, n));
+ assert(number.empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ ubyte n;
+ string number = "29";
+ assert(readString(number, n));
+ assert(n == 29);
+ assert(number.empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ ubyte n;
+ string number = "25467";
+ assert(!readString(number, n));
+ assert(number.front == '6');
}
/**
diff --git a/source/tanya/net/uri.d b/source/tanya/net/uri.d
index 8b05f8e..021b4b4 100644
--- a/source/tanya/net/uri.d
+++ b/source/tanya/net/uri.d
@@ -305,7 +305,8 @@ struct URL
*/
private bool parsePort(const(char)[] port) @nogc nothrow pure @safe
{
- return stringToInt(port[1 .. $], this.port);
+ auto portNumber = port[1 .. $];
+ return readString(portNumber, this.port) || portNumber[0] == '/';
}
}