1goog.module('protobuf.runtime.BinaryStorage'); 2 3const Storage = goog.require('protobuf.runtime.Storage'); 4const {checkDefAndNotNull} = goog.require('protobuf.internal.checks'); 5 6/** 7 * Class storing all the fields of a binary protobuf message. 8 * 9 * @package 10 * @template FieldType 11 * @implements {Storage} 12 */ 13class BinaryStorage { 14 /** 15 * @param {number=} pivot 16 */ 17 constructor(pivot = Storage.DEFAULT_PIVOT) { 18 /** 19 * Fields having a field number no greater than the pivot value are stored 20 * into an array for fast access. A field with field number X is stored into 21 * the array position X - 1. 22 * 23 * @private @const {!Array<!FieldType|undefined>} 24 */ 25 this.array_ = new Array(pivot); 26 27 /** 28 * Fields having a field number higher than the pivot value are stored into 29 * the map. We create the map only when it's needed, since even an empty map 30 * takes up a significant amount of memory. 31 * 32 * @private {?Map<number, !FieldType>} 33 */ 34 this.map_ = null; 35 } 36 37 /** 38 * Fields having a field number no greater than the pivot value are stored 39 * into an array for fast access. A field with field number X is stored into 40 * the array position X - 1. 41 * @return {number} 42 * @override 43 */ 44 getPivot() { 45 return this.array_.length; 46 } 47 48 /** 49 * Sets a field in the specified field number. 50 * 51 * @param {number} fieldNumber 52 * @param {!FieldType} field 53 * @override 54 */ 55 set(fieldNumber, field) { 56 if (fieldNumber <= this.getPivot()) { 57 this.array_[fieldNumber - 1] = field; 58 } else { 59 if (this.map_) { 60 this.map_.set(fieldNumber, field); 61 } else { 62 this.map_ = new Map([[fieldNumber, field]]); 63 } 64 } 65 } 66 67 /** 68 * Returns a field at the specified field number. 69 * 70 * @param {number} fieldNumber 71 * @return {!FieldType|undefined} 72 * @override 73 */ 74 get(fieldNumber) { 75 if (fieldNumber <= this.getPivot()) { 76 return this.array_[fieldNumber - 1]; 77 } else { 78 return this.map_ ? this.map_.get(fieldNumber) : undefined; 79 } 80 } 81 82 /** 83 * Deletes a field from the specified field number. 84 * 85 * @param {number} fieldNumber 86 * @override 87 */ 88 delete(fieldNumber) { 89 if (fieldNumber <= this.getPivot()) { 90 delete this.array_[fieldNumber - 1]; 91 } else { 92 if (this.map_) { 93 this.map_.delete(fieldNumber); 94 } 95 } 96 } 97 98 /** 99 * Executes the provided function once for each field. 100 * 101 * @param {function(!FieldType, number): void} callback 102 * @override 103 */ 104 forEach(callback) { 105 this.array_.forEach((field, fieldNumber) => { 106 if (field) { 107 callback(checkDefAndNotNull(field), fieldNumber + 1); 108 } 109 }); 110 if (this.map_) { 111 this.map_.forEach(callback); 112 } 113 } 114 115 /** 116 * Creates a shallow copy of the storage. 117 * 118 * @return {!BinaryStorage} 119 * @override 120 */ 121 shallowCopy() { 122 const copy = new BinaryStorage(this.getPivot()); 123 this.forEach( 124 (field, fieldNumber) => 125 void copy.set(fieldNumber, field.shallowCopy())); 126 return copy; 127 } 128} 129 130exports = BinaryStorage; 131