class NestedIterator extends WrappedIterator<Edge> {

    private final int MAX_CACHED_COUNT = 1000;
    /**
     * Set<Id> visited: visited vertex-ids of all parent-tree
     * used to exclude visited vertex
     */
    private final boolean nearest;
    private final Set<Id> visited;
    private final int MAX_VISITED_COUNT = 100000;

    // cache for edges, initial capacity to avoid memory fragment
    private final List<HugeEdge> cache;
    private final Map<Long, Integer> parentEdgePointerMap;

    private final Iterator<Edge> parentIterator;
    private final HugeTraverser traverser;
    private final Steps steps;
    private final ObjectIntMapping<Id> idMapping;
    private HugeEdge currentEdge;
    private int cachePointer;
    private Iterator<Edge> currentIterator;

    public NestedIterator(HugeTraverser traverser,
                          Iterator<Edge> parentIterator,
                          Steps steps,
                          Set<Id> visited,
                          boolean nearest) {
        this.traverser = traverser;
        this.parentIterator = parentIterator;
        this.steps = steps;
        this.visited = visited;
        this.nearest = nearest;

        this.cache = new ArrayList<>(MAX_CACHED_COUNT);
        this.parentEdgePointerMap = new HashMap<>();

        this.cachePointer = 0;
        this.currentEdge = null;
        this.currentIterator = null;

        this.idMapping = ObjectIntMappingFactory.newObjectIntMapping(false);
    }

    private static Long makeVertexPairIndex(int source, int target) {
        return ((long) source & 0xFFFFFFFFL) |
               (((long) target << 32) & 0xFFFFFFFF00000000L);
    }

    @Override
    public boolean hasNext() {
        if (this.currentIterator == null || !this.currentIterator.hasNext()) {
            return fetch();
        }
        return true;
    }

    @Override
    public Edge next() {
        return this.currentIterator.next();
    }

    @Override
    protected Iterator<?> originIterator() {
        return this.parentIterator;
    }

    @Override
    protected boolean fetch() {
        while (this.currentIterator == null || !this.currentIterator.hasNext()) {
            if (this.currentIterator != null) {
                this.currentIterator = null;
            }

            if (this.cache.size() == this.cachePointer && !this.fillCache()) {
                return false;
            }

            this.currentEdge = this.cache.get(this.cachePointer);
            this.cachePointer++;
            this.currentIterator =
                    traverser.edgesOfVertex(this.currentEdge.id().otherVertexId(), steps);
            this.traverser.vertexIterCounter.addAndGet(1L);

        }
        return true;
    }

    private boolean fillCache() {
        // fill cache from parent
        while (this.parentIterator.hasNext() && this.cache.size() < MAX_CACHED_COUNT) {
            HugeEdge edge = (HugeEdge) this.parentIterator.next();
            Id vertexId = edge.id().otherVertexId();

            this.traverser.edgeIterCounter.addAndGet(1L);

            if (!this.nearest || !this.visited.contains(vertexId)) {
                // update parent edge cache pointer
                int parentEdgePointer = -1;
                if (this.parentIterator instanceof NestedIterator) {
                    parentEdgePointer = ((NestedIterator) this.parentIterator).currentEdgePointer();
                }

                this.parentEdgePointerMap.put(makeEdgeIndex(edge), parentEdgePointer);

                this.cache.add(edge);
                if (this.visited.size() < MAX_VISITED_COUNT) {
                    this.visited.add(vertexId);
                }
            }
        }
        return this.cache.size() > this.cachePointer;
    }

    public List<HugeEdge> pathEdges() {
        List<HugeEdge> edges = new ArrayList<>();
        HugeEdge currentEdge = this.currentEdge;
        if (this.parentIterator instanceof NestedIterator) {
            NestedIterator parent = (NestedIterator) this.parentIterator;
            int parentEdgePointer = this.parentEdgePointerMap.get(makeEdgeIndex(currentEdge));
            edges.addAll(parent.pathEdges(parentEdgePointer));
        }
        edges.add(currentEdge);
        return edges;
    }

    private List<HugeEdge> pathEdges(int edgePointer) {<FILL_FUNCTION_BODY>}

    public int currentEdgePointer() {
        return this.cachePointer - 1;
    }

    private Long makeEdgeIndex(HugeEdge edge) {
        int sourceV = this.code(edge.id().ownerVertexId());
        int targetV = this.code(edge.id().otherVertexId());
        return makeVertexPairIndex(sourceV, targetV);
    }

    private int code(Id id) {
        if (id.number()) {
            long l = id.asLong();
            if (0 <= l && l <= Integer.MAX_VALUE) {
                return (int) l;
            }
        }
        int code = this.idMapping.object2Code(id);
        assert code > 0;
        return -code;
    }
}

        List<HugeEdge> edges = new ArrayList<>();
        HugeEdge edge = this.cache.get(edgePointer);
        if (this.parentIterator instanceof NestedIterator) {
            NestedIterator parent = (NestedIterator) this.parentIterator;
            int parentEdgePointer = this.parentEdgePointerMap.get(makeEdgeIndex(edge));
            edges.addAll(parent.pathEdges(parentEdgePointer));
        }
        edges.add(edge);
        return edges;
    
<no_super_class>