BsonTrie.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /* Copyright 2010-2015 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. using System.IO;
  17. using System.Text;
  18. using UnityEngine;
  19. namespace MongoDB.Bson.IO
  20. {
  21. /// <summary>
  22. /// Represents a mapping from a set of UTF8 encoded strings to a set of elementName/value pairs, implemented as a trie.
  23. /// </summary>
  24. /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam>
  25. public class BsonTrie<TValue>
  26. {
  27. // private fields
  28. private readonly BsonTrieNode<TValue> _root;
  29. // constructors
  30. /// <summary>
  31. /// Initializes a new instance of the BsonTrie class.
  32. /// </summary>
  33. public BsonTrie()
  34. {
  35. _root = new BsonTrieNode<TValue>(0);
  36. }
  37. // public properties
  38. /// <summary>
  39. /// Gets the root node.
  40. /// </summary>
  41. public BsonTrieNode<TValue> Root
  42. {
  43. get
  44. {
  45. return _root;
  46. }
  47. }
  48. // public methods
  49. /// <summary>
  50. /// Adds the specified elementName (after encoding as a UTF8 byte sequence) and value to the trie.
  51. /// </summary>
  52. /// <param name="elementName">The element name to add.</param>
  53. /// <param name="value">The value to add. The value can be null for reference types.</param>
  54. public void Add(string elementName, TValue value)
  55. {
  56. var utf8 = Utf8Encodings.Strict.GetBytes(elementName);
  57. var node = _root;
  58. foreach (var keyByte in utf8)
  59. {
  60. var child = node.GetChild(keyByte);
  61. if (child == null)
  62. {
  63. child = new BsonTrieNode<TValue>(keyByte);
  64. node.AddChild(child);
  65. }
  66. node = child;
  67. }
  68. node.SetValue(elementName, value);
  69. }
  70. /// <summary>
  71. /// Gets the node associated with the specified element name.
  72. /// </summary>
  73. /// <param name="utf8">The element name.</param>
  74. /// <param name="node">
  75. /// When this method returns, contains the node associated with the specified element name, if the key is found;
  76. /// otherwise, null. This parameter is passed unitialized.
  77. /// </param>
  78. /// <returns>True if the node was found; otherwise, false.</returns>
  79. public bool TryGetNode(ArraySegment<byte> utf8, out BsonTrieNode<TValue> node)
  80. {
  81. node = _root;
  82. for (var i = 0; node != null && i < utf8.Count; i++)
  83. {
  84. var keyByte = utf8.Array[utf8.Offset + i];
  85. node = node.GetChild(keyByte);
  86. }
  87. return node != null;
  88. }
  89. /// <summary>
  90. /// Tries to get the node associated with a name read from a stream.
  91. /// </summary>
  92. /// <param name="stream">The stream.</param>
  93. /// <param name="node">The node.</param>
  94. /// <returns>
  95. /// True if the node was found.
  96. /// If the node was found the stream is advanced over the name, otherwise
  97. /// the stream is repositioned to the beginning of the name.
  98. /// </returns>
  99. public bool TryGetNode(BsonStream stream, out BsonTrieNode<TValue> node)
  100. {
  101. var position = stream.Position;
  102. var utf8 = stream.ReadCStringBytes();
  103. if (TryGetNode(utf8, out node))
  104. {
  105. return true;
  106. }
  107. stream.Position = position;
  108. return false;
  109. }
  110. /// <summary>
  111. /// Gets the value associated with the specified element name.
  112. /// </summary>
  113. /// <param name="utf8">The element name.</param>
  114. /// <param name="value">
  115. /// When this method returns, contains the value associated with the specified element name, if the key is found;
  116. /// otherwise, the default value for the type of the value parameter. This parameter is passed unitialized.
  117. /// </param>
  118. /// <returns>True if the value was found; otherwise, false.</returns>
  119. public bool TryGetValue(ArraySegment<byte> utf8, out TValue value)
  120. {
  121. BsonTrieNode<TValue> node;
  122. if (TryGetNode(utf8, out node) && node.HasValue)
  123. {
  124. value = node.Value;
  125. return true;
  126. }
  127. value = default(TValue);
  128. return false;
  129. }
  130. /// <summary>
  131. /// Gets the value associated with the specified element name.
  132. /// </summary>
  133. /// <param name="elementName">The element name.</param>
  134. /// <param name="value">
  135. /// When this method returns, contains the value associated with the specified element name, if the key is found;
  136. /// otherwise, the default value for the type of the value parameter. This parameter is passed unitialized.
  137. /// </param>
  138. /// <returns>True if the value was found; otherwise, false.</returns>
  139. public bool TryGetValue(string elementName, out TValue value)
  140. {
  141. var bytes = Utf8Encodings.Strict.GetBytes(elementName);
  142. var utf8 = new ArraySegment<byte>(bytes, 0, bytes.Length);
  143. return TryGetValue(utf8, out value);
  144. }
  145. }
  146. /// <summary>
  147. /// Represents a node in a BsonTrie.
  148. /// </summary>
  149. /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam>
  150. public sealed class BsonTrieNode<TValue>
  151. {
  152. // private fields
  153. private readonly byte _keyByte;
  154. private string _elementName;
  155. private TValue _value;
  156. private BsonTrieNode<TValue> _onlyChild; // used when there is only one child
  157. private BsonTrieNode<TValue>[] _children; // used when there are two or more children
  158. private byte[] _childrenIndexes; // maps key bytes into indexes into the _children array
  159. private byte _minChildKeyByte; // key byte value of first element in _childrenIndexes
  160. // constructors
  161. internal BsonTrieNode(byte keyByte)
  162. {
  163. _keyByte = keyByte;
  164. }
  165. /// <summary>
  166. /// Gets whether this node has a value.
  167. /// </summary>
  168. public bool HasValue
  169. {
  170. get
  171. {
  172. return _elementName != null;
  173. }
  174. }
  175. /// <summary>
  176. /// Gets the element name for this node.
  177. /// </summary>
  178. public string ElementName
  179. {
  180. get
  181. {
  182. if (_elementName == null)
  183. {
  184. throw new InvalidOperationException("BsonTrieNode doesn't have a value.");
  185. }
  186. return _elementName;
  187. }
  188. }
  189. /// <summary>
  190. /// Gets the value for this node.
  191. /// </summary>
  192. public TValue Value
  193. {
  194. get
  195. {
  196. if (_elementName == null)
  197. {
  198. throw new InvalidOperationException("BsonTrieNode doesn't have a value.");
  199. }
  200. return _value;
  201. }
  202. }
  203. // public methods
  204. /// <summary>
  205. /// Gets the child of this node for a given key byte.
  206. /// </summary>
  207. /// <param name="keyByte">The key byte.</param>
  208. /// <returns>The child node if it exists; otherwise, null.</returns>
  209. public BsonTrieNode<TValue> GetChild(byte keyByte)
  210. {
  211. if (_onlyChild != null)
  212. {
  213. // optimization for nodes that have only one child
  214. if (_onlyChild._keyByte == keyByte)
  215. {
  216. return _onlyChild;
  217. }
  218. }
  219. else if (_children != null)
  220. {
  221. // 这里做了修改,il2cpp uint跟int比较有bug
  222. int index = keyByte - _minChildKeyByte;
  223. if (index < 0)
  224. {
  225. return null;
  226. }
  227. if (index < _childrenIndexes.Length)
  228. {
  229. index = _childrenIndexes[index];
  230. if (index < _children.Length)
  231. {
  232. return _children[index];
  233. }
  234. }
  235. }
  236. return null;
  237. }
  238. // internal methods
  239. internal void AddChild(BsonTrieNode<TValue> child)
  240. {
  241. if (GetChild(child._keyByte) != null)
  242. {
  243. throw new ArgumentException("BsonTrieNode already contains a child with the same keyByte.");
  244. }
  245. if (_children != null)
  246. {
  247. // add a new child to the existing _children
  248. var children = new BsonTrieNode<TValue>[_children.Length + 1];
  249. Array.Copy(_children, children, _children.Length);
  250. children[children.Length - 1] = child;
  251. var childrenIndexes = _childrenIndexes;
  252. var minChildKeyByte = _minChildKeyByte;
  253. var maxChildKeyByte = _minChildKeyByte + _childrenIndexes.Length - 1;
  254. // if new keyByte doesn't fall within existing min/max range expand the range
  255. if (child._keyByte < minChildKeyByte)
  256. {
  257. // grow the indexes on the min side
  258. minChildKeyByte = child._keyByte;
  259. childrenIndexes = new byte[maxChildKeyByte - minChildKeyByte + 1];
  260. var sizeDelta = childrenIndexes.Length - _childrenIndexes.Length;
  261. for (var i = 0; i < sizeDelta; i++)
  262. {
  263. childrenIndexes[i] = 255;
  264. }
  265. Array.Copy(_childrenIndexes, 0, childrenIndexes, sizeDelta, _childrenIndexes.Length);
  266. }
  267. else if (child._keyByte > maxChildKeyByte)
  268. {
  269. // grow the indexes on the max side
  270. maxChildKeyByte = child._keyByte;
  271. childrenIndexes = new byte[maxChildKeyByte - minChildKeyByte + 1];
  272. Array.Copy(_childrenIndexes, 0, childrenIndexes, 0, _childrenIndexes.Length);
  273. for (var i = _childrenIndexes.Length; i < childrenIndexes.Length; i++)
  274. {
  275. childrenIndexes[i] = 255;
  276. }
  277. }
  278. childrenIndexes[child._keyByte - minChildKeyByte] = (byte)(children.Length - 1);
  279. _children = children;
  280. _childrenIndexes = childrenIndexes;
  281. _minChildKeyByte = minChildKeyByte;
  282. }
  283. else if (_onlyChild != null)
  284. {
  285. // switch from having an _onlyChild to having two _children
  286. var children = new BsonTrieNode<TValue>[2];
  287. children[0] = _onlyChild;
  288. children[1] = child;
  289. var minChildKeyByte = _onlyChild._keyByte;
  290. var maxChildKeyByte = child._keyByte;
  291. if (minChildKeyByte > maxChildKeyByte)
  292. {
  293. minChildKeyByte = child._keyByte;
  294. maxChildKeyByte = _onlyChild._keyByte;
  295. }
  296. var childrenIndexes = new byte[maxChildKeyByte - minChildKeyByte + 1];
  297. for (var i = 0; i < childrenIndexes.Length; i++)
  298. {
  299. childrenIndexes[i] = 255;
  300. }
  301. childrenIndexes[_onlyChild._keyByte - minChildKeyByte] = 0;
  302. childrenIndexes[child._keyByte - minChildKeyByte] = 1;
  303. _onlyChild = null;
  304. _children = children;
  305. _childrenIndexes = childrenIndexes;
  306. _minChildKeyByte = minChildKeyByte;
  307. }
  308. else
  309. {
  310. _onlyChild = child;
  311. }
  312. }
  313. internal void SetValue(string elementName, TValue value)
  314. {
  315. if (elementName == null)
  316. {
  317. throw new ArgumentNullException("elementName");
  318. }
  319. if (_elementName != null)
  320. {
  321. throw new InvalidOperationException("BsonTrieNode already has a value.");
  322. }
  323. _elementName = elementName;
  324. _value = value;
  325. }
  326. }
  327. }