diff tests/test-revset.t @ 25309:b333ca94403d

revset: reduce nesting of chained 'or' operations (issue4624) This reduces the stack depth of chained 'or' operations: - from O(n) to O(1) at the parsing, alias expansion and optimization phases - from O(n) to O(log(n)) at the evaluation phase simplifyinfixops() must be applied immediately after the parsing phase. Otherwise, alias expansion would crash by "maximum recursion depth exceeded" error. Test cases use 'x:y|y:z' instead of 'x|y' because I'm planning to optimize 'x|y' in a different way. Benchmarks: 0) 605b1d32c1c0 1) this patch revset #0: 0 + 1 + 2 + ... + 200 0) wall 0.026347 comb 0.030000 user 0.030000 sys 0.000000 (best of 101) 1) wall 0.023858 comb 0.030000 user 0.030000 sys 0.000000 (best of 112) revset #1: 0 + 1 + 2 + ... + 1000 0) maximum recursion depth exceeded 1) wall 0.483341 comb 0.480000 user 0.480000 sys 0.000000 (best of 20) revset #2: sort(0 + 1 + 2 + ... + 200) 0) wall 0.013404 comb 0.010000 user 0.010000 sys 0.000000 (best of 196) 1) wall 0.006814 comb 0.010000 user 0.010000 sys 0.000000 (best of 375) revset #3: sort(0 + 1 + 2 + ... + 1000) 0) maximum recursion depth exceeded 1) wall 0.035240 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
author Yuya Nishihara <yuya@tcha.org>
date Sun, 26 Apr 2015 18:13:48 +0900
parents 701df761aa94
children 7fbef7932af9
line wrap: on
line diff
--- a/tests/test-revset.t	Sun May 24 14:10:52 2015 +0900
+++ b/tests/test-revset.t	Sun Apr 26 18:13:48 2015 +0900
@@ -128,16 +128,15 @@
   6
   $ try '0|1|2'
   (or
-    (or
-      ('symbol', '0')
-      ('symbol', '1'))
+    ('symbol', '0')
+    ('symbol', '1')
     ('symbol', '2'))
   * set:
   <addset
+    <baseset [0]>,
     <addset
-      <baseset [0]>,
-      <baseset [1]>>,
-    <baseset [2]>>
+      <baseset [1]>,
+      <baseset [2]>>>
   0
   1
   2
@@ -910,6 +909,49 @@
   4
   5
 
+test that chained `or` operations make balanced addsets
+
+  $ try '0:1|1:2|2:3|3:4|4:5'
+  (or
+    (range
+      ('symbol', '0')
+      ('symbol', '1'))
+    (range
+      ('symbol', '1')
+      ('symbol', '2'))
+    (range
+      ('symbol', '2')
+      ('symbol', '3'))
+    (range
+      ('symbol', '3')
+      ('symbol', '4'))
+    (range
+      ('symbol', '4')
+      ('symbol', '5')))
+  * set:
+  <addset
+    <addset
+      <spanset+ 0:1>,
+      <spanset+ 1:2>>,
+    <addset
+      <spanset+ 2:3>,
+      <addset
+        <spanset+ 3:4>,
+        <spanset+ 4:5>>>>
+  0
+  1
+  2
+  3
+  4
+  5
+
+test that chained `or` operations never eat up stack (issue4624)
+(uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
+
+  $ hg log -T '{rev}\n' -r "`python -c "print '|'.join(['0:1'] * 500)"`"
+  0
+  1
+
 check that conversion to only works
   $ try --optimize '::3 - ::1'
   (minus
@@ -1352,6 +1394,44 @@
   <baseset [5]>
   5
 
+test chained `or` operations are flattened at parsing phase
+
+  $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
+  $ try 'chainedorops(0:1, 1:2, 2:3)'
+  (func
+    ('symbol', 'chainedorops')
+    (list
+      (list
+        (range
+          ('symbol', '0')
+          ('symbol', '1'))
+        (range
+          ('symbol', '1')
+          ('symbol', '2')))
+      (range
+        ('symbol', '2')
+        ('symbol', '3'))))
+  (or
+    (range
+      ('symbol', '0')
+      ('symbol', '1'))
+    (range
+      ('symbol', '1')
+      ('symbol', '2'))
+    (range
+      ('symbol', '2')
+      ('symbol', '3')))
+  * set:
+  <addset
+    <spanset+ 0:1>,
+    <addset
+      <spanset+ 1:2>,
+      <spanset+ 2:3>>>
+  0
+  1
+  2
+  3
+
 test variable isolation, variable placeholders are rewritten as string
 then parsed and matched again as string. Check they do not leak too
 far away.