summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-09-02 08:27:26 +0200
committerEugen Wissner <belka@caraus.de>2018-09-02 08:27:26 +0200
commit1f615301e5af2bcda525327f0dfd4381c24c0e45 (patch)
treea3dd33fe1a3612e5caad80d4a17ee20b59b5a209
parent131675d0a8cf440dfe8e6b3af0245bb6e93bb421 (diff)
downloadtanya-1f615301e5af2bcda525327f0dfd4381c24c0e45.tar.gz
memory.op: Add findNullTerminated
-rw-r--r--source/tanya/memory/op.d103
1 files changed, 89 insertions, 14 deletions
diff --git a/source/tanya/memory/op.d b/source/tanya/memory/op.d
index ec9bc2e..8e56c80 100644
--- a/source/tanya/memory/op.d
+++ b/source/tanya/memory/op.d
@@ -305,7 +305,7 @@ do
* first occurrence of $(D_PARAM needle). If $(D_PARAM needle)
* couldn't be found, an empty `inout void[]` is returned.
*/
-inout(void[]) find(return inout void[] haystack, const ubyte needle)
+inout(void[]) find(return inout void[] haystack, ubyte needle)
@nogc nothrow pure @trusted
in
{
@@ -326,19 +326,19 @@ do
{
return bytes[0 .. length];
}
- bytes++;
- length--;
+ ++bytes;
+ --length;
}
// Check if some of the words has the needle
auto words = cast(inout(size_t)*) bytes;
while (length >= size_t.sizeof)
{
- if (((*words ^ needleWord) - highBits) & (~*words) & mask)
+ if ((((*words ^ needleWord) - highBits) & (~*words) & mask) != 0)
{
break;
}
- words++;
+ ++words;
length -= size_t.sizeof;
}
@@ -350,8 +350,8 @@ do
{
return bytes[0 .. length];
}
- bytes++;
- length--;
+ ++bytes;
+ --length;
}
return haystack[$ .. $];
@@ -362,14 +362,89 @@ do
{
const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];
- assert(find(haystack, 'a') == haystack[]);
- assert(find(haystack, 'b') == haystack[1 .. $]);
- assert(find(haystack, 'c') == haystack[2 .. $]);
- assert(find(haystack, 'd') == haystack[3 .. $]);
- assert(find(haystack, 'e') == haystack[4 .. $]);
- assert(find(haystack, 'f') == haystack[5 .. $]);
- assert(find(haystack, 'h') == haystack[8 .. $]);
+ assert(cmp(find(haystack, 'a'), haystack[]) == 0);
+ assert(cmp(find(haystack, 'b'), haystack[1 .. $]) == 0);
+ assert(cmp(find(haystack, 'c'), haystack[2 .. $]) == 0);
+ assert(cmp(find(haystack, 'd'), haystack[3 .. $]) == 0);
+ assert(cmp(find(haystack, 'e'), haystack[4 .. $]) == 0);
+ assert(cmp(find(haystack, 'f'), haystack[5 .. $]) == 0);
+ assert(cmp(find(haystack, 'h'), haystack[8 .. $]) == 0);
assert(find(haystack, 'i').length == 0);
assert(find(null, 'a').length == 0);
}
+
+/**
+ * Looks for `\0` in the $(D_PARAM haystack) and returns the part of the
+ * $(D_PARAM haystack) ahead of it.
+ *
+ * Returns $(D_KEYWORD null) if $(D_PARAM haystack) doesn't contain a null
+ * character.
+ *
+ * Params:
+ * haystack = Memory block.
+ *
+ * Returns: The subrange that spans all bytes before the null character or
+ * $(D_KEYWORD null) if the $(D_PARAM haystack) doesn't contain any.
+ */
+inout(char[]) findNullTerminated(return inout char[] haystack)
+@nogc nothrow pure @trusted
+in
+{
+ assert(haystack.length == 0 || haystack.ptr !is null);
+}
+do
+{
+ auto length = haystack.length;
+ enum size_t highBits = filledBytes!(0x01, 0);
+ enum size_t mask = filledBytes!(0x80, 0);
+
+ // Align
+ auto bytes = cast(inout(ubyte)*) haystack;
+ while (length > 0 && ((cast(size_t) bytes) & 3) != 0)
+ {
+ if (*bytes == '\0')
+ {
+ return haystack[0 .. haystack.length - length];
+ }
+ ++bytes;
+ --length;
+ }
+
+ // Check if some of the words contains 0
+ auto words = cast(inout(size_t)*) bytes;
+ while (length >= size_t.sizeof)
+ {
+ if (((*words - highBits) & (~*words) & mask) != 0)
+ {
+ break;
+ }
+ ++words;
+ length -= size_t.sizeof;
+ }
+
+ // Find the exact 0 position in the word
+ bytes = cast(inout(ubyte)*) words;
+ while (length > 0)
+ {
+ if (*bytes == '\0')
+ {
+ return haystack[0 .. haystack.length - length];
+ }
+ ++bytes;
+ --length;
+ }
+
+ return null;
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ assert(cmp(findNullTerminated("abcdef\0gh"), "abcdef") == 0);
+ assert(cmp(findNullTerminated("\0garbage"), "") == 0);
+ assert(cmp(findNullTerminated("\0"), "") == 0);
+ assert(cmp(findNullTerminated("cstring\0"), "cstring") == 0);
+ assert(findNullTerminated(null) is null);
+ assert(findNullTerminated("abcdef") is null);
+}