binary_storage.js 3.1 KB

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