Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

fix Issue 7300 - std.regex.ShiftOr!dchar.search is broken #462

Merged
merged 9 commits into from about 2 years ago

4 participants

Dmitry Olshansky David Nadlinger Timon Gehr Andrei Alexandrescu
Dmitry Olshansky
Collaborator

Aside from fixing this particular bug in one codepath of ShiftOr this includes

  • A start on cleaning up old CTFE and compiler workarounds.
  • Caching regexes was part of original std.regex though it had single recently used slot.
Dmitry Olshansky
Collaborator

I'm rebasing this. Ehm kills code comments :(

Dmitry Olshansky
Collaborator

Anything else on this pull? I'd really like to move this forward.

Dmitry Olshansky
Collaborator

Extended, fixed and rebased.

David Nadlinger
Collaborator

Looks fine to me – I wonder, though, if isTwowayCompatible should be publicly documented, so that users can make sense of failing template constraints.

Dmitry Olshansky
Collaborator

If documented then we are looking for a better name, something like isTwowayOrder or isTwowayComparator, or whatever.

Dmitry Olshansky
Collaborator

Ok, I've settled on just documenting isTwoWayCompatible. Any good ideas for renaming it are still welcome.

Andrei Alexandrescu andralex merged commit 84a847c into from March 30, 2012
Andrei Alexandrescu andralex closed this March 30, 2012
Timon Gehr tgehr commented on the diff March 30, 2012
std/range.d
@@ -5933,6 +5933,27 @@ unittest {
5933 5933
 }
5934 5934
 
5935 5935
 /**
  5936
+  Returns true if $(D fn) accepts variables of type T1 and T2 in any order.
  5937
+  The following code should compile:
  5938
+  ---
  5939
+  T1 t1; 
  5940
+  T2 t2;
  5941
+  fn(t1, t2);
  5942
+  fn(t2, t1);
  5943
+  ---
  5944
+*/
  5945
+template isTwoWayCompatible(alias fn, T1, T2)
  5946
