This is an automated email from the ASF dual-hosted git repository.

andreac pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit f50294137f401188f13039c6d350171ded7c6e97
Merge: 6b5c24d20c a64ed7220e
Author: Andrea Child <[email protected]>
AuthorDate: Tue Oct 21 09:47:50 2025 -0700

    Merge branch '3.8-dev'

 CHANGELOG.asciidoc                                 |   2 +
 docs/src/reference/the-traversal.asciidoc          |  21 +-
 docs/src/upgrade/release-3.8.x.asciidoc            |  70 +-
 .../gremlin/process/traversal/Traverser.java       |  19 +-
 .../process/traversal/step/branch/RepeatStep.java  |   2 +-
 .../traversal/step/filter/RangeGlobalStep.java     |  86 ++-
 .../optimization/RepeatUnrollStrategy.java         |   4 +
 .../traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java   |  90 +--
 .../traverser/B_LP_NL_O_S_SE_SL_Traverser.java     |  94 +--
 .../traverser/B_NL_O_S_SE_SL_Traverser.java        |  93 +--
 .../traversal/traverser/B_O_S_SE_SL_Traverser.java |  70 +-
 .../traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java  |  97 +--
 .../traverser/LP_NL_O_OB_S_SE_SL_Traverser.java    |  95 +--
 .../traverser/NL_O_OB_S_SE_SL_Traverser.java       |  95 +--
 .../traversal/traverser/NL_SL_Traverser.java       | 247 +++++++
 .../traverser/O_OB_S_SE_SL_Traverser.java          |  83 ++-
 .../traverser/util/AbstractTraverser.java          |  27 +-
 .../traversal/traverser/util/LabelledCounter.java  |   4 +
 .../traversal/step/filter/RangeGlobalStepTest.java |  61 +-
 .../B_LP_NL_O_P_S_SE_SL_TraverserTest.java         |  28 +
 .../traverser/B_LP_NL_O_S_SE_SL_TraverserTest.java |  28 +
 .../traverser/B_LP_O_P_S_SE_SL_TraverserTest.java  |  28 +
 .../traverser/B_LP_O_S_SE_SL_TraverserTest.java    |  28 +
 .../traverser/B_NL_O_S_SE_SL_TraverserTest.java    |  28 +
 .../traverser/B_O_S_SE_SL_TraverserTest.java       |  27 +
 .../LP_NL_O_OB_P_S_SE_SL_TraverserTest.java        |  28 +
 .../LP_NL_O_OB_S_SE_SL_TraverserTest.java          |  28 +
 .../traverser/LP_O_OB_P_S_SE_SL_TraverserTest.java |  28 +
 .../traverser/LP_O_OB_S_SE_SL_TraverserTest.java   |  28 +
 .../traverser/NL_O_OB_S_SE_SL_TraverserTest.java   |  28 +
 .../traversal/traverser/NL_TraverserTest.java      | 158 +++++
 .../traverser/O_OB_S_SE_SL_TraverserTest.java      |  28 +
 .../traversal/traverser/SL_TraverserTest.java      | 135 ++++
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  21 +
 gremlin-go/driver/cucumber/gremlin.go              |  21 +
 .../gremlin-javascript/test/cucumber/gremlin.js    |  21 +
 gremlin-python/src/main/python/radish/gremlin.py   |  21 +
 .../gremlin/test/features/filter/Range.feature     | 236 +++++++
 .../integrated/RepeatUnrollStrategy.feature        |   4 +-
 .../TinkerGraphRepeatRangeGlobalTest.java          | 769 +++++++++++++++++++++
 40 files changed, 2404 insertions(+), 577 deletions(-)

diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
index fd54ff71bc,335b8070d1..a0ce38d1f2
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
@@@ -18,20 -18,16 +18,17 @@@
   */
  package org.apache.tinkerpop.gremlin.process.traversal.traverser;
  
+ import java.util.Objects;
+ import java.util.Stack;
 -import org.apache.commons.collections.map.ReferenceMap;
 +import org.apache.commons.collections4.map.AbstractReferenceMap;
 +import org.apache.commons.collections4.map.ReferenceMap;
  import org.apache.tinkerpop.gremlin.process.traversal.Step;
  import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
  
