diff --git a/src/ol/structs/rbush.js b/src/ol/structs/rbush.js index dc6d3dfb97..36d86329b7 100644 --- a/src/ol/structs/rbush.js +++ b/src/ol/structs/rbush.js @@ -189,6 +189,12 @@ ol.structs.RBush = function(opt_maxEntries) { */ this.valueExtent_ = {}; + /** + * @private + * @type {number} + */ + this.readers_ = 0; + }; @@ -387,7 +393,12 @@ ol.structs.RBush.prototype.condense_ = function(path) { * @template S */ ol.structs.RBush.prototype.forEach = function(callback, opt_obj) { - return this.forEach_(this.root_, callback, opt_obj); + ++this.readers_; + try { + return this.forEach_(this.root_, callback, opt_obj); + } finally { + --this.readers_; + } }; @@ -432,6 +443,25 @@ ol.structs.RBush.prototype.forEach_ = function(node, callback, opt_obj) { */ ol.structs.RBush.prototype.forEachInExtent = function(extent, callback, opt_obj) { + ++this.readers_; + try { + return this.forEachInExtent_(extent, callback, opt_obj); + } finally { + --this.readers_; + } +}; + + +/** + * @param {ol.Extent} extent Extent. + * @param {function(this: S, T): *} callback Callback. + * @param {S=} opt_obj Scope. + * @private + * @return {*} Callback return value. + * @template S + */ +ol.structs.RBush.prototype.forEachInExtent_ = + function(extent, callback, opt_obj) { /** @type {Array.>} */ var toVisit = [this.root_]; var result; @@ -496,6 +526,9 @@ ol.structs.RBush.prototype.getKey_ = function(value) { * @param {T} value Value. */ ol.structs.RBush.prototype.insert = function(extent, value) { + if (this.readers_) { + throw Error('cannot insert value while reading'); + } var key = this.getKey_(value); goog.asserts.assert(!this.valueExtent_.hasOwnProperty(key)); this.insert_(extent, value, this.root_.height - 1); @@ -535,6 +568,9 @@ ol.structs.RBush.prototype.insert_ = function(extent, value, level) { * @param {T} value Value. */ ol.structs.RBush.prototype.remove = function(value) { + if (this.readers_) { + throw Error('cannot remove value while reading'); + } var key = this.getKey_(value); goog.asserts.assert(this.valueExtent_.hasOwnProperty(key)); var extent = this.valueExtent_[key]; @@ -629,6 +665,9 @@ ol.structs.RBush.prototype.splitRoot_ = function(node1, node2) { * @param {T} value Value. */ ol.structs.RBush.prototype.update = function(extent, value) { + if (this.readers_) { + throw Error('cannot update value while reading'); + } var key = this.getKey_(value); var currentExtent = this.valueExtent_[key]; goog.asserts.assert(goog.isDef(currentExtent)); diff --git a/test/spec/ol/structs/rbush.js b/test/spec/ol/structs/rbush.js index 7549662134..473126ac09 100644 --- a/test/spec/ol/structs/rbush.js +++ b/test/spec/ol/structs/rbush.js @@ -55,6 +55,27 @@ describe('ol.structs.RBush', function() { }); + describe('#insert', function() { + + it('throws an exception if called while iterating over all values', + function() { + expect(function() { + rBush.forEach(function(value) { + rBush.insert([0, 0, 1, 1], {}); + }); + }).to.throwException(); + }); + + it('throws an exception if called while iterating over an extent', + function() { + expect(function() { + rBush.forEachInExtent([-10, -10, 10, 10], function(value) { + rBush.insert([0, 0, 1, 1], {}); + }); + }).to.throwException(); + }); + }); + describe('#remove', function() { it('can remove each object', function() { @@ -66,6 +87,45 @@ describe('ol.structs.RBush', function() { } }); + it('throws an exception if called while iterating over all values', + function() { + expect(function() { + rBush.forEach(function(value) { + rBush.remove(value); + }); + }).to.throwException(); + }); + + it('throws an exception if called while iterating over an extent', + function() { + expect(function() { + rBush.forEachInExtent([-10, -10, 10, 10], function(value) { + rBush.remove(value); + }); + }).to.throwException(); + }); + + }); + + describe('#update', function() { + + it('throws an exception if called while iterating over all values', + function() { + expect(function() { + rBush.forEach(function(value) { + rBush.update([0, 0, 1, 1], objs[1]); + }); + }).to.throwException(); + }); + + it('throws an exception if called while iterating over an extent', + function() { + expect(function() { + rBush.forEachInExtent([-10, -10, 10, 10], function(value) { + rBush.update([0, 0, 1, 1], objs[1]); + }); + }).to.throwException(); + }); }); });