1 module libd.algorithm.search; 2 import libd.algorithm, libd.util.cpuid; 3 4 const INDEX_NOT_FOUND = size_t.max; // Since our only target is x86_64, we can account for the fact it's literally impossible for a memory address to be this value. 5 6 @nogc nothrow: 7 8 // Using NASM because D's inline ASM, and even core.simd, don't support things like vpbroadcastb, so.... 9 @trusted 10 private extern(C) ulong indexOfByteAvx2(const(ubyte)* haystack, ulong haystackSize, ubyte* needle, ulong* remainingChars); 11 @("indexOfByteAvx2") 12 unittest 13 { 14 if(cpuidHasAvx2) 15 { 16 size_t remainingChars; 17 ubyte needle = ' '; 18 assert(indexOfByteAvx2(null, 0, &needle, &remainingChars) == INDEX_NOT_FOUND); 19 assert(indexOfByteAvx2(cast(const ubyte*)" ".ptr, 32, &needle, &remainingChars) == 0); 20 assert(indexOfByteAvx2(cast(const ubyte*)"0123 ".ptr, 32, &needle, &remainingChars) == 4); 21 22 remainingChars = 33; 23 needle = '_'; 24 assert(indexOfByteAvx2(cast(const ubyte*)"0123 _".ptr, 33, &needle, &remainingChars) == INDEX_NOT_FOUND); 25 assert(remainingChars == 1); 26 27 assert(indexOfByteAvx2(cast(const ubyte*)"0123 _123 ".ptr, 64, &needle, &remainingChars) == 32); 28 needle = '6'; 29 assert(indexOfByteAvx2(cast(const ubyte*)"0123 _126 ".ptr, 64, &needle, &remainingChars) == 35); 30 } 31 } 32 33 @trusted 34 size_t indexOfAscii(scope const bcstring haystack, char asciiChar) 35 { 36 assert((asciiChar & 0b1000_0000) == 0, "This function does not support searching for UTF chars."); 37 38 size_t remainingChars = haystack.length; 39 40 if(cpuidHasAvx2 && remainingChars >= 32) 41 { 42 const result = indexOfByteAvx2(cast(const ubyte*)haystack.ptr, haystack.length, cast(ubyte*)&asciiChar, &remainingChars); 43 if(result != INDEX_NOT_FOUND) 44 return result; 45 } 46 47 for(size_t i = haystack.length-remainingChars; i < haystack.length; i++) 48 { 49 if(haystack[i] == asciiChar) 50 return i; 51 } 52 53 return INDEX_NOT_FOUND; 54 } 55 /// 56 @("indexOfAscii") 57 unittest 58 { 59 assert("0123456789".indexOfAscii('0') == 0); 60 assert("0123456789".indexOfAscii('9') == 9); 61 assert("0123456789".indexOfAscii('4') == 4); 62 63 assert("The quick brown fox jumped over the lazy dog.".indexOfAscii('d') == 25); 64 assert("The quick brown fox jumped over the lazy dog.".indexOfAscii('z') == 38); 65 } 66 67 size_t indexOf(alias Comparator, HaystackT, NeedleT)(const auto ref HaystackT haystack, const auto ref NeedleT needle) 68 if(canForeachOrProvidesRange!HaystackT) 69 { 70 import libd.meta : ElementType; 71 72 static if(!canForeach!HaystackT) 73 auto range = haystack.range; 74 else 75 alias range = haystack; 76 77 static immutable IMPL = q{ 78 if(value == needle) 79 return index; 80 index++; 81 }; 82 83 size_t index; 84 static if(!is(ElementType!range == struct) || __traits(isPOD, ElementType!range)) 85 { 86 foreach(value; range) 87 mixin(IMPL); 88 } 89 else 90 { 91 foreach(ref value; range) 92 mixin(IMPL); 93 } 94 95 return INDEX_NOT_FOUND; 96 } 97 /// 98 @("indexOf") 99 unittest 100 { 101 import libd.datastructures..string, libd.datastructures.array; 102 103 Array!char arr; 104 arr.put("0123456789"); 105 106 assert("0123456789".indexOf('0') == 0); 107 assert(String("0123456789").indexOf('9') == 9); 108 assert(arr.indexOf('4') == 4); 109 110 assert("The quick brown fox jumped over the lazy dog.".indexOf('d') == 25); 111 assert("The quick brown fox jumped over the lazy dog.".indexOf('z') == 38); 112 } 113 114 size_t indexOf(HaystackT, NeedleT, alias Comparator = (a,b) => a == b)(const auto ref HaystackT haystack, const auto ref NeedleT needle) 115 { 116 return indexOf!Comparator(haystack, needle); 117 }