Cursor.java 3.1 KB
Newer Older
1
/*
Thomas Mueller's avatar
Thomas Mueller committed
2
 * Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * Version 1.0, and under the Eclipse Public License, Version 1.0
 * (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.mvstore;

import java.util.Iterator;

/**
 * A cursor to iterate over elements in ascending order.
 *
 * @param <K> the key type
 */
public class Cursor<K> implements Iterator<K> {

18 19 20 21
    private final MVMap<K, ?> map;
    private final K from;
    private CursorPos pos;
    private K current;
22 23 24
    private final Page root;
    private boolean initialized;

25
    Cursor(MVMap<K, ?> map, Page root, K from) {
26 27 28 29 30
        this.map = map;
        this.root = root;
        this.from = from;
    }

31
    @Override
32 33 34 35 36 37 38 39 40
    public boolean hasNext() {
        if (!initialized) {
            min(root, from);
            initialized = true;
            fetchNext();
        }
        return current != null;
    }

41 42 43 44 45 46 47 48
    @Override
    public K next() {
        hasNext();
        K c = current;
        fetchNext();
        return c;
    }

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    /**
     * Skip over that many entries. This method is relatively fast (for this map
     * implementation) even if many entries need to be skipped.
     *
     * @param n the number of entries to skip
     */
    public void skip(long n) {
        if (!hasNext()) {
            return;
        }
        if (n < 10) {
            while (n-- > 0) {
                fetchNext();
            }
            return;
        }
        long index = map.getKeyIndex(current);
        K k = map.getKey(index + n);
67
        pos = null;
68 69 70 71
        min(root, k);
        fetchNext();
    }

72
    @Override
73
    public void remove() {
74 75
        throw DataUtils.newUnsupportedOperationException(
                "Removing is not supported");
76 77 78 79
    }

    /**
     * Fetch the next entry that is equal or larger than the given key, starting
80
     * from the given page. This method retains the stack.
81 82 83 84
     *
     * @param p the page to start
     * @param from the key to search
     */
85
    private void min(Page p, K from) {
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
        while (true) {
            if (p.isLeaf()) {
                int x = from == null ? 0 : p.binarySearch(from);
                if (x < 0) {
                    x = -x - 1;
                }
                pos = new CursorPos(p, x, pos);
                break;
            }
            int x = from == null ? -1 : p.binarySearch(from);
            if (x < 0) {
                x = -x - 1;
            } else {
                x++;
            }
            pos = new CursorPos(p, x + 1, pos);
            p = p.getChildPage(x);
        }
    }

    /**
     * Fetch the next entry if there is one.
     */
    @SuppressWarnings("unchecked")
110
    private void fetchNext() {
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        while (pos != null) {
            if (pos.index < pos.page.getKeyCount()) {
                current = (K) pos.page.getKey(pos.index++);
                return;
            }
            pos = pos.parent;
            if (pos == null) {
                break;
            }
            if (pos.index < map.getChildPageCount(pos.page)) {
                min(pos.page.getChildPage(pos.index++), null);
            }
        }
        current = null;
    }

}