summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x64/linux/memory/cmp.S7
-rw-r--r--arch/x64/linux/syscall.S12
-rw-r--r--source/tanya/algorithm/mutation.d60
-rw-r--r--source/tanya/container/string.d2
-rw-r--r--source/tanya/conv.d13
-rw-r--r--source/tanya/math/mp.d8
-rw-r--r--source/tanya/memory/package.d2
-rw-r--r--source/tanya/net/ip.d374
-rw-r--r--source/tanya/range/primitive.d19
9 files changed, 473 insertions, 24 deletions
diff --git a/arch/x64/linux/memory/cmp.S b/arch/x64/linux/memory/cmp.S
index 64d3ca6..bd9f02e 100644
--- a/arch/x64/linux/memory/cmp.S
+++ b/arch/x64/linux/memory/cmp.S
@@ -8,10 +8,9 @@
* rdx - r2 length.
* rcx - r2 data.
*/
- .globl _D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi
- .type _D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi, @function
-
-_D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi:
+ .globl _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi
+ .type _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi, @function
+_D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi:
// Compare the lengths
cmp %rdx, %rdi
jl less
diff --git a/arch/x64/linux/syscall.S b/arch/x64/linux/syscall.S
index 7c00036..3d7f0b8 100644
--- a/arch/x64/linux/syscall.S
+++ b/arch/x64/linux/syscall.S
@@ -23,10 +23,10 @@ syscall1:
// 2 parameters.
- .globl _D5tanya3sys5linux7syscall7syscallFNbNilllZl
- .type _D5tanya3sys5linux7syscall7syscallFNbNilllZl, @function
+ .globl _D5tanya3sys5linux7syscallQiFNbNilllZl
+ .type _D5tanya3sys5linux7syscallQiFNbNilllZl, @function
-_D5tanya3sys5linux7syscall7syscallFNbNilllZl:
+_D5tanya3sys5linux7syscallQiFNbNilllZl:
movq %rdx, %rax
syscall
@@ -35,10 +35,10 @@ _D5tanya3sys5linux7syscall7syscallFNbNilllZl:
// 6 parameters.
- .globl _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl
- .type _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl, @function
+ .globl _D5tanya3sys5linux7syscallQiFNbNilllllllZl
+ .type _D5tanya3sys5linux7syscallQiFNbNilllllllZl, @function
-_D5tanya3sys5linux7syscall7syscallFNbNilllllllZl:
+_D5tanya3sys5linux7syscallQiFNbNilllllllZl:
pushq %rbp
movq %rsp, %rbp
diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d
index df741cc..bf39b22 100644
--- a/source/tanya/algorithm/mutation.d
+++ b/source/tanya/algorithm/mutation.d
@@ -14,8 +14,9 @@
*/
module tanya.algorithm.mutation;
-import tanya.memory.op;
+static import tanya.memory.op;
import tanya.meta.trait;
+import tanya.range;
private void deinitialize(bool zero, T)(ref T value)
{
@@ -39,11 +40,12 @@ private void deinitialize(bool zero, T)(ref T value)
}
static if (zero)
{
- fill!0((cast(void*) &value)[0 .. size]);
+ tanya.memory.op.fill!0((cast(void*) &value)[0 .. size]);
}
else
{
- copy(typeid(T).initializer()[0 .. size], (&value)[0 .. 1]);
+ tanya.memory.op.copy(typeid(T).initializer()[0 .. size],
+ (&value)[0 .. 1]);
}
}
}
@@ -81,7 +83,7 @@ do
{
static if (is(T == struct) || isStaticArray!T)
{
- copy((&source)[0 .. 1], (&target)[0 .. 1]);
+ tanya.memory.op.copy((&source)[0 .. 1], (&target)[0 .. 1]);
static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T)
{
@@ -273,3 +275,53 @@ void swap(T)(ref T a, ref T b) @trusted
assert(a == 5);
assert(b == 3);
}
+
+/**
+ * Copies the $(D_PARAM source) range into the $(D_PARAM target) range.
+ *
+ * Params:
+ * Source = Input range type.
+ * Target = Output range type.
+ * source = Source input range.
+ * target = Target output range.
+ *
+ * Precondition: $(D_PARAM target) should be large enough to accept all
+ * $(D_PARAM source) elements.
+ */
+void copy(Source, Target)(Source source, Target target)
+if (isInputRange!Source && isOutputRange!(Target, Source))
+in
+{
+ static if (hasLength!Source && hasLength!Target)
+ {
+ assert(target.length >= source.length);
+ }
+}
+do
+{
+ alias E = ElementType!Source;
+ static if (isDynamicArray!Source
+ && is(Source == Target)
+ && !hasElaborateCopyConstructor!E
+ && !hasElaborateAssign!E)
+ {
+ tanya.memory.op.copy(source, target);
+ }
+ else
+ {
+ for (; !source.empty; source.popFront())
+ {
+ put(target, source.front);
+ }
+ }
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ int[2] actual;
+ int[2] expected = [2, 3];
+
+ copy(actual[], expected[]);
+ assert(actual == expected);
+}
diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d
index a523d68..c6bc4e7 100644
--- a/source/tanya/container/string.d
+++ b/source/tanya/container/string.d
@@ -27,7 +27,7 @@
module tanya.container.string;
import std.algorithm.comparison : cmp;
-import std.algorithm.mutation : bringToFront, copy;
+import std.algorithm.mutation : bringToFront;
import std.algorithm.searching;
import tanya.algorithm.comparison;
import tanya.algorithm.mutation;
diff --git a/source/tanya/conv.d b/source/tanya/conv.d
index 561ccce..bce5401 100644
--- a/source/tanya/conv.d
+++ b/source/tanya/conv.d
@@ -308,11 +308,11 @@ do
{
digit = range.front - 'W';
}
- else if (range.front >= 'A')
+ else if (range.front >= 'A' && range.front <= 'Z')
{
digit = range.front - '7';
}
- else if (range.front >= '0')
+ else if (range.front >= '0' && range.front <= '9')
{
digit = range.front - '0';
}
@@ -360,6 +360,15 @@ do
return n;
}
+// ':' is not a hex value
+@nogc nothrow pure @safe unittest
+{
+ string colon = ":";
+ auto actual = readIntegral!ubyte(colon, 16);
+ assert(actual == 0);
+ assert(colon.length == 1);
+}
+
// reads ubyte.max
@nogc nothrow pure @safe unittest
{
diff --git a/source/tanya/math/mp.d b/source/tanya/math/mp.d
index ae365de..5a1e49a 100644
--- a/source/tanya/math/mp.d
+++ b/source/tanya/math/mp.d
@@ -15,14 +15,13 @@
module tanya.math.mp;
import std.algorithm.comparison : cmp;
-import std.algorithm.mutation : copy, fill, reverse;
+import std.algorithm.mutation : fill, reverse;
import std.range;
import tanya.algorithm.comparison;
import tanya.algorithm.mutation;
import tanya.container.array;
import tanya.encoding.ascii;
import tanya.memory;
-static import tanya.memory.op;
import tanya.meta.trait;
import tanya.meta.transform;
@@ -211,7 +210,7 @@ struct Integer
this(this) @nogc nothrow pure @safe
{
auto tmp = allocator.resize!digit(null, this.size);
- tanya.memory.op.copy(this.rep[0 .. this.size], tmp);
+ copy(this.rep[0 .. this.size], tmp);
this.rep = tmp;
}
@@ -344,8 +343,7 @@ struct Integer
if (is(Unqual!T == Integer))
{
this.rep = allocator.resize(this.rep, value.size);
- tanya.memory.op.copy(value.rep[0 .. value.size],
- this.rep[0 .. value.size]);
+ copy(value.rep[0 .. value.size], this.rep[0 .. value.size]);
this.size = value.size;
this.sign = value.sign;
diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d
index 7cf49e4..a98cf4a 100644
--- a/source/tanya/memory/package.d
+++ b/source/tanya/memory/package.d
@@ -14,7 +14,7 @@
*/
module tanya.memory;
-import std.algorithm.mutation;
+import std.algorithm.mutation : uninitializedFill;
import tanya.conv;
import tanya.exception;
public import tanya.memory.allocator;
diff --git a/source/tanya/net/ip.d b/source/tanya/net/ip.d
new file mode 100644
index 0000000..5c375ba
--- /dev/null
+++ b/source/tanya/net/ip.d
@@ -0,0 +1,374 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Internet Protocol implementation.
+ *
+ * Copyright: Eugene Wissner 2018.
+ * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
+ * Mozilla Public License, v. 2.0).
+ * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
+ * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/net/ip.d,
+ * tanya/net/ip.d)
+ */
+module tanya.net.ip;
+
+import tanya.algorithm.mutation;
+import tanya.container.string;
+import tanya.conv;
+import tanya.format;
+import tanya.meta.trait;
+import tanya.meta.transform;
+import tanya.net.inet;
+import tanya.range;
+import tanya.typecons;
+
+/**
+ * IPv4 internet address.
+ */
+struct Address4
+{
+ // In network byte order.
+ private uint address;
+
+ version (LittleEndian)
+ {
+ private enum uint loopback_ = 0x0100007fU;
+ enum byte step = 8;
+ }
+ else
+ {
+ private enum uint loopback_ = 0x7f000001U;
+ enum byte step = -8;
+ }
+ private enum uint any_ = 0U;
+ private enum uint broadcast = uint.max;
+
+ /**
+ * Constructs an $(D_PSYMBOL Address4) from an unsigned integer in host
+ * byte order.
+ *
+ * Params:
+ * address = The address as an unsigned integer in host byte order.
+ */
+ this(uint address) @nogc nothrow pure @safe
+ {
+ copy(NetworkOrder!4(address),
+ (() @trusted => (cast(ubyte*) &this.address)[0 .. 4])());
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(Address4(0x00202000U).toUInt() == 0x00202000U);
+ }
+
+ /**
+ * Returns object that represents 127.0.0.1.
+ *
+ * Returns: Object that represents the Loopback address.
+ */
+ static Address4 loopback() @nogc nothrow pure @safe
+ {
+ typeof(return) address;
+ address.address = Address4.loopback_;
+ return address;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(Address4.loopback().isLoopback());
+ }
+
+ /**
+ * Returns object that represents 0.0.0.0.
+ *
+ * Returns: Object that represents any address.
+ */
+ static Address4 any() @nogc nothrow pure @safe
+ {
+ typeof(return) address;
+ address.address = Address4.any_;
+ return address;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(Address4.any().isAny());
+ }
+
+ /**
+ * Loopback address is 127.0.0.1.
+ *
+ * Returns: $(D_KEYWORD true) if this is a loopback address,
+ * $(D_KEYWORD false) otherwise.
+ */
+ bool isLoopback() const @nogc nothrow pure @safe
+ {
+ return this.address == loopback_;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(address4("127.0.0.1").isLoopback());
+ }
+
+ /**
+ * 0.0.0.0 can represent any address. This function checks whether this
+ * address is 0.0.0.0.
+ *
+ * Returns: $(D_KEYWORD true) if this is an unspecified address,
+ * $(D_KEYWORD false) otherwise.
+ */
+ bool isAny() const @nogc nothrow pure @safe
+ {
+ return this.address == any_;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(address4("0.0.0.0").isAny());
+ }
+
+ /**
+ * Broadcast address is 255.255.255.255.
+ *
+ * Returns: $(D_KEYWORD true) if this is a broadcast address,
+ * $(D_KEYWORD false) otherwise.
+ */
+ bool isBroadcast() const @nogc nothrow pure @safe
+ {
+ return this.address == broadcast;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(address4("255.255.255.255").isBroadcast());
+ }
+
+ /**
+ * Determines whether this address' destination is a group of endpoints.
+ *
+ * Returns: $(D_KEYWORD true) if this is a multicast address,
+ * $(D_KEYWORD false) otherwise.
+ *
+ * See_Also: $(D_PSYMBOL isMulticast).
+ */
+ bool isMulticast() const @nogc nothrow pure @safe
+ {
+ version (LittleEndian)
+ {
+ enum uint mask = 0xe0;
+ }
+ else
+ {
+ enum uint mask = 0xe0000000U;
+ }
+ return (this.address & mask) == mask;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(address4("224.0.0.3").isMulticast());
+ }
+
+ /**
+ * Determines whether this address' destination is a single endpoint.
+ *
+ * Returns: $(D_KEYWORD true) if this is a multicast address,
+ * $(D_KEYWORD false) otherwise.
+ *
+ * See_Also: $(D_PSYMBOL isMulticast).
+ */
+ bool isUnicast() const @nogc nothrow pure @safe
+ {
+ return !isMulticast();
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(address4("192.168.0.1").isUnicast());
+ }
+
+ /**
+ * Produces a string containing an IPv4 address in dotted-decimal notation.
+ *
+ * Returns: This address in dotted-decimal notation.
+ */
+ String stringify() const @nogc nothrow pure @safe
+ {
+ const octets = (() @trusted => (cast(ubyte*) &this.address)[0 .. 4])();
+ enum string fmt = "{}.{}.{}.{}";
+ version (LittleEndian)
+ {
+ return format!fmt(octets[0], octets[1], octets[2], octets[3]);
+ }
+ else
+ {
+ return format!fmt(octets[3], octets[2], octets[1], octets[0]);
+ }
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ const dottedDecimal = "192.168.0.1";
+ const address = address4(dottedDecimal);
+ assert(address.get.stringify() == dottedDecimal);
+ }
+
+ /**
+ * Produces a byte array containing this address in network byte order.
+ *
+ * Returns: This address as raw bytes in network byte order.
+ */
+ ubyte[4] toBytes() const @nogc nothrow pure @safe
+ {
+ ubyte[4] bytes;
+ copy((() @trusted => (cast(ubyte*) &this.address)[0 .. 4])(), bytes[]);
+ return bytes;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ const actual = address4("192.168.0.1");
+ const ubyte[4] expected = [192, 168, 0, 1];
+ assert(actual.toBytes() == expected);
+ }
+
+ /**
+ * Converts this address to an unsigned integer in host byte order.
+ *
+ * Returns: This address as an unsigned integer in host byte order.
+ */
+ uint toUInt() const @nogc nothrow pure @safe
+ {
+ alias slice = () @trusted => (cast(ubyte*) &this.address)[0 .. 4];
+ return toHostOrder!uint(slice());
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ assert(address4("127.0.0.1").toUInt() == 0x7f000001U);
+ }
+}
+
+/**
+ * Parses a string containing an IPv4 address in dotted-decimal notation.
+ *
+ * Params:
+ * R = Input range type.
+ * range = Stringish range containing the address.
+ *
+ * Returns: $(D_PSYMBOL Option) containing the address if the parsing was
+ * successful, or nothing otherwise.
+ */
+Option!Address4 address4(R)(R range)
+if (isInputRange!R && isSomeChar!(ElementType!R))
+{
+ Address4 result;
+ version (LittleEndian)
+ {
+ ubyte shift;
+ enum ubyte cond = 24;
+ }
+ else
+ {
+ ubyte shift = 24;
+ enum ubyte cond = 0;
+ }
+
+ for (; shift != cond; shift += Address4.step, range.popFront())
+ {
+ result.address |= readIntegral!ubyte(range) << shift;
+ if (range.empty || range.front != '.')
+ {
+ return typeof(return)();
+ }
+ }
+
+ result.address |= readIntegral!ubyte(range) << shift;
+ return range.empty ? typeof(return)(result) : typeof(return)();
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ assert(address4("256.0.0.1").isNothing);
+}
+
+/**
+ * Constructs an $(D_PSYMBOL Address4) from raw bytes in network byte order.
+ *
+ * Params:
+ * R = Input range type.
+ * range = $(D_KEYWORD ubyte) range containing the address.
+ *
+ * Returns: $(D_PSYMBOL Option) containing the address if the $(D_PARAM range)
+ * contains exactly 4 bytes, or nothing otherwise.
+ */
+Option!Address4 address4(R)(R range)
+if (isInputRange!R && is(Unqual!(ElementType!R) == ubyte))
+{
+ Address4 result;
+ version (LittleEndian)
+ {
+ ubyte shift;
+ }
+ else
+ {
+ ubyte shift = 24;
+ }
+
+ for (; shift <= 24; shift += Address4.step, range.popFront())
+ {
+ if (range.empty)
+ {
+ return typeof(return)();
+ }
+ result.address |= range.front << shift;
+ }
+
+ return range.empty ? typeof(return)(result) : typeof(return)();
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ {
+ ubyte[4] actual = [127, 0, 0, 1];
+ assert(address4(actual[]).isLoopback());
+ }
+ {
+ ubyte[3] actual = [127, 0, 0];
+ assert(address4(actual[]).isNothing);
+ }
+ {
+ ubyte[5] actual = [127, 0, 0, 0, 1];
+ assert(address4(actual[]).isNothing);
+ }
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert(address4(cast(ubyte[]) []).isNothing);
+}
+
+// Assignment and comparison works
+@nogc nothrow pure @safe unittest
+{
+ auto address1 = Address4.loopback();
+ auto address2 = Address4.any();
+ address1 = address2;
+ assert(address1 == address2);
+}
diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d
index c9134de..72824a5 100644
--- a/source/tanya/range/primitive.d
+++ b/source/tanya/range/primitive.d
@@ -851,6 +851,8 @@ void put(R, E)(ref R range, auto ref E e)
}
else static if (isInputRange!E)
{
+ pragma(msg, "Putting an input range into an output range is "
+ ~ "deprecated. Use tanya.algorithm.mutation.copy instead");
for (; !e.empty; e.popFront())
{
put(range, e.front);
@@ -963,7 +965,22 @@ void put(R, E)(ref R range, auto ref E e)
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is an output range for the
* elements of the type $(D_PARAM E), $(D_KEYWORD false) otherwise.
*/
-enum bool isOutputRange(R, E) = is(typeof((ref R r, ref E e) => put(r, e)));
+template isOutputRange(R, E)
+{
+ static if (is(typeof((R r, E e) => put(r, e))))
+ {
+ enum bool isOutputRange = true;
+ }
+ else static if (isInputRange!E)
+ {
+ alias ET = ElementType!E;
+ enum bool isOutputRange = is(typeof((R r, ET e) => put(r, e)));
+ }
+ else
+ {
+ enum bool isOutputRange = false;
+ }
+}
///
@nogc nothrow pure @safe unittest