+{
  5947
+    enum isTwoWayCompatible = is(typeof( (){ 
  5948
+            T1 e; 
  5949
+            T2 v;
  5950
+            return fn(v,e) && fn(e,v); 
6
Timon Gehr
tgehr added a note March 30, 2012

The documentation is inconsistent with the example, and both are inconsistent with the implementation.

Dmitry Olshansky Collaborator

I think the example is what documentation states.
Yet, the actual test code is even more restricted.
I'll make a pull to get this in line.

Timon Gehr
tgehr added a note March 31, 2012

The example also requires that T1 and T2 are default-constructible. You could initialize them with void to fix this.

Dmitry Olshansky Collaborator

The trick is ... it doesn't compile with:
T1 e=void;
T2 v=void;
fn(v,e);
fn(e,v);

I believe it has something to do with string predicates.
Like compiler checking "value used before initialized", it works ok for => predicates.

Problem happens with code like this:
import std.range;

void main(){
int[] abc = [1, 2, 3];
auto srange = assumeSorted!"<="(abc);
srange.lowerBound(2);
}

Timon Gehr
tgehr added a note April 04, 2012

What about

T1 foo();
T2 bar();

fn(foo(), bar());
fn(bar(),foo());

?

Dmitry Olshansky Collaborator

Nice one.
#521

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Steven Schveighoffer schveiguy referenced this pull request in schveiguy/phobos April 14, 2012
Merged

std.process ready for review? #1

Deleted user Unknown referenced this pull request from a commit December 24, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
3  changelog.dd
@@ -2,14 +2,17 @@ $(VERSION 059, ddd mm, 2012, =================================================,
2 2
 
3 3
     $(LIBBUGSFIXED
4 4
         $(LI $(BUGZILLA 4604): A stack overflow with writeln)
  5
+        $(LI $(BUGZILLA 5523): std.regex handles "\s" and "\W" (etc.) inside square brackets improperly)
5 6
         $(LI $(BUGZILLA 5674): AssertError in std.regex)
6 7
         $(LI $(BUGZILLA 5652): Add \p and \P unicode properties to std.regex)
7 8
         $(LI $(BUGZILLA 5964): std.stdio.readln can throw a UnicodeException)
  9
+        $(LI $(BUGZILLA 6217): [GSOC] result of std.algorithm.map is not movable)
8 10
         $(LI $(BUGZILLA 6403): Upgrade std.regex to Unicode UTS #18 Level 1 support)
9 11
         $(LI $(BUGZILLA 7111): New regex engine cannot match beginning of empty string)
10 12
         $(LI $(BUGZILLA 7138): Can't call array() on dirEntries)
11 13
         $(LI $(BUGZILLA 7264): Can't iterate result from 4-arg dirEntries as string)
12 14
         $(LI $(BUGZILLA 7299): std.uni missing doc comments)
  15
+        $(LI $(BUGZILLA 7300): std.regex.ShiftOr!dchar.search is broken)
13 16
         $(LI $(BUGZILLA 7374): stdin.byLine() throws AssertError on empty input)
14 17
         $(LI $(BUGZILLA 7628): std.format formatValue incorrect overload)
15 18
         $(LI $(BUGZILLA 7674): regex replace requires escaped format)
8  std/algorithm.d
@@ -1406,7 +1406,7 @@ unittest
1406 1406
 /// Ditto
1407 1407
 T move(T)(ref T src)
1408 1408
 {
1409  
-    T result;
  1409
+    T result=void;
1410 1410
     move(src, result);
1411 1411
     return result;
1412 1412
 }
@@ -8724,3 +8724,9 @@ unittest
8724 8724
     //writeln(b[0]);
8725 8725
     assert(b[0] == tuple(4.0, 2u));
8726 8726
 }
  8727
+
  8728
+unittest//Issue 6217 
  8729
+{
  8730
+    auto x = map!"a"([1,2,3]);
  8731
+    x = move(x);
  8732
+}
10  std/internal/uni.d
@@ -58,16 +58,6 @@ body
58 58
     }
59 59
 }
60 60
 
61  
-//ditto
62  
-@trusted void moveAllAlt(T)(T[] src, T[] dest)
63  
-{//moveAll is @system
64  
-    if(__ctfe)
65  
-        foreach(i,v; src)
66  
-            dest[i] = v;
67  
-    else
68  
-        moveAll(src, dest);
69  
-}
70  
-
71 61
 //$(D Interval)  represents an interval of codepoints: [a,b).
72 62
 struct Interval
73 63
 {
56  std/range.d
@@ -5933,6 +5933,27 @@ unittest {
5933 5933
 }
5934 5934
 
5935 5935
 /**
  5936
+  Returns true if $(D fn) accepts variables of type T1 and T2 in any order.
  5937
+  The following code should compile:
  5938
+  ---
  5939
+  T1 t1; 
  5940
+  T2 t2;
  5941
+  fn(t1, t2);
  5942
+  fn(t2, t1);
  5943
+  ---
  5944
+*/
  5945
+template isTwoWayCompatible(alias fn, T1, T2)
  5946
+{
  5947
+    enum isTwoWayCompatible = is(typeof( (){ 
  5948
+            T1 e; 
  5949
+            T2 v;
  5950
+            return fn(v,e) && fn(e,v); 
  5951
+        }
  5952
+    ));
  5953
+}
  5954
+
  5955
+
  5956
+/**
5936 5957
    Policy used with the searching primitives $(D lowerBound), $(D
5937 5958
    upperBound), and $(D equalRange) of $(LREF SortedRange) below.
5938 5959
  */
@@ -6233,10 +6254,9 @@ if (isRandomAccessRange!Range)
6233 6254
    ----
6234 6255
 */
6235 6256
     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
6236  
-    if (is(V : ElementType!Range))
  6257
+    if (isTwoWayCompatible!(predFun, ElementType!Range, V))
6237 6258
     {
6238  
-        ElementType!Range v = value;
6239  
-        return this[0 .. getTransitionIndex!(sp, geq)(v)];
  6259
+        return this[0 .. getTransitionIndex!(sp, geq)(value)];
6240 6260
     }
6241 6261
 
6242 6262
 // upperBound
@@ -6257,10 +6277,9 @@ if (isRandomAccessRange!Range)
6257 6277
    ----
6258 6278
 */
6259 6279
     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
6260  
-    if (is(V : ElementType!Range))
  6280
+    if (isTwoWayCompatible!(predFun, ElementType!Range, V))
6261 6281
     {
6262  
-        ElementType!Range v = value;
6263  
-        return this[getTransitionIndex!(sp, gt)(v) .. length];
  6282
+        return this[getTransitionIndex!(sp, gt)(value) .. length];
6264 6283
     }
6265 6284
 
6266 6285
 // equalRange
@@ -6284,7 +6303,8 @@ if (isRandomAccessRange!Range)
6284 6303
    assert(equal(r, [ 3, 3, 3 ]));
6285 6304
    ----
6286 6305
 */
6287  
-    auto equalRange(V)(V value) if (is(V : ElementType!Range))
  6306
+    auto equalRange(V)(V value)
  6307
+    if (isTwoWayCompatible!(predFun, ElementType!Range, V))
6288 6308
     {
6289 6309
         size_t first = 0, count = _input.length;
6290 6310
         while (count > 0)
@@ -6339,7 +6359,8 @@ assert(equal(r[1], [ 3, 3, 3 ]));
6339 6359
 assert(equal(r[2], [ 4, 4, 5, 6 ]));
6340 6360
 ----
6341 6361
 */
6342  
-    auto trisect(V)(V value) if (is(V : ElementType!Range))
  6362
+    auto trisect(V)(V value)
  6363
+    if (isTwoWayCompatible!(predFun, ElementType!Range, V))
6343 6364
     {
6344 6365
         size_t first = 0, count = _input.length;
6345 6366
         while (count > 0)
@@ -6447,6 +6468,19 @@ unittest
6447 6468
 
6448 6469
 unittest
6449 6470
 {
  6471
+    auto a = [ "A", "AG", "B", "E", "F" ];
  6472
+    auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
  6473
+    assert(equal(r[0], [ "A", "AG" ]));
  6474
+    assert(equal(r[1], [ "B" ]));
  6475
+    assert(equal(r[2], [ "E", "F" ]));
  6476
+    r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
  6477
+    assert(r[0].empty);
  6478
+    assert(equal(r[1], [ "A" ]));
  6479
+    assert(equal(r[2], [ "AG", "B", "E", "F" ]));
  6480
+}
  6481
+
  6482
+unittest
  6483
+{
6450 6484
     static void test(SearchPolicy pol)()
6451 6485
     {
6452 6486
         auto a = [ 1, 2, 3, 42, 52, 64 ];
@@ -6536,6 +6570,8 @@ unittest
6536 6570
     assert(equal(p, [0, 1, 2, 3, 4]));
6537 6571
     p = assumeSorted(a).lowerBound(6);
6538 6572
     assert(equal(p, [ 0, 1, 2, 3, 4, 5]));
  6573
+    p = assumeSorted(a).lowerBound(6.9);
  6574
+    assert(equal(p, [ 0, 1, 2, 3, 4, 5, 6]));
6539 6575
 }
6540 6576
 
6541 6577
 unittest
@@ -6543,6 +6579,8 @@ unittest
6543 6579
     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
6544 6580
     auto p = assumeSorted(a).upperBound(3);
6545 6581
     assert(equal(p, [4, 4, 5, 6 ]));
  6582
+    p = assumeSorted(a).upperBound(4.2);
  6583
+    assert(equal(p, [ 5, 6 ]));
6546 6584
 }
6547 6585
 
6548 6586
 unittest
@@ -6558,6 +6596,8 @@ unittest
6558 6596
     assert(p.empty);
6559 6597
     p = assumeSorted(a).equalRange(7);
6560 6598
     assert(p.empty);
  6599
+    p = assumeSorted(a).equalRange(3.0);
  6600
+    assert(equal(p, [ 3, 3, 3]));
6561 6601
 }
6562 6602
 
6563 6603
 unittest
181  std/regex.d
@@ -774,21 +774,11 @@ auto memoizeExpr(string expr)()
774 774
         s.add(Interval(0,0x7f));
775 775
     else
776 776
     {
777  
-        version(fred_perfect_hashing)
778  
-        {
779  
-            uint key = phash(name);
780  
-            if(key >= PHASHNKEYS || ucmp(name,unicodeProperties[key].name) != 0)
781  
-                enforce(0, "invalid property name");
782  
-            s = cast(CodepointSet)unicodeProperties[key].set;
783  
-        }
784  
-        else
785  
-        {
786  
-            auto range = assumeSorted!((x,y){ return ucmp(x.name, y.name) < 0; })(unicodeProperties);
787  
-            //creating empty Codepointset is a workaround
788  
-            auto eq = range.lowerBound(UnicodeProperty(cast(string)name,CodepointSet.init)).length;
789  
-            enforce(eq!=range.length && ucmp(name,range[eq].name)==0,"invalid property name");
790  
-            s = range[eq].set.dup;
791  
-        }
  777
+        auto range = assumeSorted!((x,y) => ucmp(x.name, y.name) < 0)(unicodeProperties);
  778
+        //creating empty Codepointset is a workaround
  779
+        auto eq = range.lowerBound(UnicodeProperty(cast(string)name,CodepointSet.init)).length;
  780
+        enforce(eq!=range.length && ucmp(name,range[eq].name)==0,"invalid property name");
  781
+        s = range[eq].set.dup;
792 782
     }
793 783
 
794 784
     if(casefold)
@@ -873,23 +863,19 @@ struct Parser(R, bool CTFE=false)
873 863
         if(isSomeString!S)
874 864
     {
875 865
         pat = origin = pattern;
  866
+        //reserve slightly more then avg as sampled from unittests
876 867
         if(!__ctfe)
877  
-            ir.reserve(pat.length);
  868
+            ir.reserve((pat.length*5+2)/4);
878 869
         parseFlags(flags);
879 870
         _current = ' ';//a safe default for freeform parsing
880 871
         next();
881  
-        if(__ctfe)
  872
+        try
  873
+        {
882 874
             parseRegex();
883  
-        else
  875
+        }
  876
+        catch(Exception e)
884 877
         {
885  
-            try
886  
-            {
887  
-                parseRegex();
888  
-            }
889  
-            catch(Exception e)
890  
-            {
891  
-                error(e.msg);//also adds pattern location
892  
-            }
  878
+            error(e.msg);//also adds pattern location
893 879
         }
894 880
         put(Bytecode(IR.End, 0));
895 881
     }
@@ -911,10 +897,8 @@ struct Parser(R, bool CTFE=false)
911 897
             empty =  true;
912 898
             return false;
913 899
         }
914  
-        //for CTFEability
915  
-        size_t idx=0;
916  
-        _current = decode(pat, idx);
917  
-        pat = pat[idx..$];
  900
+        _current = pat.front;
  901
+        pat.popFront();
918 902
         return true;
919 903
     }
920 904
 
@@ -1250,7 +1234,7 @@ struct Parser(R, bool CTFE=false)
1250 1234
         default:
1251 1235
             if(replace)
1252 1236
             {
1253  
-                moveAllAlt(ir[offset+1..$],ir[offset..$-1]);
  1237
+                moveAll(ir[offset+1..$],ir[offset..$-1]);
1254 1238
                 ir.length -= 1;
1255 1239
             }
1256 1240
             return;
@@ -1299,15 +1283,8 @@ struct Parser(R, bool CTFE=false)
1299 1283
             }
1300 1284
             else if(replace)
1301 1285
             {
1302  
-                if(__ctfe)//CTFE workaround: no moveAll and length -= x;
1303  
-                {
1304  
-                    ir = ir[0..offset] ~ ir[offset+1..$];
1305  
-                }
1306  
-                else
1307  
-                {
1308  
-                    moveAll(ir[offset+1 .. $],ir[offset .. $-1]);
1309  
-                    ir.length -= 1;
1310  
-                }
  1286
+                moveAll(ir[offset+1 .. $],ir[offset .. $-1]);
  1287
+                ir.length -= 1;
1311 1288
             }
1312 1289
             put(Bytecode(greedy ? IR.InfiniteStart : IR.InfiniteQStart, len));
1313 1290
             enforce(ir.length + len < maxCompiledLength,  "maximum compiled pattern length is exceeded");
@@ -2160,15 +2137,10 @@ private:
2160 2137
 }
2161 2138
 
2162 2139
 //
2163  
-@trusted uint lookupNamedGroup(String)(NamedGroup[] dict,String name)
  2140
+@trusted uint lookupNamedGroup(String)(NamedGroup[] dict, String name)
2164 2141
 {//equal is @system?
2165  
-    //@@@BUG@@@ assumeSorted kills "-inline"
2166  
-    //auto fnd = assumeSorted(map!"a.name"(dict)).lowerBound(name).length;
2167  
-    uint fnd;
2168  
-    for(fnd = 0; fnd<dict.length; fnd++)
2169  
-        if(equal(dict[fnd].name,name))
2170  
-            break;
2171  
-    enforce(fnd < dict.length, text("no submatch named ", name));
  2142
+    auto fnd = assumeSorted!"cmp(a,b) < 0"(map!"a.name"(dict)).lowerBound(name).length;
  2143
+    enforce(equal(dict[fnd].name, name), text("no submatch named ", name));
2172 2144
     return dict[fnd].group;
2173 2145
 }
2174 2146
 
@@ -2766,7 +2738,7 @@ public:
2766 2738
     // returns only valid UTF indexes
2767 2739
     // (that given the haystack in question is valid UTF string)
2768 2740
     @trusted size_t search(const(Char)[] haystack, size_t idx)
2769  
-    {
  2741
+    {//@BUG: apparently assumes little endian machines
2770 2742
         assert(!empty);
2771 2743
         auto p = cast(const(ubyte)*)(haystack.ptr+idx);
2772 2744
         uint state = uint.max;
@@ -2779,9 +2751,10 @@ public:
2779 2751
             while(p != end)
2780 2752
             {
2781 2753
                 if(!~state)
2782  
-                {
  2754
+                {//speed up seeking first matching place
2783 2755
                     for(;;)
2784 2756
                     {
  2757
+                        assert(p <= end, text(p," vs ", end));
2785 2758
                         p = cast(ubyte*)memchr(p, fChar, end - p);
2786 2759
                         if(!p)
2787 2760
                             return haystack.length;
@@ -2796,31 +2769,40 @@ public:
2796 2769
                     {
2797 2770
                         state = (state<<1) | table[p[1]];
2798 2771
                         state = (state<<1) | table[p[2]];
2799  
-                        p += 3;
  2772
+                        p += 4;
2800 2773
                     }
2801  
-                }
2802  
-                //first char is already tested, see if that's all
2803  
-                if(!(state & limit))//division rounds down for dchar
2804  
-                    return (p-cast(ubyte*)haystack.ptr)/Char.sizeof
2805  
-                        -length+1;
2806  
-                static if(charSize == 3)
2807  
-                {
2808  
-                    state = (state<<1) | table[p[1]];
2809  
-                    state = (state<<1) | table[p[2]];
2810  
-                    state = (state<<1) | table[p[3]];
2811  
-                    p+=4;
  2774
+                    else
  2775
+                        p++;
  2776
+                    //first char is tested, see if that's all
  2777
+                    if(!(state & limit))
  2778
+                        return (p-cast(ubyte*)haystack.ptr)/Char.sizeof
  2779
+                            -length;
2812 2780
                 }
2813 2781
                 else
2814  
-                {
2815  
-                    state = (state<<1) | table[p[1]];
2816  
-                    p++;
  2782
+                {//have some bits/states for possible matches,
  2783
+                 //use the usual shift-or cycle
  2784
+                    static if(charSize == 3)
  2785
+                    {
  2786
+                        state = (state<<1) | table[p[0]];
  2787
+                        state = (state<<1) | table[p[1]];
  2788
+                        state = (state<<1) | table[p[2]];
  2789
+                        p+=4;
  2790
+                    }
  2791
+                    else
  2792
+                    {
  2793
+                        state = (state<<1) | table[p[0]];
  2794
+                        p++;
  2795
+                    }
  2796
+                    if(!(state & limit))
  2797
+                        return (p-cast(ubyte*)haystack.ptr)/Char.sizeof
  2798
+                            -length;
2817 2799
                 }
2818 2800
                 debug(fred_search) writefln("State: %32b", state);
2819 2801
             }
2820 2802
         }
2821 2803
         else
2822 2804
         {
2823  
-            //in this path we have to shift first
  2805
+            //normal path, partially unrolled for char/wchar
2824 2806
             static if(charSize == 3)
2825 2807
             {
2826 2808
                 const(ubyte)* end = cast(ubyte*)(haystack.ptr + haystack.length);
@@ -4870,8 +4852,6 @@ enum OneShot { Fwd, Bwd };
4870 4852
     if(is(Char : dchar))
4871 4853
 {
4872 4854
     alias Stream.DataIndex DataIndex;
4873  
-    alias const(Char)[] String;
4874  
-    enum threadAllocSize = 16;
4875 4855
     Thread!DataIndex* freelist;
4876 4856
     ThreadList!DataIndex clist, nlist;
4877 4857
     DataIndex[] merge;
@@ -4978,7 +4958,6 @@ enum OneShot { Fwd, Bwd };
4978 4958
             writeln("------------------------------------------");
4979 4959
         if(exhausted)
4980 4960
         {
4981  
-
4982 4961
             return false;
4983 4962
         }
4984 4963
         if(re.flags & RegexInfo.oneShot)
@@ -5039,8 +5018,7 @@ enum OneShot { Fwd, Bwd };
5039 5018
                     break;
5040 5019
                 }
5041 5020
             }
5042  
-        else
5043  
-            exhausted = true;
  5021
+
5044 5022
         genCounter++; //increment also on each end
5045 5023
         debug(fred_matching) writefln("Threaded matching threads at end");
5046 5024
         //try out all zero-width posibilities
@@ -5050,8 +5028,17 @@ enum OneShot { Fwd, Bwd };
5050 5028
         }
5051 5029
         if(!matched)
5052 5030
             eval!false(createStart(index), matches);//new thread starting at end of input
5053  
-        if(matched && !(re.flags & RegexOption.global))
5054  
-           exhausted = true;
  5031
+        if(matched)
  5032
+        {//in case NFA found match along the way
  5033
+         //and last possible longer alternative ultimately failed
  5034
+            s.reset(matches[0].end);//reset to last successful match
  5035
+            next();//and reload front character
  5036
+            //--- here the exact state of stream was restored ---
  5037
+            exhausted = atEnd || !(re.flags & RegexOption.global);
  5038
+            //+ empty match advances the input
  5039
+            if(!exhausted && matches[0].begin == matches[0].end)
  5040
+                next(); 
  5041
+        }
5055 5042
         return matched;
5056 5043
     }
5057 5044
 
@@ -6278,6 +6265,24 @@ public:
6278 6265
     @property ref captures(){ return this; }
6279 6266
 }
6280 6267
 
  6268
+unittest//verify example
  6269
+{
  6270
+    auto m = match("@abc#", regex(`(\w)(\w)(\w)`));
  6271
+    auto c = m.captures;
  6272
+    assert(c.pre == "@");// part of input preceeding match
  6273
+    assert(c.post == "#"); // immediately after match
  6274
+    assert(c.hit == c[0] && c.hit == "abc");// the whole match
  6275
+    assert(c[2] =="b");
  6276
+    assert(c.front == "abc");
  6277
+    c.popFront();
  6278
+    assert(c.front == "a");
  6279
+    assert(c.back == "c");
  6280
+    c.popBack();
  6281
+    assert(c.back == "b");
  6282
+    popFrontN(c, 2);
  6283
+    assert(c.empty);
  6284
+}
  6285
+
6281 6286
 /++
6282 6287
     A regex engine state, as returned by $(D match) family of functions.
6283 6288
 
@@ -6397,9 +6402,19 @@ public:
6397 6402
 
6398 6403
     Throws: $(D RegexException) if there were any errors during compilation.
6399 6404
 +/
6400  
-public auto regex(S)(S pattern, const(char)[] flags="")
  6405
+@trusted public auto regex(S)(S pattern, const(char)[] flags="")
6401 6406
     if(isSomeString!(S))
6402 6407
 {
  6408
+    enum cacheSize = 8; //TODO: invent nice interface to control regex caching
  6409
+    if(__ctfe)
  6410
+        return regexImpl(pattern, flags);
  6411
+    return memoize!(regexImpl!S, cacheSize)(pattern, flags);
  6412
+}
  6413
+
  6414
+public auto regexImpl(S)(S pattern, const(char)[] flags="")
  6415
+    if(isSomeString!(S))
  6416
+{
  6417
+    alias Regex!(BasicElementOf!S) Reg;
6403 6418
     if(!__ctfe)
6404 6419
     {
6405 6420
         auto parser = Parser!(Unqual!(typeof(pattern)))(pattern, flags);
@@ -7228,8 +7243,9 @@ unittest
7228 7243
         run_tests!match(); //thompson VM
7229 7244
     }
7230 7245
 }
7231  
- version(fred_ct)
7232  
- {
  7246
+
  7247
+version(fred_ct)
  7248
+{
7233 7249
     unittest
7234 7250
     {
7235 7251
         auto cr = ctRegex!("abc");
@@ -7424,6 +7440,11 @@ else
7424 7440
                 if(ch != '-') //'--' is an operator
7425 7441
                     assert(match(to!string(ch),regex(`[\`~ch~`-\`~ch~`]`)));
7426 7442
             }
  7443
+            //bugzilla 7718
  7444
+            string strcmd = "./myApp.rb -os OSX -path \"/GIT/Ruby Apps/sec\" -conf 'notimer'";
  7445
+            auto reStrCmd = regex (`(".*")|('.*')`, "g");
  7446
+            assert(equal(map!"a[0]"(matchFn(strcmd, reStrCmd)),
  7447
+                         [`"/GIT/Ruby Apps/sec"`, `'notimer'`]));
7427 7448
         }
7428 7449
         test_body!bmatch();
7429 7450
         test_body!match();
@@ -7502,8 +7523,12 @@ else
7502 7523
     }
7503 7524
     unittest
7504 7525
     {//bugzilla 7111
7505  
-        assert(!match("", regex("^")).empty);
  7526
+        assert(match("", regex("^")));
7506 7527
     }
  7528
+    unittest
  7529
+    {//bugzilla 7300
  7530
+        assert(!match("a"d, "aa"d));
  7531
+    }    
7507 7532
 
7508 7533
     unittest
7509 7534
     {//bugzilla 7674
@@ -7523,4 +7548,4 @@ else
7523 7548
     }
7524 7549
 }
7525 7550
 
7526  
-}
  7551
+}//version(unittest)
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.