parent
422053f3bc
commit
da1c46401b
6 changed files with 178 additions and 113 deletions
@ -0,0 +1,130 @@ |
||||
goog.module('protobuf.runtime.BinaryStorage'); |
||||
|
||||
const Storage = goog.require('protobuf.runtime.Storage'); |
||||
const {checkDefAndNotNull} = goog.require('protobuf.internal.checks'); |
||||
|
||||
/** |
||||
* Class storing all the fields of a binary protobuf message. |
||||
* |
||||
* @package |
||||
* @template FieldType |
||||
* @implements {Storage} |
||||
*/ |
||||
class BinaryStorage { |
||||
/** |
||||
* @param {number=} pivot |
||||
*/ |
||||
constructor(pivot = Storage.DEFAULT_PIVOT) { |
||||
/** |
||||
* Fields having a field number no greater than the pivot value are stored |
||||
* into an array for fast access. A field with field number X is stored into |
||||
* the array position X - 1. |
||||
* |
||||
* @private @const {!Array<!FieldType|undefined>} |
||||
*/ |
||||
this.array_ = new Array(pivot); |
||||
|
||||
/** |
||||
* Fields having a field number higher than the pivot value are stored into |
||||
* the map. We create the map only when it's needed, since even an empty map |
||||
* takes up a significant amount of memory. |
||||
* |
||||
* @private {?Map<number, !FieldType>} |
||||
*/ |
||||
this.map_ = null; |
||||
} |
||||
|
||||
/** |
||||
* Fields having a field number no greater than the pivot value are stored |
||||
* into an array for fast access. A field with field number X is stored into |
||||
* the array position X - 1. |
||||
* @return {number} |
||||
* @override |
||||
*/ |
||||
getPivot() { |
||||
return this.array_.length; |
||||
} |
||||
|
||||
/** |
||||
* Sets a field in the specified field number. |
||||
* |
||||
* @param {number} fieldNumber |
||||
* @param {!FieldType} field |
||||
* @override |
||||
*/ |
||||
set(fieldNumber, field) { |
||||
if (fieldNumber <= this.getPivot()) { |
||||
this.array_[fieldNumber - 1] = field; |
||||
} else { |
||||
if (this.map_) { |
||||
this.map_.set(fieldNumber, field); |
||||
} else { |
||||
this.map_ = new Map([[fieldNumber, field]]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a field at the specified field number. |
||||
* |
||||
* @param {number} fieldNumber |
||||
* @return {!FieldType|undefined} |
||||
* @override |
||||
*/ |
||||
get(fieldNumber) { |
||||
if (fieldNumber <= this.getPivot()) { |
||||
return this.array_[fieldNumber - 1]; |
||||
} else { |
||||
return this.map_ ? this.map_.get(fieldNumber) : undefined; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Deletes a field from the specified field number. |
||||
* |
||||
* @param {number} fieldNumber |
||||
* @override |
||||
*/ |
||||
delete(fieldNumber) { |
||||
if (fieldNumber <= this.getPivot()) { |
||||
delete this.array_[fieldNumber - 1]; |
||||
} else { |
||||
if (this.map_) { |
||||
this.map_.delete(fieldNumber); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Executes the provided function once for each field. |
||||
* |
||||
* @param {function(!FieldType, number): void} callback |
||||
* @override |
||||
*/ |
||||
forEach(callback) { |
||||
this.array_.forEach((field, fieldNumber) => { |
||||
if (field) { |
||||
callback(checkDefAndNotNull(field), fieldNumber + 1); |
||||
} |
||||
}); |
||||
if (this.map_) { |
||||
this.map_.forEach(callback); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a shallow copy of the storage. |
||||
* |
||||
* @return {!BinaryStorage} |
||||
* @override |
||||
*/ |
||||
shallowCopy() { |
||||
const copy = new BinaryStorage(this.getPivot()); |
||||
this.forEach( |
||||
(field, fieldNumber) => |
||||
void copy.set(fieldNumber, field.shallowCopy())); |
||||
return copy; |
||||
} |
||||
} |
||||
|
||||
exports = BinaryStorage; |
Loading…
Reference in new issue