1ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format
2ffe3c632Sopenharmony_ci// Copyright 2008 Google Inc.  All rights reserved.
3ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/
4ffe3c632Sopenharmony_ci//
5ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
6ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are
7ffe3c632Sopenharmony_ci// met:
8ffe3c632Sopenharmony_ci//
9ffe3c632Sopenharmony_ci//     * Redistributions of source code must retain the above copyright
10ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer.
11ffe3c632Sopenharmony_ci//     * Redistributions in binary form must reproduce the above
12ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer
13ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the
14ffe3c632Sopenharmony_ci// distribution.
15ffe3c632Sopenharmony_ci//     * Neither the name of Google Inc. nor the names of its
16ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from
17ffe3c632Sopenharmony_ci// this software without specific prior written permission.
18ffe3c632Sopenharmony_ci//
19ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30ffe3c632Sopenharmony_ci
31ffe3c632Sopenharmony_cigoog.provide('jspb.Map');
32ffe3c632Sopenharmony_ci
33ffe3c632Sopenharmony_cigoog.require('goog.asserts');
34ffe3c632Sopenharmony_ci
35ffe3c632Sopenharmony_cigoog.requireType('jspb.BinaryReader');
36ffe3c632Sopenharmony_cigoog.requireType('jspb.BinaryWriter');
37ffe3c632Sopenharmony_ci
38ffe3c632Sopenharmony_ci
39ffe3c632Sopenharmony_ci
40ffe3c632Sopenharmony_ci/**
41ffe3c632Sopenharmony_ci * Constructs a new Map. A Map is a container that is used to implement map
42ffe3c632Sopenharmony_ci * fields on message objects. It closely follows the ES6 Map API; however,
43ffe3c632Sopenharmony_ci * it is distinct because we do not want to depend on external polyfills or
44ffe3c632Sopenharmony_ci * on ES6 itself.
45ffe3c632Sopenharmony_ci *
46ffe3c632Sopenharmony_ci * This constructor should only be called from generated message code. It is not
47ffe3c632Sopenharmony_ci * intended for general use by library consumers.
48ffe3c632Sopenharmony_ci *
49ffe3c632Sopenharmony_ci * @template K, V
50ffe3c632Sopenharmony_ci *
51ffe3c632Sopenharmony_ci * @param {!Array<!Array<?>>} arr
52ffe3c632Sopenharmony_ci *
53ffe3c632Sopenharmony_ci * @param {?function(new:V, ?=)=} opt_valueCtor
54ffe3c632Sopenharmony_ci *    The constructor for type V, if type V is a message type.
55ffe3c632Sopenharmony_ci *
56ffe3c632Sopenharmony_ci * @constructor
57ffe3c632Sopenharmony_ci * @struct
58ffe3c632Sopenharmony_ci */
59ffe3c632Sopenharmony_cijspb.Map = function(arr, opt_valueCtor) {
60ffe3c632Sopenharmony_ci  /** @const @private */
61ffe3c632Sopenharmony_ci  this.arr_ = arr;
62ffe3c632Sopenharmony_ci  /** @const @private */
63ffe3c632Sopenharmony_ci  this.valueCtor_ = opt_valueCtor;
64ffe3c632Sopenharmony_ci
65ffe3c632Sopenharmony_ci  /** @type {!Object<string, !jspb.Map.Entry_<K,V>>} @private */
66ffe3c632Sopenharmony_ci  this.map_ = {};
67ffe3c632Sopenharmony_ci
68ffe3c632Sopenharmony_ci  /**
69ffe3c632Sopenharmony_ci   * Is `this.arr_ updated with respect to `this.map_`?
70ffe3c632Sopenharmony_ci   * @type {boolean}
71ffe3c632Sopenharmony_ci   */
72ffe3c632Sopenharmony_ci  this.arrClean = true;
73ffe3c632Sopenharmony_ci
74ffe3c632Sopenharmony_ci  if (this.arr_.length > 0) {
75ffe3c632Sopenharmony_ci    this.loadFromArray_();
76ffe3c632Sopenharmony_ci  }
77ffe3c632Sopenharmony_ci};
78ffe3c632Sopenharmony_ci
79ffe3c632Sopenharmony_ci
80ffe3c632Sopenharmony_ci/**
81ffe3c632Sopenharmony_ci * Load initial content from underlying array.
82ffe3c632Sopenharmony_ci * @private
83ffe3c632Sopenharmony_ci */
84ffe3c632Sopenharmony_cijspb.Map.prototype.loadFromArray_ = function() {
85ffe3c632Sopenharmony_ci  for (var i = 0; i < this.arr_.length; i++) {
86ffe3c632Sopenharmony_ci    var record = this.arr_[i];
87ffe3c632Sopenharmony_ci    var key = record[0];
88ffe3c632Sopenharmony_ci    var value = record[1];
89ffe3c632Sopenharmony_ci    this.map_[key.toString()] = new jspb.Map.Entry_(key, value);
90ffe3c632Sopenharmony_ci  }
91ffe3c632Sopenharmony_ci  this.arrClean = true;
92ffe3c632Sopenharmony_ci};
93ffe3c632Sopenharmony_ci
94ffe3c632Sopenharmony_ci
95ffe3c632Sopenharmony_ci/**
96ffe3c632Sopenharmony_ci * Synchronize content to underlying array, if needed, and return it.
97ffe3c632Sopenharmony_ci * @return {!Array<!Array<!Object>>}
98ffe3c632Sopenharmony_ci */
99ffe3c632Sopenharmony_cijspb.Map.prototype.toArray = function() {
100ffe3c632Sopenharmony_ci  if (this.arrClean) {
101ffe3c632Sopenharmony_ci    if (this.valueCtor_) {
102ffe3c632Sopenharmony_ci      // We need to recursively sync maps in submessages to their arrays.
103ffe3c632Sopenharmony_ci      var m = this.map_;
104ffe3c632Sopenharmony_ci      for (var p in m) {
105ffe3c632Sopenharmony_ci        if (Object.prototype.hasOwnProperty.call(m, p)) {
106ffe3c632Sopenharmony_ci          var valueWrapper = /** @type {?jspb.Message} */ (m[p].valueWrapper);
107ffe3c632Sopenharmony_ci          if (valueWrapper) {
108ffe3c632Sopenharmony_ci            valueWrapper.toArray();
109ffe3c632Sopenharmony_ci          }
110ffe3c632Sopenharmony_ci        }
111ffe3c632Sopenharmony_ci      }
112ffe3c632Sopenharmony_ci    }
113ffe3c632Sopenharmony_ci  } else {
114ffe3c632Sopenharmony_ci    // Delete all elements.
115ffe3c632Sopenharmony_ci    this.arr_.length = 0;
116ffe3c632Sopenharmony_ci    var strKeys = this.stringKeys_();
117ffe3c632Sopenharmony_ci    // Output keys in deterministic (sorted) order.
118ffe3c632Sopenharmony_ci    strKeys.sort();
119ffe3c632Sopenharmony_ci    for (var i = 0; i < strKeys.length; i++) {
120ffe3c632Sopenharmony_ci      var entry = this.map_[strKeys[i]];
121ffe3c632Sopenharmony_ci      var valueWrapper = /** @type {?jspb.Message} */ (entry.valueWrapper);
122ffe3c632Sopenharmony_ci      if (valueWrapper) {
123ffe3c632Sopenharmony_ci        valueWrapper.toArray();
124ffe3c632Sopenharmony_ci      }
125ffe3c632Sopenharmony_ci      this.arr_.push([entry.key, entry.value]);
126ffe3c632Sopenharmony_ci    }
127ffe3c632Sopenharmony_ci    this.arrClean = true;
128ffe3c632Sopenharmony_ci  }
129ffe3c632Sopenharmony_ci  return this.arr_;
130ffe3c632Sopenharmony_ci};
131ffe3c632Sopenharmony_ci
132ffe3c632Sopenharmony_ci
133ffe3c632Sopenharmony_ci/**
134ffe3c632Sopenharmony_ci * Returns the map formatted as an array of key-value pairs, suitable for the
135ffe3c632Sopenharmony_ci * toObject() form of a message.
136ffe3c632Sopenharmony_ci *
137ffe3c632Sopenharmony_ci * @param {boolean=} includeInstance Whether to include the JSPB instance for
138ffe3c632Sopenharmony_ci *    transitional soy proto support: http://goto/soy-param-migration
139ffe3c632Sopenharmony_ci * @param {function((boolean|undefined),V):!Object=} valueToObject
140ffe3c632Sopenharmony_ci *    The static toObject() method, if V is a message type.
141ffe3c632Sopenharmony_ci * @return {!Array<!Array<!Object>>}
142ffe3c632Sopenharmony_ci */
143ffe3c632Sopenharmony_cijspb.Map.prototype.toObject = function(includeInstance, valueToObject) {
144ffe3c632Sopenharmony_ci  var rawArray = this.toArray();
145ffe3c632Sopenharmony_ci  var entries = [];
146ffe3c632Sopenharmony_ci  for (var i = 0; i < rawArray.length; i++) {
147ffe3c632Sopenharmony_ci    var entry = this.map_[rawArray[i][0].toString()];
148ffe3c632Sopenharmony_ci    this.wrapEntry_(entry);
149ffe3c632Sopenharmony_ci    var valueWrapper = /** @type {V|undefined} */ (entry.valueWrapper);
150ffe3c632Sopenharmony_ci    if (valueWrapper) {
151ffe3c632Sopenharmony_ci      goog.asserts.assert(valueToObject);
152ffe3c632Sopenharmony_ci      entries.push([entry.key, valueToObject(includeInstance, valueWrapper)]);
153ffe3c632Sopenharmony_ci    } else {
154ffe3c632Sopenharmony_ci      entries.push([entry.key, entry.value]);
155ffe3c632Sopenharmony_ci    }
156ffe3c632Sopenharmony_ci  }
157ffe3c632Sopenharmony_ci  return entries;
158ffe3c632Sopenharmony_ci};
159ffe3c632Sopenharmony_ci
160ffe3c632Sopenharmony_ci
161ffe3c632Sopenharmony_ci/**
162ffe3c632Sopenharmony_ci * Returns a Map from the given array of key-value pairs when the values are of
163ffe3c632Sopenharmony_ci * message type. The values in the array must match the format returned by their
164ffe3c632Sopenharmony_ci * message type's toObject() method.
165ffe3c632Sopenharmony_ci *
166ffe3c632Sopenharmony_ci * @template K, V
167ffe3c632Sopenharmony_ci * @param {!Array<!Array<!Object>>} entries
168ffe3c632Sopenharmony_ci * @param {function(new:V,?=)} valueCtor
169ffe3c632Sopenharmony_ci *    The constructor for type V.
170ffe3c632Sopenharmony_ci * @param {function(!Object):V} valueFromObject
171ffe3c632Sopenharmony_ci *    The fromObject function for type V.
172ffe3c632Sopenharmony_ci * @return {!jspb.Map<K, V>}
173ffe3c632Sopenharmony_ci */
174ffe3c632Sopenharmony_cijspb.Map.fromObject = function(entries, valueCtor, valueFromObject) {
175ffe3c632Sopenharmony_ci  var result = new jspb.Map([], valueCtor);
176ffe3c632Sopenharmony_ci  for (var i = 0; i < entries.length; i++) {
177ffe3c632Sopenharmony_ci    var key = entries[i][0];
178ffe3c632Sopenharmony_ci    var value = valueFromObject(entries[i][1]);
179ffe3c632Sopenharmony_ci    result.set(key, value);
180ffe3c632Sopenharmony_ci  }
181ffe3c632Sopenharmony_ci  return result;
182ffe3c632Sopenharmony_ci};
183ffe3c632Sopenharmony_ci
184ffe3c632Sopenharmony_ci
185ffe3c632Sopenharmony_ci/**
186ffe3c632Sopenharmony_ci * Helper: an IteratorIterable over an array.
187ffe3c632Sopenharmony_ci * @template T
188ffe3c632Sopenharmony_ci * @param {!Array<T>} arr the array
189ffe3c632Sopenharmony_ci * @implements {IteratorIterable<T>}
190ffe3c632Sopenharmony_ci * @constructor @struct
191ffe3c632Sopenharmony_ci * @private
192ffe3c632Sopenharmony_ci */
193ffe3c632Sopenharmony_cijspb.Map.ArrayIteratorIterable_ = function(arr) {
194ffe3c632Sopenharmony_ci  /** @type {number} @private */
195ffe3c632Sopenharmony_ci  this.idx_ = 0;
196ffe3c632Sopenharmony_ci
197ffe3c632Sopenharmony_ci  /** @const @private */
198ffe3c632Sopenharmony_ci  this.arr_ = arr;
199ffe3c632Sopenharmony_ci};
200ffe3c632Sopenharmony_ci
201ffe3c632Sopenharmony_ci
202ffe3c632Sopenharmony_ci/** @override @final */
203ffe3c632Sopenharmony_cijspb.Map.ArrayIteratorIterable_.prototype.next = function() {
204ffe3c632Sopenharmony_ci  if (this.idx_ < this.arr_.length) {
205ffe3c632Sopenharmony_ci    return {done: false, value: this.arr_[this.idx_++]};
206ffe3c632Sopenharmony_ci  } else {
207ffe3c632Sopenharmony_ci    return {done: true, value: undefined};
208ffe3c632Sopenharmony_ci  }
209ffe3c632Sopenharmony_ci};
210ffe3c632Sopenharmony_ci
211ffe3c632Sopenharmony_ciif (typeof(Symbol) != 'undefined') {
212ffe3c632Sopenharmony_ci  /** @override */
213ffe3c632Sopenharmony_ci  jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] = function() {
214ffe3c632Sopenharmony_ci    return this;
215ffe3c632Sopenharmony_ci  };
216ffe3c632Sopenharmony_ci}
217ffe3c632Sopenharmony_ci
218ffe3c632Sopenharmony_ci
219ffe3c632Sopenharmony_ci/**
220ffe3c632Sopenharmony_ci * Returns the map's length (number of key/value pairs).
221ffe3c632Sopenharmony_ci * @return {number}
222ffe3c632Sopenharmony_ci */
223ffe3c632Sopenharmony_cijspb.Map.prototype.getLength = function() {
224ffe3c632Sopenharmony_ci  return this.stringKeys_().length;
225ffe3c632Sopenharmony_ci};
226ffe3c632Sopenharmony_ci
227ffe3c632Sopenharmony_ci
228ffe3c632Sopenharmony_ci/**
229ffe3c632Sopenharmony_ci * Clears the map.
230ffe3c632Sopenharmony_ci */
231ffe3c632Sopenharmony_cijspb.Map.prototype.clear = function() {
232ffe3c632Sopenharmony_ci  this.map_ = {};
233ffe3c632Sopenharmony_ci  this.arrClean = false;
234ffe3c632Sopenharmony_ci};
235ffe3c632Sopenharmony_ci
236ffe3c632Sopenharmony_ci
237ffe3c632Sopenharmony_ci/**
238ffe3c632Sopenharmony_ci * Deletes a particular key from the map.
239ffe3c632Sopenharmony_ci * N.B.: differs in name from ES6 Map's `delete` because IE8 does not support
240ffe3c632Sopenharmony_ci * reserved words as property names.
241ffe3c632Sopenharmony_ci * @this {jspb.Map}
242ffe3c632Sopenharmony_ci * @param {K} key
243ffe3c632Sopenharmony_ci * @return {boolean} Whether any entry with this key was deleted.
244ffe3c632Sopenharmony_ci */
245ffe3c632Sopenharmony_cijspb.Map.prototype.del = function(key) {
246ffe3c632Sopenharmony_ci  var keyValue = key.toString();
247ffe3c632Sopenharmony_ci  var hadKey = this.map_.hasOwnProperty(keyValue);
248ffe3c632Sopenharmony_ci  delete this.map_[keyValue];
249ffe3c632Sopenharmony_ci  this.arrClean = false;
250ffe3c632Sopenharmony_ci  return hadKey;
251ffe3c632Sopenharmony_ci};
252ffe3c632Sopenharmony_ci
253ffe3c632Sopenharmony_ci
254ffe3c632Sopenharmony_ci/**
255ffe3c632Sopenharmony_ci * Returns an array of [key, value] pairs in the map.
256ffe3c632Sopenharmony_ci *
257ffe3c632Sopenharmony_ci * This is redundant compared to the plain entries() method, but we provide this
258ffe3c632Sopenharmony_ci * to help out Angular 1.x users.  Still evaluating whether this is the best
259ffe3c632Sopenharmony_ci * option.
260ffe3c632Sopenharmony_ci *
261ffe3c632Sopenharmony_ci * @return {!Array<!Array<K|V>>}
262ffe3c632Sopenharmony_ci */
263ffe3c632Sopenharmony_cijspb.Map.prototype.getEntryList = function() {
264ffe3c632Sopenharmony_ci  var entries = [];
265ffe3c632Sopenharmony_ci  var strKeys = this.stringKeys_();
266ffe3c632Sopenharmony_ci  strKeys.sort();
267ffe3c632Sopenharmony_ci  for (var i = 0; i < strKeys.length; i++) {
268ffe3c632Sopenharmony_ci    var entry = this.map_[strKeys[i]];
269ffe3c632Sopenharmony_ci    entries.push([entry.key, entry.value]);
270ffe3c632Sopenharmony_ci  }
271ffe3c632Sopenharmony_ci  return entries;
272ffe3c632Sopenharmony_ci};
273ffe3c632Sopenharmony_ci
274ffe3c632Sopenharmony_ci
275ffe3c632Sopenharmony_ci/**
276ffe3c632Sopenharmony_ci * Returns an iterator-iterable over [key, value] pairs in the map.
277ffe3c632Sopenharmony_ci * Closure compiler sadly doesn't support tuples, ie. Iterator<[K,V]>.
278ffe3c632Sopenharmony_ci * @return {!IteratorIterable<!Array<K|V>>} The iterator-iterable.
279ffe3c632Sopenharmony_ci */
280ffe3c632Sopenharmony_cijspb.Map.prototype.entries = function() {
281ffe3c632Sopenharmony_ci  var entries = [];
282ffe3c632Sopenharmony_ci  var strKeys = this.stringKeys_();
283ffe3c632Sopenharmony_ci  strKeys.sort();
284ffe3c632Sopenharmony_ci  for (var i = 0; i < strKeys.length; i++) {
285ffe3c632Sopenharmony_ci    var entry = this.map_[strKeys[i]];
286ffe3c632Sopenharmony_ci    entries.push([entry.key, this.wrapEntry_(entry)]);
287ffe3c632Sopenharmony_ci  }
288ffe3c632Sopenharmony_ci  return new jspb.Map.ArrayIteratorIterable_(entries);
289ffe3c632Sopenharmony_ci};
290ffe3c632Sopenharmony_ci
291ffe3c632Sopenharmony_ci
292ffe3c632Sopenharmony_ci/**
293ffe3c632Sopenharmony_ci * Returns an iterator-iterable over keys in the map.
294ffe3c632Sopenharmony_ci * @return {!IteratorIterable<K>} The iterator-iterable.
295ffe3c632Sopenharmony_ci */
296ffe3c632Sopenharmony_cijspb.Map.prototype.keys = function() {
297ffe3c632Sopenharmony_ci  var keys = [];
298ffe3c632Sopenharmony_ci  var strKeys = this.stringKeys_();
299ffe3c632Sopenharmony_ci  strKeys.sort();
300ffe3c632Sopenharmony_ci  for (var i = 0; i < strKeys.length; i++) {
301ffe3c632Sopenharmony_ci    var entry = this.map_[strKeys[i]];
302ffe3c632Sopenharmony_ci    keys.push(entry.key);
303ffe3c632Sopenharmony_ci  }
304ffe3c632Sopenharmony_ci  return new jspb.Map.ArrayIteratorIterable_(keys);
305ffe3c632Sopenharmony_ci};
306ffe3c632Sopenharmony_ci
307ffe3c632Sopenharmony_ci
308ffe3c632Sopenharmony_ci/**
309ffe3c632Sopenharmony_ci * Returns an iterator-iterable over values in the map.
310ffe3c632Sopenharmony_ci * @return {!IteratorIterable<V>} The iterator-iterable.
311ffe3c632Sopenharmony_ci */
312ffe3c632Sopenharmony_cijspb.Map.prototype.values = function() {
313ffe3c632Sopenharmony_ci  var values = [];
314ffe3c632Sopenharmony_ci  var strKeys = this.stringKeys_();
315ffe3c632Sopenharmony_ci  strKeys.sort();
316ffe3c632Sopenharmony_ci  for (var i = 0; i < strKeys.length; i++) {
317ffe3c632Sopenharmony_ci    var entry = this.map_[strKeys[i]];
318ffe3c632Sopenharmony_ci    values.push(this.wrapEntry_(entry));
319ffe3c632Sopenharmony_ci  }
320ffe3c632Sopenharmony_ci  return new jspb.Map.ArrayIteratorIterable_(values);
321ffe3c632Sopenharmony_ci};
322ffe3c632Sopenharmony_ci
323ffe3c632Sopenharmony_ci
324ffe3c632Sopenharmony_ci/**
325ffe3c632Sopenharmony_ci * Iterates over entries in the map, calling a function on each.
326ffe3c632Sopenharmony_ci * @template T
327ffe3c632Sopenharmony_ci * @param {function(this:T, V, K, ?jspb.Map<K, V>)} cb
328ffe3c632Sopenharmony_ci * @param {T=} opt_thisArg
329ffe3c632Sopenharmony_ci */
330ffe3c632Sopenharmony_cijspb.Map.prototype.forEach = function(cb, opt_thisArg) {
331ffe3c632Sopenharmony_ci  var strKeys = this.stringKeys_();
332ffe3c632Sopenharmony_ci  strKeys.sort();
333ffe3c632Sopenharmony_ci  for (var i = 0; i < strKeys.length; i++) {
334ffe3c632Sopenharmony_ci    var entry = this.map_[strKeys[i]];
335ffe3c632Sopenharmony_ci    cb.call(opt_thisArg, this.wrapEntry_(entry), entry.key, this);
336ffe3c632Sopenharmony_ci  }
337ffe3c632Sopenharmony_ci};
338ffe3c632Sopenharmony_ci
339ffe3c632Sopenharmony_ci
340ffe3c632Sopenharmony_ci/**
341ffe3c632Sopenharmony_ci * Sets a key in the map to the given value.
342ffe3c632Sopenharmony_ci * @param {K} key The key
343ffe3c632Sopenharmony_ci * @param {V} value The value
344ffe3c632Sopenharmony_ci * @return {!jspb.Map<K,V>}
345ffe3c632Sopenharmony_ci */
346ffe3c632Sopenharmony_cijspb.Map.prototype.set = function(key, value) {
347ffe3c632Sopenharmony_ci  var entry = new jspb.Map.Entry_(key);
348ffe3c632Sopenharmony_ci  if (this.valueCtor_) {
349ffe3c632Sopenharmony_ci    entry.valueWrapper = value;
350ffe3c632Sopenharmony_ci    // .toArray() on a message returns a reference to the underlying array
351ffe3c632Sopenharmony_ci    // rather than a copy.
352ffe3c632Sopenharmony_ci    entry.value = value.toArray();
353ffe3c632Sopenharmony_ci  } else {
354ffe3c632Sopenharmony_ci    entry.value = value;
355ffe3c632Sopenharmony_ci  }
356ffe3c632Sopenharmony_ci  this.map_[key.toString()] = entry;
357ffe3c632Sopenharmony_ci  this.arrClean = false;
358ffe3c632Sopenharmony_ci  return this;
359ffe3c632Sopenharmony_ci};
360ffe3c632Sopenharmony_ci
361ffe3c632Sopenharmony_ci
362ffe3c632Sopenharmony_ci/**
363ffe3c632Sopenharmony_ci * Helper: lazily construct a wrapper around an entry, if needed, and return the
364ffe3c632Sopenharmony_ci * user-visible type.
365ffe3c632Sopenharmony_ci * @param {!jspb.Map.Entry_<K,V>} entry
366ffe3c632Sopenharmony_ci * @return {V}
367ffe3c632Sopenharmony_ci * @private
368ffe3c632Sopenharmony_ci */
369ffe3c632Sopenharmony_cijspb.Map.prototype.wrapEntry_ = function(entry) {
370ffe3c632Sopenharmony_ci  if (this.valueCtor_) {
371ffe3c632Sopenharmony_ci    if (!entry.valueWrapper) {
372ffe3c632Sopenharmony_ci      entry.valueWrapper = new this.valueCtor_(entry.value);
373ffe3c632Sopenharmony_ci    }
374ffe3c632Sopenharmony_ci    return /** @type {V} */ (entry.valueWrapper);
375ffe3c632Sopenharmony_ci  } else {
376ffe3c632Sopenharmony_ci    return entry.value;
377ffe3c632Sopenharmony_ci  }
378ffe3c632Sopenharmony_ci};
379ffe3c632Sopenharmony_ci
380ffe3c632Sopenharmony_ci
381ffe3c632Sopenharmony_ci/**
382ffe3c632Sopenharmony_ci * Gets the value corresponding to a key in the map.
383ffe3c632Sopenharmony_ci * @param {K} key
384ffe3c632Sopenharmony_ci * @return {V|undefined} The value, or `undefined` if key not present
385ffe3c632Sopenharmony_ci */
386ffe3c632Sopenharmony_cijspb.Map.prototype.get = function(key) {
387ffe3c632Sopenharmony_ci  var keyValue = key.toString();
388ffe3c632Sopenharmony_ci  var entry = this.map_[keyValue];
389ffe3c632Sopenharmony_ci  if (entry) {
390ffe3c632Sopenharmony_ci    return this.wrapEntry_(entry);
391ffe3c632Sopenharmony_ci  } else {
392ffe3c632Sopenharmony_ci    return undefined;
393ffe3c632Sopenharmony_ci  }
394ffe3c632Sopenharmony_ci};
395ffe3c632Sopenharmony_ci
396ffe3c632Sopenharmony_ci
397ffe3c632Sopenharmony_ci/**
398ffe3c632Sopenharmony_ci * Determines whether the given key is present in the map.
399ffe3c632Sopenharmony_ci * @param {K} key
400ffe3c632Sopenharmony_ci * @return {boolean} `true` if the key is present
401ffe3c632Sopenharmony_ci */
402ffe3c632Sopenharmony_cijspb.Map.prototype.has = function(key) {
403ffe3c632Sopenharmony_ci  var keyValue = key.toString();
404ffe3c632Sopenharmony_ci  return (keyValue in this.map_);
405ffe3c632Sopenharmony_ci};
406ffe3c632Sopenharmony_ci
407ffe3c632Sopenharmony_ci
408ffe3c632Sopenharmony_ci/**
409ffe3c632Sopenharmony_ci * Write this Map field in wire format to a BinaryWriter, using the given field
410ffe3c632Sopenharmony_ci * number.
411ffe3c632Sopenharmony_ci * @param {number} fieldNumber
412ffe3c632Sopenharmony_ci * @param {!jspb.BinaryWriter} writer
413ffe3c632Sopenharmony_ci * @param {function(this:jspb.BinaryWriter,number,K)} keyWriterFn
414ffe3c632Sopenharmony_ci *     The method on BinaryWriter that writes type K to the stream.
415ffe3c632Sopenharmony_ci * @param {function(this:jspb.BinaryWriter,number,V,?=)|
416ffe3c632Sopenharmony_ci *          function(this:jspb.BinaryWriter,number,V,?)} valueWriterFn
417ffe3c632Sopenharmony_ci *     The method on BinaryWriter that writes type V to the stream.  May be
418ffe3c632Sopenharmony_ci *     writeMessage, in which case the second callback arg form is used.
419ffe3c632Sopenharmony_ci * @param {function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback
420ffe3c632Sopenharmony_ci *    The BinaryWriter serialization callback for type V, if V is a message
421ffe3c632Sopenharmony_ci *    type.
422ffe3c632Sopenharmony_ci */
423ffe3c632Sopenharmony_cijspb.Map.prototype.serializeBinary = function(
424ffe3c632Sopenharmony_ci    fieldNumber, writer, keyWriterFn, valueWriterFn, opt_valueWriterCallback) {
425ffe3c632Sopenharmony_ci  var strKeys = this.stringKeys_();
426ffe3c632Sopenharmony_ci  strKeys.sort();
427ffe3c632Sopenharmony_ci  for (var i = 0; i < strKeys.length; i++) {
428ffe3c632Sopenharmony_ci    var entry = this.map_[strKeys[i]];
429ffe3c632Sopenharmony_ci    writer.beginSubMessage(fieldNumber);
430ffe3c632Sopenharmony_ci    keyWriterFn.call(writer, 1, entry.key);
431ffe3c632Sopenharmony_ci    if (this.valueCtor_) {
432ffe3c632Sopenharmony_ci      valueWriterFn.call(writer, 2, this.wrapEntry_(entry),
433ffe3c632Sopenharmony_ci                         opt_valueWriterCallback);
434ffe3c632Sopenharmony_ci    } else {
435ffe3c632Sopenharmony_ci      /** @type {function(this:jspb.BinaryWriter,number,?)} */ (valueWriterFn)
436ffe3c632Sopenharmony_ci          .call(writer, 2, entry.value);
437ffe3c632Sopenharmony_ci    }
438ffe3c632Sopenharmony_ci    writer.endSubMessage();
439ffe3c632Sopenharmony_ci  }
440ffe3c632Sopenharmony_ci};
441ffe3c632Sopenharmony_ci
442ffe3c632Sopenharmony_ci
443ffe3c632Sopenharmony_ci/**
444ffe3c632Sopenharmony_ci * Read one key/value message from the given BinaryReader. Compatible as the
445ffe3c632Sopenharmony_ci * `reader` callback parameter to jspb.BinaryReader.readMessage, to be called
446ffe3c632Sopenharmony_ci * when a key/value pair submessage is encountered. If the Key is undefined,
447ffe3c632Sopenharmony_ci * we should default it to 0.
448ffe3c632Sopenharmony_ci * @template K, V
449ffe3c632Sopenharmony_ci * @param {!jspb.Map} map
450ffe3c632Sopenharmony_ci * @param {!jspb.BinaryReader} reader
451ffe3c632Sopenharmony_ci * @param {function(this:jspb.BinaryReader):K} keyReaderFn
452ffe3c632Sopenharmony_ci *     The method on BinaryReader that reads type K from the stream.
453ffe3c632Sopenharmony_ci *
454ffe3c632Sopenharmony_ci * @param {function(this:jspb.BinaryReader):V|
455ffe3c632Sopenharmony_ci *          function(this:jspb.BinaryReader,V,
456ffe3c632Sopenharmony_ci *                  function(V,!jspb.BinaryReader))} valueReaderFn
457ffe3c632Sopenharmony_ci *    The method on BinaryReader that reads type V from the stream. May be
458ffe3c632Sopenharmony_ci *    readMessage, in which case the second callback arg form is used.
459ffe3c632Sopenharmony_ci *
460ffe3c632Sopenharmony_ci * @param {?function(V,!jspb.BinaryReader)=} opt_valueReaderCallback
461ffe3c632Sopenharmony_ci *    The BinaryReader parsing callback for type V, if V is a message type
462ffe3c632Sopenharmony_ci *
463ffe3c632Sopenharmony_ci * @param {K=} opt_defaultKey
464ffe3c632Sopenharmony_ci *    The default value for the type of map keys. Accepting map entries with
465ffe3c632Sopenharmony_ci *    unset keys is required for maps to be backwards compatible with the
466ffe3c632Sopenharmony_ci *    repeated message representation described here: goo.gl/zuoLAC
467ffe3c632Sopenharmony_ci *
468ffe3c632Sopenharmony_ci * @param {V=} opt_defaultValue
469ffe3c632Sopenharmony_ci *    The default value for the type of map values. Accepting map entries with
470ffe3c632Sopenharmony_ci *    unset values is required for maps to be backwards compatible with the
471ffe3c632Sopenharmony_ci *    repeated message representation described here: goo.gl/zuoLAC
472ffe3c632Sopenharmony_ci *
473ffe3c632Sopenharmony_ci */
474ffe3c632Sopenharmony_cijspb.Map.deserializeBinary = function(map, reader, keyReaderFn, valueReaderFn,
475ffe3c632Sopenharmony_ci                                      opt_valueReaderCallback, opt_defaultKey,
476ffe3c632Sopenharmony_ci                                      opt_defaultValue) {
477ffe3c632Sopenharmony_ci  var key = opt_defaultKey;
478ffe3c632Sopenharmony_ci  var value = opt_defaultValue;
479ffe3c632Sopenharmony_ci
480ffe3c632Sopenharmony_ci  while (reader.nextField()) {
481ffe3c632Sopenharmony_ci    if (reader.isEndGroup()) {
482ffe3c632Sopenharmony_ci      break;
483ffe3c632Sopenharmony_ci    }
484ffe3c632Sopenharmony_ci    var field = reader.getFieldNumber();
485ffe3c632Sopenharmony_ci
486ffe3c632Sopenharmony_ci    if (field == 1) {
487ffe3c632Sopenharmony_ci      // Key.
488ffe3c632Sopenharmony_ci      key = keyReaderFn.call(reader);
489ffe3c632Sopenharmony_ci    } else if (field == 2) {
490ffe3c632Sopenharmony_ci      // Value.
491ffe3c632Sopenharmony_ci      if (map.valueCtor_) {
492ffe3c632Sopenharmony_ci        goog.asserts.assert(opt_valueReaderCallback);
493ffe3c632Sopenharmony_ci        if (!value) {
494ffe3c632Sopenharmony_ci          // Old generator still doesn't provide default value message.
495ffe3c632Sopenharmony_ci          // Need this for backward compatibility.
496ffe3c632Sopenharmony_ci          value = new map.valueCtor_();
497ffe3c632Sopenharmony_ci        }
498ffe3c632Sopenharmony_ci        valueReaderFn.call(reader, value, opt_valueReaderCallback);
499ffe3c632Sopenharmony_ci      } else {
500ffe3c632Sopenharmony_ci        value =
501ffe3c632Sopenharmony_ci            (/** @type {function(this:jspb.BinaryReader):?} */ (valueReaderFn))
502ffe3c632Sopenharmony_ci                .call(reader);
503ffe3c632Sopenharmony_ci      }
504ffe3c632Sopenharmony_ci    }
505ffe3c632Sopenharmony_ci  }
506ffe3c632Sopenharmony_ci
507ffe3c632Sopenharmony_ci  goog.asserts.assert(key != undefined);
508ffe3c632Sopenharmony_ci  goog.asserts.assert(value != undefined);
509ffe3c632Sopenharmony_ci  map.set(key, value);
510ffe3c632Sopenharmony_ci};
511ffe3c632Sopenharmony_ci
512ffe3c632Sopenharmony_ci
513ffe3c632Sopenharmony_ci/**
514ffe3c632Sopenharmony_ci * Helper: compute the list of all stringified keys in the underlying Object
515ffe3c632Sopenharmony_ci * map.
516ffe3c632Sopenharmony_ci * @return {!Array<string>}
517ffe3c632Sopenharmony_ci * @private
518ffe3c632Sopenharmony_ci */
519ffe3c632Sopenharmony_cijspb.Map.prototype.stringKeys_ = function() {
520ffe3c632Sopenharmony_ci  var m = this.map_;
521ffe3c632Sopenharmony_ci  var ret = [];
522ffe3c632Sopenharmony_ci  for (var p in m) {
523ffe3c632Sopenharmony_ci    if (Object.prototype.hasOwnProperty.call(m, p)) {
524ffe3c632Sopenharmony_ci      ret.push(p);
525ffe3c632Sopenharmony_ci    }
526ffe3c632Sopenharmony_ci  }
527ffe3c632Sopenharmony_ci  return ret;
528ffe3c632Sopenharmony_ci};
529ffe3c632Sopenharmony_ci
530ffe3c632Sopenharmony_ci
531ffe3c632Sopenharmony_ci
532ffe3c632Sopenharmony_ci/**
533ffe3c632Sopenharmony_ci * @param {K} key The entry's key.
534ffe3c632Sopenharmony_ci * @param {V=} opt_value The entry's value wrapper.
535ffe3c632Sopenharmony_ci * @constructor
536ffe3c632Sopenharmony_ci * @struct
537ffe3c632Sopenharmony_ci * @template K, V
538ffe3c632Sopenharmony_ci * @private
539ffe3c632Sopenharmony_ci */
540ffe3c632Sopenharmony_cijspb.Map.Entry_ = function(key, opt_value) {
541ffe3c632Sopenharmony_ci  /** @const {K} */
542ffe3c632Sopenharmony_ci  this.key = key;
543ffe3c632Sopenharmony_ci
544ffe3c632Sopenharmony_ci  // The JSPB-serializable value.  For primitive types this will be of type V.
545ffe3c632Sopenharmony_ci  // For message types it will be an array.
546ffe3c632Sopenharmony_ci  /** @type {V} */
547ffe3c632Sopenharmony_ci  this.value = opt_value;
548ffe3c632Sopenharmony_ci
549ffe3c632Sopenharmony_ci  // Only used for submessage values.
550ffe3c632Sopenharmony_ci  /** @type {V} */
551ffe3c632Sopenharmony_ci  this.valueWrapper = undefined;
552ffe3c632Sopenharmony_ci};
553