diff --git a/.gitignore b/.gitignore index 723cf46..1e605e9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ /.dub/ /obj/ fast -fast.dproj -fast.sln +/mono-d/ + diff --git a/source/fast/internal.d b/source/fast/internal.d index 1b3c746..2c9d040 100644 --- a/source/fast/internal.d +++ b/source/fast/internal.d @@ -180,7 +180,7 @@ version (benchmark) import fast.string, fast.uniconv; static immutable pathname = "hello/i_am_a/path_name\\with_several_different\\slashes"; - static zeroterm = "wefwfnqwefnw(eknwoemkf)moorroijqwoijqioqo(vqwojkpjavnal(nvo(eirvn$wefwfnqwefnw(eknwoemkf)moorroijqwoijqioqo(vqwojkpjavnal(nvo(eirvn$wefwfnqwefnw(eknwoemkf)moorroijqwoijqioqo(vqwojkpjavnal(nvo(eirvn$\0"; + static immutable zeroterm = "wefwfnqwefnw(eknwoemkf)moorroijqwoijq&oqo(vqwojkpjavnal(nvo(eirvn$wefwfnqwefnw(eknwoemkf)moorroijqwoihqioqo(vqwojkpjavnal(nvo(eirvn$wefwfnqwef\"w(eknwoemkf)moorroijqwoijqioqo(vqwojkpjavnal(nvo(eirvn$\0"; static pathSepRegex = ctRegex!`[/\\]`; enum pathnameWStringLength = to!wstring(pathname).length; @@ -189,24 +189,22 @@ version (benchmark) benchmark ("uniconv.stackToWString", () { mixin stackToWString!("result", pathname); return result.ptr[pathnameWStringLength]; }), ); - run ("Check that there are no tabs in a string...", true, - benchmark ("std.string.indexOf", () { return std.string.indexOf(zeroterm, '\t') == -1; }), - benchmark ("algorithm.countUntil", () { return countUntil(zeroterm, '\t') == -1; }), - benchmark ("foreach", () { foreach (ref c; zeroterm) if (c == '\t') return false; return true; }), - benchmark ("fast.string.find", () { return !(fast.string.find!'\t'(zeroterm) < zeroterm.length); }), + run ("Split a string at each occurance of <, >, & and \"...", "w(eknwoemkf)moorroijqwoijqioqo(vqwojkpjavnal(nvo(eirvn$\0", + benchmark (`while + if with 4 cond`, () { string before; immutable(char*) stop = zeroterm.ptr + zeroterm.length; immutable(char)* iter = zeroterm.ptr; immutable(char)* done = zeroterm.ptr; if (iter !is stop) do { char c = *iter++; if (c == '<' || c == '>' || c == '&' || c == '"') { before = done[0 .. iter - done]; done = iter; }} while (iter !is stop); return done[0 .. stop - done]; }), + benchmark ("fast.string.find", () { string before, after = zeroterm; while (fast.string.split!('<', '>', '&', '"')(after, before, after)) {} return before; }), ); run ("Find terminating zero in a string...", zeroterm.length - 1, - benchmark ("std.string.indexOf", () { return cast(size_t) std.string.indexOf(zeroterm, '\0'); }), - benchmark ("algorithm.countUntil", () { return cast(size_t) countUntil(zeroterm, '\0'); }), - benchmark ("while(*ptr) ptr++", () { auto ptr = zeroterm.ptr; while (*ptr) ptr++; return cast(size_t) (ptr - zeroterm.ptr); }), - benchmark ("fast.string.find", () { return fast.string.find!'\0'(zeroterm.ptr); }), + benchmark ("std.string.indexOf", () { return cast(size_t) std.string.indexOf(zeroterm, '\0'); }), + benchmark ("algorithm.countUntil", () { return cast(size_t) countUntil(zeroterm, '\0'); }), + benchmark ("while(*ptr) ptr++", () { auto ptr = zeroterm.ptr; while (*ptr) ptr++; return cast(size_t) (ptr - zeroterm.ptr); }), + benchmark ("fast.string.find", () { return fast.string.find!'\0'(zeroterm.ptr); }), ); run ("Split a path by '/' or '\\'...", "slashes", - benchmark ("std.regex.splitter", () { string last; auto range = splitter(pathname, pathSepRegex); while (!range.empty) { last = range.front; range.popFront(); } return last; }), - benchmark ("std.regex.split", () { return split(pathname, pathSepRegex)[$-1]; }), - benchmark ("fast.string.split", () { string before, after = pathname; while (fast.string.split!('\\', '/')(after, before, after)) {} return after; }), + benchmark ("std.regex.splitter", () { string last; auto range = splitter(pathname, pathSepRegex); while (!range.empty) { last = range.front; range.popFront(); } return last; }), + benchmark ("std.regex.split", () { return split(pathname, pathSepRegex)[$-1]; }), + benchmark ("fast.string.split", () { string before, after = pathname; while (fast.string.split!('\\', '/')(after, before, after)) {} return before; }), ); writeln("Benchmark done!"); diff --git a/source/fast/string.d b/source/fast/string.d index 3f50b77..1f2406d 100644 --- a/source/fast/string.d +++ b/source/fast/string.d @@ -26,23 +26,24 @@ import fast.internal; * Splits a string in two around one or more compile-time known code units. * * Params: - * ch = The code unit(s) that initiates the split. It is typically an ASCII symbol. + * ch... = The code unit(s) that initiates the split. It is typically an ASCII symbol. * str = The string to scan. - * before = Iff the call was successful, the part before the split is stored here. Otherwise it remains unchanged. - * after = Iff the call was successful, the part after the split is stored here. Otherwise it remains unchanged. + * before = The part before the split is stored here. If no character in $(D ch...) is found, the original string is returned here. + * after = The part after the split is stored here. If no character in $(D ch...) is found, $(D null) is returned here. * * Returns: * $(D true), iff the symbol was found in the string. */ bool split(ch...)(scope inout(char[]) str, ref inout(char)[] before, ref inout(char)[] after, char* splitter = null) { - immutable pos = findImpl!(false, ch)(str.ptr, str.length); + immutable pos = min (str.length, findImpl!(false, ch)(str.ptr, str.length)); + before = str[0 .. pos]; if (pos < str.length) { - before = str[0 .. pos]; after = str[pos+1 .. $]; if (splitter) *splitter = str[pos]; return true; } + after = null; return false; }