• riffle.js

  • ¶
    var cadence = require('cadence')
    
    function Forward (cursor, inclusive) {
        this._cursor = cursor
        this.last = this._cursor.page.right.address == null
        this._inclusive = inclusive
        this._index = null
    }
    
    Forward.prototype.get = function () {
        return this._items[this._index++]
    }
    
    Forward.prototype.next = cadence(function (async) {
        if (this._index === null) {
            var index = this._cursor.index
            this._index = index < 0 ? ~index : this._inclusive ? index : index + 1
            this._items = this._cursor.page.items
            return [ this._index < this._items.length ]
        }
        async(function () {
            this._cursor.next(async())
        }, function (more) {
            if (!more) {
                return [ false ]
            }
            this.last = this._cursor.page.right.address === null
            this._items = this._cursor.page.items
            this._index = this._cursor.page.ghosts
            return [ true ]
        })
    })
    
    Forward.prototype.unlock = function (callback) {
        this._cursor.unlock(callback)
    }
    
    exports.forward = cadence(function (async, strata, key, inclusive) {
        var condition = key == null ? strata.left : strata.key(key)
        inclusive = inclusive == null ? true : inclusive
        async(function () {
            strata.iterator(condition, async())
        }, function (cursor) {
            return new Forward(cursor, inclusive)
        })
    })
    
    function Reverse (strata, cursor, inclusive) {
        var index = cursor.index
        this._strata = strata
        this._cursor = cursor
        this._index = null
        this._inclusive = inclusive
        this.last = false
    }
    
    Reverse.prototype.get = function () {
        if (this._index < this._ghosts) {
            return null
        }
        return this._items[this._index--]
    }
    
    Reverse.prototype.next = cadence(function (async) {
        if (this._index !== null && this._cursor.page.address == 1) {
            return [ false ]
        }
        if (this._index === null) {
            var index = this._cursor.index
            index = index < 0 ? ~index - 1 : this._inclusive ? index : index - 1
            if (index < this._cursor.page.ghosts && this._cursor.page.address === 1) {
                this._index = -1
                return [ false ]
            }
            this._items = this._cursor.page.items
            this._index = index
            return [ true ]
        }
        var address = this._cursor.page.address, key
        async(function () {
            key = this._cursor.page.items[0].key
            async(function () {
                this._cursor.unlock(async())
            }, function () {
                exports._racer(key, async())
            }, function () {
                this._strata.iterator(this._strata.leftOf(key), async())
            })
        }, function (cursor) {
            this.last = cursor.page.address === 1
            this._cursor = cursor
            this._items = cursor.page.items
            this._ghosts = cursor.page.ghosts
            if (this._cursor.page.right.address === address) {
                this._index = this._cursor.page.items.length - 1
            } else {
                var index = this._cursor.index
                this._index = (index < 0 ? ~index : index) - 1
            }
            return [ true ]
        })
    })
    
    Reverse.prototype.unlock = function (callback) {
        this._cursor.unlock(callback)
    }
    
    exports.reverse = cadence(function (async, strata, key, inclusive) {
        inclusive = inclusive == null ? true : inclusive
        var condition = key == null ? strata.right : strata.key(key)
        async(function () {
            strata.iterator(condition, async())
        }, function (cursor) {
            return new Reverse(strata, cursor, inclusive)
        })
    })
    
    exports._racer = function (key, callback) { callback() }