- 
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Stack;
- 
- public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends 
B_LP_O_P_S_SE_SL_Traverser<T> {
+ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends 
B_LP_O_P_S_SE_SL_Traverser<T> implements NL_SL_Traverser<T> {
  
      protected Stack<LabelledCounter> nestedLoops;
 -    protected ReferenceMap loopNames = null;
 +    protected ReferenceMap<String,Object> loopNames = null;
  
      protected B_LP_NL_O_P_S_SE_SL_Traverser() {
      }
@@@ -39,25 -35,17 +36,18 @@@
      public B_LP_NL_O_P_S_SE_SL_Traverser(final T t, final Step<T, ?> step, 
final long initialBulk) {
          super(t, step, initialBulk);
          this.nestedLoops = new Stack<>();
 -        this.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
 +        this.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
 +                AbstractReferenceMap.ReferenceStrength.WEAK);
      }
  
-     /////////////////
- 
      @Override
-     public int loops() {
-         return this.nestedLoops.peek().count();
+     public Stack<LabelledCounter> getNestedLoops() {
+         return nestedLoops;
      }
  
      @Override
-     public int loops(final String loopName) {
-         if (loopName == null)
-             return loops();
-         else if (this.loopNames.containsKey(loopName))
-             return ((LabelledCounter) this.loopNames.get(loopName)).count();
-         else
-             throw new IllegalArgumentException("Loop name not defined: " + 
loopName);
 -    public ReferenceMap getNestedLoopNames() {
++    public ReferenceMap<String,Object> getNestedLoopNames() {
+         return loopNames;
      }
  
      @Override
@@@ -158,4 -97,10 +99,11 @@@
          return result;
      }
  
+     private void cloneLoopState(final B_LP_NL_O_P_S_SE_SL_Traverser<?> clone) 
{
+         clone.nestedLoops = new Stack<>();
 -        clone.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
++        clone.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
++                AbstractReferenceMap.ReferenceStrength.WEAK);
+         copyNestedLoops(clone.nestedLoops, clone.loopNames);
+     }
+ 
  }
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
index d14c8c1a91,03c3a5835b..f3cf0fb87d
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
@@@ -18,20 -18,16 +18,17 @@@
   */
  package org.apache.tinkerpop.gremlin.process.traversal.traverser;
  
+ import java.util.Objects;
+ import java.util.Stack;
 -import org.apache.commons.collections.map.ReferenceMap;
 +import org.apache.commons.collections4.map.ReferenceMap;
 +import org.apache.commons.collections4.map.AbstractReferenceMap;
  import org.apache.tinkerpop.gremlin.process.traversal.Step;
  import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
  
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.Stack;
- 
- public class B_LP_NL_O_S_SE_SL_Traverser<T> extends 
B_LP_O_S_SE_SL_Traverser<T> {
+ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends 
B_LP_O_S_SE_SL_Traverser<T> implements NL_SL_Traverser<T> {
  
      protected Stack<LabelledCounter> nestedLoops;
 -    protected ReferenceMap loopNames = null;
 +    protected ReferenceMap<String,Object> loopNames = null;
  
      protected B_LP_NL_O_S_SE_SL_Traverser() {
      }
@@@ -39,39 -35,17 +36,18 @@@
      public B_LP_NL_O_S_SE_SL_Traverser(final T t, final Step<T, ?> step, 
final long initialBulk) {
          super(t, step, initialBulk);
          this.nestedLoops = new Stack<>();
 -        this.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
 +        this.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
 +                AbstractReferenceMap.ReferenceStrength.WEAK);
      }
  
-     /////////////////
- 
-     @Override
-     public int loops() {
-         return this.nestedLoops.peek().count();
-     }
- 
      @Override
-     public int loops(final String loopName) {
-         if (loopName == null)
-             return loops();
-         else if (this.loopNames.containsKey(loopName))
-             return ((LabelledCounter) this.loopNames.get(loopName)).count();
-         else
-             throw new IllegalArgumentException("Loop name not defined: " + 
loopName);
+     public Stack<LabelledCounter> getNestedLoops() {
+         return nestedLoops;
      }
  
      @Override
-     public void initialiseLoops(final String stepLabel, final String 
loopName) {
-         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-             final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
-             this.nestedLoops.push(lc);
-             if (loopName != null)
-                 this.loopNames.put(loopName, lc);
-         }
-     }
-     @Override
-     public Set<String> getLoopNames() {
-         return loopNames.keySet();
 -    public ReferenceMap getNestedLoopNames() {
++    public ReferenceMap<String,Object> getNestedLoopNames() {
+         return loopNames;
      }
  
      @Override
@@@ -162,4 -97,10 +99,11 @@@
          return result;
      }
  
+     private void cloneLoopState(final B_LP_NL_O_S_SE_SL_Traverser<?> clone) {
+         clone.nestedLoops = new Stack<>();
 -        clone.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
++        clone.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
++                AbstractReferenceMap.ReferenceStrength.WEAK);
+         copyNestedLoops(clone.nestedLoops, clone.loopNames);
+     }
+ 
  }
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
index ba1d543a5a,46794ca4e6..ebe3ee9f58
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
@@@ -18,19 -18,16 +18,17 @@@
   */
  package org.apache.tinkerpop.gremlin.process.traversal.traverser;
  
+ import java.util.Objects;
+ import java.util.Stack;
 -import org.apache.commons.collections.map.ReferenceMap;
 +import org.apache.commons.collections4.map.AbstractReferenceMap;
 +import org.apache.commons.collections4.map.ReferenceMap;
  import org.apache.tinkerpop.gremlin.process.traversal.Step;
  import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
  
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Stack;
- 
- public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
+ public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> 
implements NL_SL_Traverser<T> {
  
      protected Stack<LabelledCounter> nestedLoops;
 -    protected ReferenceMap loopNames = null;
 +    protected ReferenceMap<String,Object> loopNames = null;
  
      protected B_NL_O_S_SE_SL_Traverser() {
      }
@@@ -38,45 -35,22 +36,23 @@@
      public B_NL_O_S_SE_SL_Traverser(final T t, final Step<T, ?> step, final 
long initialBulk) {
          super(t, step, initialBulk);
          this.nestedLoops = new Stack<>();
 -        this.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
 +        this.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
 +                AbstractReferenceMap.ReferenceStrength.WEAK);
      }
  
-     /////////////////
- 
-     @Override
-     public int loops() {
-         return this.nestedLoops.peek().count();
-     }
- 
      @Override
-     public int loops(final String loopName) {
-         if (loopName == null)
-             return loops();
-         else if (this.loopNames.containsKey(loopName))
-             return ((LabelledCounter) this.loopNames.get(loopName)).count();
-         else
-             throw new IllegalArgumentException("Loop name not defined: " + 
loopName);
+     public Stack<LabelledCounter> getNestedLoops() {
+         return nestedLoops;
      }
  
      @Override
-     public void initialiseLoops(final String stepLabel, final String 
loopName) {
-         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-             final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
-             this.nestedLoops.push(lc);
-             if (loopName != null)
-                 this.loopNames.put(loopName, lc);
-         }
 -    public ReferenceMap getNestedLoopNames() {
++    public ReferenceMap<String,Object> getNestedLoopNames() {
+         return loopNames;
      }
- 
+     
      @Override
-     public void incrLoops() {
-         this.nestedLoops.peek().increment();
-     }
- 
-     @Override
-     public void resetLoops() {
-         this.nestedLoops.pop();
+     public TraverserRequirement getLoopRequirement() {
+         return TraverserRequirement.NESTED_LOOP;
      }
  
      /////////////////
@@@ -159,4 -97,10 +99,11 @@@
          return result;
      }
  
+     private void cloneLoopState(final B_NL_O_S_SE_SL_Traverser<?> clone) {
+         clone.nestedLoops = new Stack<>();
 -        clone.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
++        clone.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
++                AbstractReferenceMap.ReferenceStrength.WEAK);
+         copyNestedLoops(clone.nestedLoops, clone.loopNames);
+     }
+ 
  }
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
index ee22c6f5ee,4d78805f51..06b8aea4c0
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
@@@ -19,20 -19,16 +19,17 @@@
  
  package org.apache.tinkerpop.gremlin.process.traversal.traverser;
  
+ import java.util.Objects;
+ import java.util.Stack;
 -import org.apache.commons.collections.map.ReferenceMap;
 +import org.apache.commons.collections4.map.AbstractReferenceMap;
 +import org.apache.commons.collections4.map.ReferenceMap;
  import org.apache.tinkerpop.gremlin.process.traversal.Step;
  import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
  
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.Stack;
- 
- public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends 
LP_O_OB_P_S_SE_SL_Traverser<T> {
+ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends 
LP_O_OB_P_S_SE_SL_Traverser<T> implements NL_SL_Traverser<T> {
  
      protected Stack<LabelledCounter> nestedLoops;
--    protected ReferenceMap loopNames = null;
++    protected ReferenceMap<String,Object> loopNames = null;
  
      protected LP_NL_O_OB_P_S_SE_SL_Traverser() {
      }
@@@ -40,40 -36,17 +37,18 @@@
      public LP_NL_O_OB_P_S_SE_SL_Traverser(final T t, final Step<T, ?> step) {
          super(t, step);
          this.nestedLoops = new Stack<>();
 -        this.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
 +        this.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
 +                AbstractReferenceMap.ReferenceStrength.WEAK);
      }
  
-     /////////////////
- 
-     @Override
-     public int loops() {
-         return this.nestedLoops.peek().count();
-     }
- 
-     @Override
-     public int loops(final String loopName) {
-         if (loopName == null)
-             return loops();
-         else if (this.loopNames.containsKey(loopName))
-             return ((LabelledCounter) this.loopNames.get(loopName)).count();
-         else
-             throw new IllegalArgumentException("Loop name not defined: " + 
loopName);
-     }
- 
      @Override
-     public void initialiseLoops(final String stepLabel, final String 
loopName) {
-         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-             final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
-             this.nestedLoops.push(lc);
-             if (loopName != null)
-                 this.loopNames.put(loopName, lc);
-         }
+     public Stack<LabelledCounter> getNestedLoops() {
+         return nestedLoops;
      }
  
      @Override
-     public void incrLoops() {
-         this.nestedLoops.peek().increment();
 -    public ReferenceMap getNestedLoopNames() {
++    public ReferenceMap<String,Object> getNestedLoopNames() {
+         return loopNames;
      }
  
      @Override
@@@ -164,4 -98,10 +100,11 @@@
          return result;
      }
  
+     private void cloneLoopState(final LP_NL_O_OB_P_S_SE_SL_Traverser<?> 
clone) {
+         clone.nestedLoops = new Stack<>();
 -        clone.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
++        clone.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
++                AbstractReferenceMap.ReferenceStrength.WEAK);
+         copyNestedLoops(clone.nestedLoops, clone.loopNames);
+     }
+ 
  }
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
index 47a8058015,5b86416e32..12073cea2c
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
@@@ -19,20 -19,16 +19,17 @@@
  
  package org.apache.tinkerpop.gremlin.process.traversal.traverser;
  
+ import java.util.Objects;
+ import java.util.Stack;
 -import org.apache.commons.collections.map.ReferenceMap;
 +import org.apache.commons.collections4.map.AbstractReferenceMap;
 +import org.apache.commons.collections4.map.ReferenceMap;
  import org.apache.tinkerpop.gremlin.process.traversal.Step;
  import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
  
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.Stack;
- 
- public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends 
LP_O_OB_S_SE_SL_Traverser<T> {
+ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends 
LP_O_OB_S_SE_SL_Traverser<T> implements NL_SL_Traverser<T> {
  
      protected Stack<LabelledCounter> nestedLoops;
 -    protected ReferenceMap loopNames = null;
 +    protected ReferenceMap<String,Object> loopNames = null;
  
      protected LP_NL_O_OB_S_SE_SL_Traverser() {
      }
@@@ -40,45 -36,17 +37,18 @@@
      public LP_NL_O_OB_S_SE_SL_Traverser(final T t, final Step<T, ?> step) {
          super(t, step);
          this.nestedLoops = new Stack<>();
 -        this.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
 +        this.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
 +                AbstractReferenceMap.ReferenceStrength.WEAK);
      }
  
-     /////////////////
- 
-     @Override
-     public int loops() {
-         return this.nestedLoops.peek().count();
-     }
- 
-     @Override
-     public int loops(final String loopName) {
-         if (loopName == null)
-             return loops();
-         else if (this.loopNames.containsKey(loopName))
-             return ((LabelledCounter) this.loopNames.get(loopName)).count();
-         else
-             throw new IllegalArgumentException("Loop name not defined: " + 
loopName);
-     }
- 
-     @Override
-     public Set<String> getLoopNames() {
-         return loopNames.keySet();
-     }
- 
      @Override
-     public void initialiseLoops(final String stepLabel, final String 
loopName) {
-         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-             final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
-             this.nestedLoops.push(lc);
-             if (loopName != null)
-                 this.loopNames.put(loopName, lc);
-         }
+     public Stack<LabelledCounter> getNestedLoops() {
+         return nestedLoops;
      }
  
      @Override
-     public void incrLoops() {
-         this.nestedLoops.peek().increment();
 -    public ReferenceMap getNestedLoopNames() {
++    public ReferenceMap<String,Object> getNestedLoopNames() {
+         return loopNames;
      }
  
      @Override
@@@ -164,4 -98,10 +100,11 @@@
          return result;
      }
  
+     private void cloneLoopState(final LP_NL_O_OB_S_SE_SL_Traverser<?> clone) {
+         clone.nestedLoops = new Stack<>();
 -        clone.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
++        clone.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
++                AbstractReferenceMap.ReferenceStrength.WEAK);
+         copyNestedLoops(clone.nestedLoops, clone.loopNames);
+     }
+ 
  }
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
index efcda13bdb,9b51ef08e6..92a2abb58a
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
@@@ -19,20 -19,16 +19,17 @@@
  
  package org.apache.tinkerpop.gremlin.process.traversal.traverser;
  
+ import java.util.Objects;
+ import java.util.Stack;
 -import org.apache.commons.collections.map.ReferenceMap;
 +import org.apache.commons.collections4.map.AbstractReferenceMap;
 +import org.apache.commons.collections4.map.ReferenceMap;
  import org.apache.tinkerpop.gremlin.process.traversal.Step;
  import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
  
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.Stack;
- 
- public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> {
+ public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> 
implements NL_SL_Traverser<T> {
  
      protected Stack<LabelledCounter> nestedLoops;
 -    protected ReferenceMap loopNames;
 +    protected ReferenceMap<String,Object> loopNames;
  
      protected NL_O_OB_S_SE_SL_Traverser() {
      }
@@@ -40,40 -36,17 +37,18 @@@
      public NL_O_OB_S_SE_SL_Traverser(final T t, final Step<T, ?> step) {
          super(t, step);
          this.nestedLoops = new Stack<>();
 -        this.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
 +        this.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
 +                AbstractReferenceMap.ReferenceStrength.WEAK);
      }
  
-     /////////////////
- 
-     @Override
-     public int loops() {
-         return this.nestedLoops.peek().count();
-     }
- 
-     @Override
-     public int loops(final String loopName) {
-         if (loopName == null)
-             return loops();
-         else if (this.loopNames.containsKey(loopName))
-             return ((LabelledCounter) this.loopNames.get(loopName)).count();
-         else
-             throw new IllegalArgumentException("Loop name not defined: " + 
loopName);
-     }
- 
      @Override
-     public void initialiseLoops(final String stepLabel, final String 
loopName) {
-         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-             final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
-             this.nestedLoops.push(lc);
-             if (loopName != null)
-                 this.loopNames.put(loopName, lc);
-         }
+     public Stack<LabelledCounter> getNestedLoops() {
+         return nestedLoops;
      }
  
      @Override
-     public void incrLoops() {
-         this.nestedLoops.peek().increment();
 -    public ReferenceMap getNestedLoopNames() {
++    public ReferenceMap<String,Object> getNestedLoopNames() {
+         return loopNames;
      }
  
      @Override
@@@ -164,4 -98,10 +100,11 @@@
          return result;
      }
  
+     private void cloneLoopState(final NL_O_OB_S_SE_SL_Traverser<?> clone) {
+         clone.nestedLoops = new Stack<>();
 -        clone.loopNames = new ReferenceMap(ReferenceMap.HARD, 
ReferenceMap.WEAK);
++        clone.loopNames = new 
ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD,
++                AbstractReferenceMap.ReferenceStrength.WEAK);
+         copyNestedLoops(clone.nestedLoops, clone.loopNames);
+     }
+ 
  }
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_SL_Traverser.java
index 0000000000,e949adc043..8b863edc16
mode 000000,100644..100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_SL_Traverser.java
@@@ -1,0 -1,248 +1,247 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  * http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package org.apache.tinkerpop.gremlin.process.traversal.traverser;
+ 
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.Objects;
+ import java.util.Set;
+ import java.util.Stack;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;
 -import org.apache.commons.collections.map.ReferenceMap;
++import org.apache.commons.collections4.map.ReferenceMap;
+ import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+ import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
+ 
+ import static 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement.NESTED_LOOP;
+ import static 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement.SINGLE_LOOP;
+ 
+ /**
+  * Intermediate helper interface for {@link Traverser}s that support loops. 
Implementations are expected to override 
+  * either the single or nested loop functions depending on the type of loop 
{@link TraverserRequirement} they are using.
+  * <p>
+  * Note: it would be nice to separate the {@link 
TraverserRequirement#SINGLE_LOOP} vs {@link TraverserRequirement#NESTED_LOOP}
+  * logic into different traverser interfaces in the future however the 
current {@link Traverser} class hierarchy makes
+  * that difficult as {@link Traverser}s that support nested loops extend from 
{@link Traverser}s that support single
+  * loops but override all single loop logic with nested loop logic.
+  */
+ public interface NL_SL_Traverser<T> extends Traverser.Admin<T> {
+     /**
+      * @return the supported loop type - either {@link 
TraverserRequirement#NESTED_LOOP} or {@link TraverserRequirement#SINGLE_LOOP}
+      */
+     TraverserRequirement getLoopRequirement();
+ 
+     // NESTED LOOPS
+ 
+     /**
+      * Override this method to support nested loops.
+      *
+      * @return the {@link Stack} of {@link LabelledCounter} which holds the 
nested loops.
+      */
+     default Stack<LabelledCounter> getNestedLoops() {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Override this method to support nested loops.
+      *
+      * @return the {@link ReferenceMap} where key=loop name and 
value=reference to the {@link LabelledCounter}.
+      */
 -    default ReferenceMap getNestedLoopNames() {
++    default ReferenceMap<String,Object> getNestedLoopNames() {
+         throw new UnsupportedOperationException();
+     }
+ 
+     // SINGLE LOOPS
+ 
+     /**
+      * Override this method to support single loop.
+      *
+      * @return the single loop count.
+      */
+     default short getSingleLoopCount() {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Override this method to support single loop. Sets the single loop 
count.
+      */
+     default void setSingleLoopCount(short loops) {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Override this method to support single loop.
+      *
+      * @return the single loop name.
+      */
+     default String getSingleLoopName() {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Override this method to support single loop. Sets the single loop name.
+      */
+     default void setSingleLoopName(final String loopName) {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Override this method to support single loop.
+      *
+      * @return the single loop step label.
+      */
+     default String getSingleLoopStepLabel() {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Override this method to support single loop. Sets the single loop step 
label.
+      */
+     default void setSingleLoopStepLabel(final String stepLabel) {
+         throw new UnsupportedOperationException();
+     }
+ 
+     @Override
+     default void incrLoops() {
+         if (NESTED_LOOP.equals(getValidLoopRequirement())) {
+             getNestedLoops().peek().increment();
+         } else {
+             setSingleLoopCount((short) (getSingleLoopCount() + 1));
+         }
+     }
+ 
+     /**
+      * @return the current loop count for single loops or the latest loop 
count for nested loops.
+      */
+     @Override
+     default int loops() {
+         return loops(null);
+     }
+ 
+     /**
+      * Obtain a loop count for a named loop or for the current loop count for 
single loops or the latest loop count for nested loops.
+      *
+      * @param loopName the optional name applied to the loop
+      * @return the count for the loop identified by the given loopName or 
current loop count for single loops or latest loop for nested loops.
+      */
+     @Override
+     default int loops(final String loopName) {
+         if (NESTED_LOOP.equals(getValidLoopRequirement())) {
+             return getNestedLoopCount(loopName);
+         } else if (loopName == null ||
+                 Objects.equals(loopName, getSingleLoopName()) ||
+                 Objects.equals(loopName, getSingleLoopStepLabel())) {
+             return getSingleLoopCount();
+         }
+         throw new IllegalArgumentException("Single loop name not defined: " + 
loopName);
+     }
+ 
+     /**
+      * Initialises loops depending on the {@link #getLoopRequirement()} loop 
type.
+      *
+      * @param stepLabel the label of the step initialising the loops.
+      * @param loopName  the optional user defined name for referencing the 
loop counter
+      */
+     @Override
+     default void initialiseLoops(final String stepLabel, final String 
loopName) {
+         if (NESTED_LOOP.equals(getValidLoopRequirement())) {
+             initialiseNestedLoops(stepLabel, loopName);
+         } else {
+             setSingleLoopStepLabel(stepLabel);
+             setSingleLoopName(loopName);
+         }
+     }
+ 
+     /**
+      * Resets loops depending on the {@link #getLoopRequirement()} loop type.
+      */
+     @Override
+     default void resetLoops() {
+         if (NESTED_LOOP.equals(getValidLoopRequirement())) {
+             getNestedLoops().pop();
+         } else {
+             setSingleLoopCount((short) 0);
+         }
+     }
+ 
+     /**
+      * @return the loop names that can be used to reference loops.
+      */
+     @Override
+     default Set<String> getLoopNames() {
+         if (NESTED_LOOP.equals(getValidLoopRequirement())) {
+             return getNestedLoopNames().keySet();
+         } else {
+             return Stream.of(getSingleLoopName(), getSingleLoopStepLabel())
+                     .filter(Objects::nonNull)
+                     .collect(Collectors.toSet());
+         }
+     }
+ 
+     default TraverserRequirement getValidLoopRequirement() {
+         final TraverserRequirement loopRequirement = getLoopRequirement();
+         if (!SINGLE_LOOP.equals(loopRequirement) && 
!NESTED_LOOP.equals(loopRequirement)) {
+             throw new IllegalStateException("Invalid loop 
TraverserRequirement " + loopRequirement);
+         }
+         return loopRequirement;
+     }
+ 
+     default void initialiseNestedLoops(final String stepLabel, final String 
loopName) {
+         final Stack<LabelledCounter> nestedLoops = getNestedLoops();
 -        final ReferenceMap loopNames = getNestedLoopNames();
++        final ReferenceMap<String, Object> loopNames = getNestedLoopNames();
+         if (nestedLoops.empty() || !nestedLoops.peek().hasLabel(stepLabel)) {
+             final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+             nestedLoops.push(lc);
+             loopNames.put(stepLabel, lc);
+             if (loopName != null && !loopName.equals(stepLabel)) {
+                 loopNames.put(loopName, lc);
+             }
+         }
+     }
+ 
+     default int getNestedLoopCount(final String loopName) {
+         if (loopName == null) {
+             return getNestedLoops().peek().count();
+         } else if (getNestedLoopNames().containsKey(loopName)) {
+             return ((LabelledCounter) 
getNestedLoopNames().get(loopName)).count();
+         } else {
+             throw new IllegalArgumentException("Nested loop name not defined: 
" + loopName);
+         }
+     }
+ 
 -    default void copyNestedLoops(final Stack<LabelledCounter> 
targetNestedLoops, final ReferenceMap targetLoopNames) {
++    default void copyNestedLoops(final Stack<LabelledCounter> 
targetNestedLoops, final ReferenceMap<String, Object> targetLoopNames) {
+         final Map<LabelledCounter, LabelledCounter> counterMapping = new 
HashMap<>();
+ 
+         for (LabelledCounter original : getNestedLoops()) {
+             final LabelledCounter cloned = (LabelledCounter) original.clone();
+             targetNestedLoops.push(cloned);
+             counterMapping.put(original, cloned);
+         }
+ 
+         if (getNestedLoopNames() != null) {
 -            for (Object entry : getNestedLoopNames().entrySet()) {
 -                final ReferenceMap.Entry pair = (ReferenceMap.Entry) entry;
++            for (Map.Entry<String, Object> pair : 
getNestedLoopNames().entrySet()) {
+                 final LabelledCounter original = (LabelledCounter) 
pair.getValue();
+                 final LabelledCounter cloned = counterMapping.get(original);
+                 if (cloned != null) {
+                     targetLoopNames.put(pair.getKey(), cloned);
+                 }
+             }
+         }
+     }
+ }


Reply via email to