ArrayElementNameAccelerator.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /* Copyright 2010-2016 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. namespace MongoDB.Bson.IO
  17. {
  18. /// <summary>
  19. /// Represents a fast converter from integer indexes to UTF8 BSON array element names.
  20. /// </summary>
  21. internal interface IArrayElementNameAccelerator
  22. {
  23. /// <summary>
  24. /// Gets the element name bytes.
  25. /// </summary>
  26. /// <param name="index">The index.</param>
  27. /// <returns>The element name bytes.</returns>
  28. byte[] GetElementNameBytes(int index);
  29. }
  30. /// <summary>
  31. /// Represents a fast converter from integer indexes to UTF8 BSON array element names.
  32. /// </summary>
  33. internal class ArrayElementNameAccelerator : IArrayElementNameAccelerator
  34. {
  35. #region static
  36. // static fields
  37. private static IArrayElementNameAccelerator __default = new ArrayElementNameAccelerator(1000);
  38. // static properties
  39. /// <summary>
  40. /// Gets or sets the default array element name accelerator.
  41. /// </summary>
  42. public static IArrayElementNameAccelerator Default
  43. {
  44. get { return __default; }
  45. set { __default = value; }
  46. }
  47. #endregion
  48. // fields
  49. private readonly byte[][] _cachedElementNames;
  50. // constructors
  51. /// <summary>
  52. /// Initializes a new instance of the <see cref="ArrayElementNameAccelerator"/> class.
  53. /// </summary>
  54. /// <param name="numberOfCachedElementNames">The number of cached element names.</param>
  55. public ArrayElementNameAccelerator(int numberOfCachedElementNames)
  56. {
  57. _cachedElementNames = new byte[numberOfCachedElementNames][];
  58. for (int index = 0; index < numberOfCachedElementNames; index++)
  59. {
  60. _cachedElementNames[index] = CreateElementNameBytes(index);
  61. }
  62. }
  63. // methods
  64. private byte[] CreateElementNameBytes(int index)
  65. {
  66. // unrolled loop optimized for index values >= 1000 and < 10,000
  67. const int asciiZero = 48;
  68. var n = index;
  69. var a = (byte)(asciiZero + n % 10);
  70. n = n / 10;
  71. var b = (byte)(asciiZero + n % 10);
  72. n = n / 10;
  73. var c = (byte)(asciiZero + n % 10);
  74. n = n / 10;
  75. var d = (byte)(asciiZero + n % 10);
  76. n = n / 10;
  77. if (n == 0)
  78. {
  79. if (d != (byte)asciiZero) { return new[] { d, c, b, a }; }
  80. if (c != (byte)asciiZero) { return new[] { c, b, a }; }
  81. if (b != (byte)asciiZero) { return new[] { b, a }; }
  82. return new[] { a };
  83. }
  84. var e = (byte)(asciiZero + n % 10);
  85. n = n / 10;
  86. if (n == 0) { return new[] { e, d, c, b, a }; }
  87. // really large indexes should be extremely rare and not worth optimizing further
  88. return Utf8Encodings.Strict.GetBytes(index.ToString());
  89. }
  90. /// <summary>
  91. /// Gets the element name bytes.
  92. /// </summary>
  93. /// <param name="index">The index.</param>
  94. /// <returns>
  95. /// The element name bytes.
  96. /// </returns>
  97. public byte[] GetElementNameBytes(int index)
  98. {
  99. if (index < 0)
  100. {
  101. throw new ArgumentOutOfRangeException("index", "index is negative.");
  102. }
  103. if (index < _cachedElementNames.Length)
  104. {
  105. return _cachedElementNames[index];
  106. }
  107. return CreateElementNameBytes(index);
  108. }
  109. }
  110. }