summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-09-20 08:31:54 +0200
committerEugen Wissner <belka@caraus.de>2017-09-20 08:31:54 +0200
commit8d3a4860e62d3b3a2dee6dd8e9343f5ff97f14dc (patch)
tree536b639ae07e52d5e6db49fd2c5e6e9383bcfa91 /source
parent3df6c833761cdeed7b9baf7bb149a452d63f9a06 (diff)
downloadtanya-8d3a4860e62d3b3a2dee6dd8e9343f5ff97f14dc.tar.gz
Add memory.op.find for looking for a byte in a memory block
Diffstat (limited to 'source')
-rw-r--r--source/tanya/memory/op.d76
1 files changed, 76 insertions, 0 deletions
diff --git a/source/tanya/memory/op.d b/source/tanya/memory/op.d
index beb37b5..e3c9451 100644
--- a/source/tanya/memory/op.d
+++ b/source/tanya/memory/op.d
@@ -278,3 +278,79 @@ private pure nothrow @safe @nogc unittest
assert(cmp(r1[0 .. $ - 1], r2[0 .. $ - 1]) == 0);
assert(cmp(r1[0 .. 8], r2[0 .. 8]) == 0);
}
+
+/**
+ * Finds the first occurrence of $(D_PARAM needle) in $(D_PARAM haystack) if
+ * any.
+ *
+ * Params:
+ * haystack = Memory block.
+ * needle = A byte.
+ *
+ * Returns: The subrange of $(D_PARAM haystack) whose first element is the
+ * 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)
+pure nothrow @trusted @nogc
+{
+ auto length = haystack.length;
+ const size_t needleWord = size_t.max * needle;
+ 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 == needle)
+ {
+ return bytes[0 .. 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)
+ {
+ break;
+ }
+ words++;
+ length -= size_t.sizeof;
+ }
+
+ // Find the exact needle position in the word
+ bytes = cast(inout(ubyte)*) words;
+ while (length > 0)
+ {
+ if (*bytes == needle)
+ {
+ return bytes[0 .. length];
+ }
+ bytes++;
+ length--;
+ }
+
+ return haystack[$ .. $];
+}
+
+///
+pure nothrow @safe @nogc unittest
+{
+ 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(find(haystack, 'i').length == 0);
+
+ assert(find(null, 'a').length == 0);
+}