Skip to content

Commit

Permalink
Merge pull request #5981 from MartinNowak/issue18114
Browse files Browse the repository at this point in the history
fix Issue 18114 - regex performance regression
merged-on-behalf-of: Martin Nowak <code@dawg.eu>
  • Loading branch information
dlang-bot committed Feb 22, 2018
2 parents d17a195 + 7283f68 commit 460693c
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 14 deletions.
2 changes: 1 addition & 1 deletion std/regex/internal/backtracking.d
Expand Up @@ -825,7 +825,7 @@ struct CtContext
int addr;
}

this(Char)(const Regex!Char re)
this(Char)(ref const Regex!Char re)
{
match = 1;
reserved = 1; //first match is skipped
Expand Down
12 changes: 6 additions & 6 deletions std/regex/internal/ir.d
Expand Up @@ -434,7 +434,7 @@ struct Group(DataIndex)
interface MatcherFactory(Char)
{
@safe:
Matcher!Char create(const Regex!Char, in Char[] input) const;
Matcher!Char create(const ref Regex!Char, in Char[] input) const;
Matcher!Char dup(Matcher!Char m, in Char[] input) const;
size_t incRef(Matcher!Char m) const;
size_t decRef(Matcher!Char m) const;
Expand All @@ -448,9 +448,9 @@ abstract class GenericFactory(alias EngineType, Char) : MatcherFactory!Char
// round up to next multiple of size_t for alignment purposes
enum classSize = (__traits(classInstanceSize, EngineType!Char) + size_t.sizeof - 1) & ~(size_t.sizeof - 1);

Matcher!Char construct(const Regex!Char re, in Char[] input, void[] memory) const;
Matcher!Char construct(const ref Regex!Char re, in Char[] input, void[] memory) const;

override Matcher!Char create(const Regex!Char re, in Char[] input) const @trusted
override Matcher!Char create(const ref Regex!Char re, in Char[] input) const @trusted
{
immutable size = EngineType!Char.initialMemory(re) + classSize;
auto memory = enforce(malloc(size), "malloc failed")[0 .. size];
Expand Down Expand Up @@ -496,7 +496,7 @@ abstract class GenericFactory(alias EngineType, Char) : MatcherFactory!Char
// A factory for run-time engines
class RuntimeFactory(alias EngineType, Char) : GenericFactory!(EngineType, Char)
{
override EngineType!Char construct(const Regex!Char re, in Char[] input, void[] memory) const
override EngineType!Char construct(const ref Regex!Char re, in Char[] input, void[] memory) const
{
import std.conv : emplace;
return emplace!(EngineType!Char)(memory[0 .. classSize],
Expand All @@ -507,7 +507,7 @@ class RuntimeFactory(alias EngineType, Char) : GenericFactory!(EngineType, Char)
// A factory for compile-time engine
class CtfeFactory(alias EngineType, Char, alias func) : GenericFactory!(EngineType, Char)
{
override EngineType!Char construct(const Regex!Char re, in Char[] input, void[] memory) const
override EngineType!Char construct(const ref Regex!Char re, in Char[] input, void[] memory) const
{
import std.conv : emplace;
return emplace!(EngineType!Char)(memory[0 .. classSize],
Expand All @@ -518,7 +518,7 @@ class CtfeFactory(alias EngineType, Char, alias func) : GenericFactory!(EngineTy
// A workaround for R-T enum re = regex(...)
template defaultFactory(Char)
{
@property MatcherFactory!Char defaultFactory(const Regex!Char re)
@property MatcherFactory!Char defaultFactory(const ref Regex!Char re) @safe
{
import std.regex.internal.backtracking : BacktrackingMatcher;
import std.regex.internal.thompson : ThompsonMatcher;
Expand Down
2 changes: 1 addition & 1 deletion std/regex/internal/thompson.d
Expand Up @@ -847,7 +847,7 @@ final:
}
}

this()(const Regex!Char program, Stream stream, void[] memory)
this()(ref const Regex!Char program, Stream stream, void[] memory)
{
// We are emplace'd to malloced memory w/o blitting T.init over it\
// make sure we initialize all fields explicitly
Expand Down
33 changes: 27 additions & 6 deletions std/regex/package.d
Expand Up @@ -441,12 +441,22 @@ template ctRegexImpl(alias pattern, string flags=[])
{
// allow code that expects mutable Regex to still work
// we stay "logically const"
@trusted @property auto getRe() const { return cast() staticRe; }
@property @trusted ref getRe() const { return *cast(Regex!Char*)&staticRe; }
alias getRe this;
}
enum wrapper = Wrapper();
}

@safe unittest
{
// test compat for logical const workaround
static void test(StaticRegex!char)
{
}
enum re = ctRegex!``;
test(re);
}

/++
Compile regular expression using CTFE
and generate optimized native machine code for matching it.
Expand Down Expand Up @@ -476,18 +486,18 @@ if (isSomeString!R)
alias String = R;
private:
import std.conv : text;
R _input;
int _nMatch;
enum smallString = 3;
enum SMALL_MASK = 0x8000_0000, REF_MASK= 0x1FFF_FFFF;
union
{
Group!DataIndex[] big_matches;
Group!DataIndex[smallString] small_matches;
}
const(NamedGroup)[] _names;
R _input;
int _nMatch;
uint _f, _b;
uint _refcount; // ref count or SMALL MASK + num groups
const(NamedGroup)[] _names;

this(R input, uint n, const(NamedGroup)[] named)
{
Expand Down Expand Up @@ -671,6 +681,17 @@ public:

///A hook for compatibility with original std.regex.
@property ref captures(){ return this; }

void opAssign()(auto ref Captures rhs)
{
if (rhs._refcount & SMALL_MASK)
small_matches[0 .. rhs._refcount & 0xFF] = rhs.small_matches[0 .. rhs._refcount & 0xFF];
else
big_matches = rhs.big_matches;
assert(&this.tupleof[0] is &big_matches);
assert(&this.tupleof[1] is &small_matches);
this.tupleof[2 .. $] = rhs.tupleof[2 .. $];
}
}

///
Expand Down Expand Up @@ -802,7 +823,7 @@ public:
@property inout(Captures!R) captures() inout { return _captures; }
}

private @trusted auto matchOnce(RegEx, R)(R input, const RegEx prog)
private @trusted auto matchOnce(RegEx, R)(R input, const auto ref RegEx prog)
{
alias Char = BasicElementOf!R;
auto factory = prog.factory is null ? defaultFactory!Char(prog) : prog.factory;
Expand All @@ -813,7 +834,7 @@ private @trusted auto matchOnce(RegEx, R)(R input, const RegEx prog)
return captures;
}

private auto matchMany(RegEx, R)(R input, RegEx re) @safe
private auto matchMany(RegEx, R)(R input, auto ref RegEx re) @safe
{
return RegexMatch!R(input, re.withFlags(re.flags | RegexOption.global));
}
Expand Down

0 comments on commit 460693c

Please sign in to comment.