| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 | // Protocol Buffers - Google's data interchange format// Copyright 2008 Google Inc.  All rights reserved.// https://developers.google.com/protocol-buffers///// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met:////     * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.//     * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.//     * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.goog.provide('jspb.Map');goog.require('goog.asserts');goog.forwardDeclare('jspb.BinaryReader');goog.forwardDeclare('jspb.BinaryWriter');/** * Constructs a new Map. A Map is a container that is used to implement map * fields on message objects. It closely follows the ES6 Map API; however, * it is distinct because we do not want to depend on external polyfills or * on ES6 itself. * * This constructor should only be called from generated message code. It is not * intended for general use by library consumers. * * @template K, V * * @param {!Array<!Array<!Object>>} arr * * @param {?function(new:V)|function(new:V,?)=} opt_valueCtor *    The constructor for type V, if type V is a message type. * * @constructor * @struct */jspb.Map = function(arr, opt_valueCtor) {  /** @const @private */  this.arr_ = arr;  /** @const @private */  this.valueCtor_ = opt_valueCtor;  /** @type {!Object<string, !jspb.Map.Entry_<K,V>>} @private */  this.map_ = {};  /**   * Is `this.arr_ updated with respect to `this.map_`?   * @type {boolean}   */  this.arrClean = true;  if (this.arr_.length > 0) {    this.loadFromArray_();  }};/** * Load initial content from underlying array. * @private */jspb.Map.prototype.loadFromArray_ = function() {  for (var i = 0; i < this.arr_.length; i++) {    var record = this.arr_[i];    var key = record[0];    var value = record[1];    this.map_[key.toString()] = new jspb.Map.Entry_(key, value);  }  this.arrClean = true;};/** * Synchronize content to underlying array, if needed, and return it. * @return {!Array<!Array<!Object>>} */jspb.Map.prototype.toArray = function() {  if (this.arrClean) {    if (this.valueCtor_) {      // We need to recursively sync maps in submessages to their arrays.      var m = this.map_;      for (var p in m) {        if (Object.prototype.hasOwnProperty.call(m, p)) {          var valueWrapper = /** @type {?jspb.Message} */ (m[p].valueWrapper);          if (valueWrapper) {            valueWrapper.toArray();          }        }      }    }  } else {    // Delete all elements.    this.arr_.length = 0;    var strKeys = this.stringKeys_();    // Output keys in deterministic (sorted) order.    strKeys.sort();    for (var i = 0; i < strKeys.length; i++) {      var entry = this.map_[strKeys[i]];      var valueWrapper = /** @type {!Object} */ (entry.valueWrapper);      if (valueWrapper) {        valueWrapper.toArray();      }      this.arr_.push([entry.key, entry.value]);    }    this.arrClean = true;  }  return this.arr_;};/** * Returns the map formatted as an array of key-value pairs, suitable for the * toObject() form of a message. * * @param {boolean=} includeInstance Whether to include the JSPB instance for *    transitional soy proto support: http://goto/soy-param-migration * @param {!function((boolean|undefined),!V):!Object=} valueToObject *    The static toObject() method, if V is a message type. * @return {!Array<!Array<!Object>>} */jspb.Map.prototype.toObject = function(includeInstance, valueToObject) {  var rawArray = this.toArray();  var entries = [];  for (var i = 0; i < rawArray.length; i++) {    var entry = this.map_[rawArray[i][0].toString()];    this.wrapEntry_(entry);    var valueWrapper = /** @type {!V|undefined} */ (entry.valueWrapper);    if (valueWrapper) {      goog.asserts.assert(valueToObject);      entries.push([entry.key, valueToObject(includeInstance, valueWrapper)]);    } else {      entries.push([entry.key, entry.value]);    }  }  return entries;};/** * Returns a Map from the given array of key-value pairs when the values are of * message type. The values in the array must match the format returned by their * message type's toObject() method. * * @template K, V * @param {!Array<!Array<!Object>>} entries * @param {!function(new:V)|function(new:V,?)} valueCtor *    The constructor for type V. * @param {!function(!Object):V} valueFromObject *    The fromObject function for type V. * @return {!jspb.Map<K, V>} */jspb.Map.fromObject = function(entries, valueCtor, valueFromObject) {  var result = new jspb.Map([], valueCtor);  for (var i = 0; i < entries.length; i++) {    var key = entries[i][0];    var value = valueFromObject(entries[i][1]);    result.set(key, value);  }  return result;};/** * Helper: an IteratorIterable over an array. * @template T * @param {!Array<T>} arr the array * @implements {IteratorIterable<T>} * @constructor @struct * @private */jspb.Map.ArrayIteratorIterable_ = function(arr) {  /** @type {number} @private */  this.idx_ = 0;  /** @const @private */  this.arr_ = arr;};/** @override @final */jspb.Map.ArrayIteratorIterable_.prototype.next = function() {  if (this.idx_ < this.arr_.length) {    return {done: false, value: this.arr_[this.idx_++]};  } else {    return {done: true, value: undefined};  }};if (typeof(Symbol) != 'undefined') {  /** @override */  jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] = function() {    return this;  };}/** * Returns the map's length (number of key/value pairs). * @return {number} */jspb.Map.prototype.getLength = function() {  return this.stringKeys_().length;};/** * Clears the map. */jspb.Map.prototype.clear = function() {  this.map_ = {};  this.arrClean = false;};/** * Deletes a particular key from the map. * N.B.: differs in name from ES6 Map's `delete` because IE8 does not support * reserved words as property names. * @this {jspb.Map} * @param {K} key * @return {boolean} Whether any entry with this key was deleted. */jspb.Map.prototype.del = function(key) {  var keyValue = key.toString();  var hadKey = this.map_.hasOwnProperty(keyValue);  delete this.map_[keyValue];  this.arrClean = false;  return hadKey;};/** * Returns an array of [key, value] pairs in the map. * * This is redundant compared to the plain entries() method, but we provide this * to help out Angular 1.x users.  Still evaluating whether this is the best * option. * * @return {!Array<!Array<K|V>>} */jspb.Map.prototype.getEntryList = function() {  var entries = [];  var strKeys = this.stringKeys_();  strKeys.sort();  for (var i = 0; i < strKeys.length; i++) {    var entry = this.map_[strKeys[i]];    entries.push([entry.key, entry.value]);  }  return entries;};/** * Returns an iterator-iterable over [key, value] pairs in the map. * Closure compiler sadly doesn't support tuples, ie. Iterator<[K,V]>. * @return {!IteratorIterable<!Array<K|V>>} The iterator-iterable. */jspb.Map.prototype.entries = function() {  var entries = [];  var strKeys = this.stringKeys_();  strKeys.sort();  for (var i = 0; i < strKeys.length; i++) {    var entry = this.map_[strKeys[i]];    entries.push([entry.key, this.wrapEntry_(entry)]);  }  return new jspb.Map.ArrayIteratorIterable_(entries);};/** * Returns an iterator-iterable over keys in the map. * @return {!IteratorIterable<K>} The iterator-iterable. */jspb.Map.prototype.keys = function() {  var keys = [];  var strKeys = this.stringKeys_();  strKeys.sort();  for (var i = 0; i < strKeys.length; i++) {    var entry = this.map_[strKeys[i]];    keys.push(entry.key);  }  return new jspb.Map.ArrayIteratorIterable_(keys);};/** * Returns an iterator-iterable over values in the map. * @return {!IteratorIterable<V>} The iterator-iterable. */jspb.Map.prototype.values = function() {  var values = [];  var strKeys = this.stringKeys_();  strKeys.sort();  for (var i = 0; i < strKeys.length; i++) {    var entry = this.map_[strKeys[i]];    values.push(this.wrapEntry_(entry));  }  return new jspb.Map.ArrayIteratorIterable_(values);};/** * Iterates over entries in the map, calling a function on each. * @template T * @param {function(this:T, V, K, ?jspb.Map<K, V>)} cb * @param {T=} opt_thisArg */jspb.Map.prototype.forEach = function(cb, opt_thisArg) {  var strKeys = this.stringKeys_();  strKeys.sort();  for (var i = 0; i < strKeys.length; i++) {    var entry = this.map_[strKeys[i]];    cb.call(opt_thisArg, this.wrapEntry_(entry), entry.key, this);  }};/** * Sets a key in the map to the given value. * @param {K} key The key * @param {V} value The value * @return {!jspb.Map<K,V>} */jspb.Map.prototype.set = function(key, value) {  var entry = new jspb.Map.Entry_(key);  if (this.valueCtor_) {    entry.valueWrapper = value;    // .toArray() on a message returns a reference to the underlying array    // rather than a copy.    entry.value = value.toArray();  } else {    entry.value = value;  }  this.map_[key.toString()] = entry;  this.arrClean = false;  return this;};/** * Helper: lazily construct a wrapper around an entry, if needed, and return the * user-visible type. * @param {!jspb.Map.Entry_<K,V>} entry * @return {V} * @private */jspb.Map.prototype.wrapEntry_ = function(entry) {  if (this.valueCtor_) {    if (!entry.valueWrapper) {      entry.valueWrapper = new this.valueCtor_(entry.value);    }    return /** @type {V} */ (entry.valueWrapper);  } else {    return entry.value;  }};/** * Gets the value corresponding to a key in the map. * @param {K} key * @return {V|undefined} The value, or `undefined` if key not present */jspb.Map.prototype.get = function(key) {  var keyValue = key.toString();  var entry = this.map_[keyValue];  if (entry) {    return this.wrapEntry_(entry);  } else {    return undefined;  }};/** * Determines whether the given key is present in the map. * @param {K} key * @return {boolean} `true` if the key is present */jspb.Map.prototype.has = function(key) {  var keyValue = key.toString();  return (keyValue in this.map_);};/** * Write this Map field in wire format to a BinaryWriter, using the given field * number. * @param {number} fieldNumber * @param {!jspb.BinaryWriter} writer * @param {!function(this:jspb.BinaryWriter,number,K)} keyWriterFn *     The method on BinaryWriter that writes type K to the stream. * @param {!function(this:jspb.BinaryWriter,number,V)| *          function(this:jspb.BinaryReader,V,?)} valueWriterFn *     The method on BinaryWriter that writes type V to the stream.  May be *     writeMessage, in which case the second callback arg form is used. * @param {function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback *    The BinaryWriter serialization callback for type V, if V is a message *    type. */jspb.Map.prototype.serializeBinary = function(    fieldNumber, writer, keyWriterFn, valueWriterFn, opt_valueWriterCallback) {  var strKeys = this.stringKeys_();  strKeys.sort();  for (var i = 0; i < strKeys.length; i++) {    var entry = this.map_[strKeys[i]];    writer.beginSubMessage(fieldNumber);    keyWriterFn.call(writer, 1, entry.key);    if (this.valueCtor_) {      valueWriterFn.call(writer, 2, this.wrapEntry_(entry),                         opt_valueWriterCallback);    } else {      valueWriterFn.call(writer, 2, entry.value);    }    writer.endSubMessage();  }};/** * Read one key/value message from the given BinaryReader. Compatible as the * `reader` callback parameter to jspb.BinaryReader.readMessage, to be called * when a key/value pair submessage is encountered. * @template K, V * @param {!jspb.Map} map * @param {!jspb.BinaryReader} reader * @param {!function(this:jspb.BinaryReader):K} keyReaderFn *     The method on BinaryReader that reads type K from the stream. * * @param {!function(this:jspb.BinaryReader):V| *          function(this:jspb.BinaryReader,V, *                  function(V,!jspb.BinaryReader))} valueReaderFn *    The method on BinaryReader that reads type V from the stream. May be *    readMessage, in which case the second callback arg form is used. * * @param {?function(V,!jspb.BinaryReader)=} opt_valueReaderCallback *    The BinaryReader parsing callback for type V, if V is a message type. * */jspb.Map.deserializeBinary = function(map, reader, keyReaderFn, valueReaderFn,                                      opt_valueReaderCallback) {  var key = undefined;  var value = undefined;  while (reader.nextField()) {    if (reader.isEndGroup()) {      break;    }    var field = reader.getFieldNumber();    if (field == 1) {      // Key.      key = keyReaderFn.call(reader);    } else if (field == 2) {      // Value.      if (map.valueCtor_) {        value = new map.valueCtor_();        valueReaderFn.call(reader, value, opt_valueReaderCallback);      } else {        value = valueReaderFn.call(reader);      }    }  }  goog.asserts.assert(key != undefined);  goog.asserts.assert(value != undefined);  map.set(key, value);};/** * Helper: compute the list of all stringified keys in the underlying Object * map. * @return {!Array<string>} * @private */jspb.Map.prototype.stringKeys_ = function() {  var m = this.map_;  var ret = [];  for (var p in m) {    if (Object.prototype.hasOwnProperty.call(m, p)) {      ret.push(p);    }  }  return ret;};/** * @param {!K} key The entry's key. * @param {V=} opt_value The entry's value wrapper. * @constructor * @struct * @template K, V * @private */jspb.Map.Entry_ = function(key, opt_value) {  /** @const {K} */  this.key = key;  // The JSPB-serializable value.  For primitive types this will be of type V.  // For message types it will be an array.  /** @type {V} */  this.value = opt_value;  // Only used for submessage values.  /** @type {V} */  this.valueWrapper = undefined;};
 |