/* Copyright 2010-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace MongoDB.Bson.IO { /// /// Represents a fast converter from integer indexes to UTF8 BSON array element names. /// internal interface IArrayElementNameAccelerator { /// /// Gets the element name bytes. /// /// The index. /// The element name bytes. byte[] GetElementNameBytes(int index); } /// /// Represents a fast converter from integer indexes to UTF8 BSON array element names. /// internal class ArrayElementNameAccelerator : IArrayElementNameAccelerator { #region static // static fields private static IArrayElementNameAccelerator __default = new ArrayElementNameAccelerator(1000); // static properties /// /// Gets or sets the default array element name accelerator. /// public static IArrayElementNameAccelerator Default { get { return __default; } set { __default = value; } } #endregion // fields private readonly byte[][] _cachedElementNames; // constructors /// /// Initializes a new instance of the class. /// /// The number of cached element names. public ArrayElementNameAccelerator(int numberOfCachedElementNames) { _cachedElementNames = new byte[numberOfCachedElementNames][]; for (int index = 0; index < numberOfCachedElementNames; index++) { _cachedElementNames[index] = CreateElementNameBytes(index); } } // methods private byte[] CreateElementNameBytes(int index) { // unrolled loop optimized for index values >= 1000 and < 10,000 const int asciiZero = 48; var n = index; var a = (byte)(asciiZero + n % 10); n = n / 10; var b = (byte)(asciiZero + n % 10); n = n / 10; var c = (byte)(asciiZero + n % 10); n = n / 10; var d = (byte)(asciiZero + n % 10); n = n / 10; if (n == 0) { if (d != (byte)asciiZero) { return new[] { d, c, b, a }; } if (c != (byte)asciiZero) { return new[] { c, b, a }; } if (b != (byte)asciiZero) { return new[] { b, a }; } return new[] { a }; } var e = (byte)(asciiZero + n % 10); n = n / 10; if (n == 0) { return new[] { e, d, c, b, a }; } // really large indexes should be extremely rare and not worth optimizing further return Utf8Encodings.Strict.GetBytes(index.ToString()); } /// /// Gets the element name bytes. /// /// The index. /// /// The element name bytes. /// public byte[] GetElementNameBytes(int index) { if (index < 0) { throw new ArgumentOutOfRangeException("index", "index is negative."); } if (index < _cachedElementNames.Length) { return _cachedElementNames[index]; } return CreateElementNameBytes(index); } } }