暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

NativeMultiHashMap.cs 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Runtime.InteropServices;
  6. using Unity.Burst;
  7. using Unity.Collections.LowLevel.Unsafe;
  8. using Unity.Collections.NotBurstCompatible;
  9. using Unity.Jobs;
  10. namespace Unity.Collections
  11. {
  12. /// <summary>
  13. /// An iterator over all values associated with an individual key in a multi hash map.
  14. /// </summary>
  15. /// <remarks>The iteration order over the values associated with a key is an implementation detail. Do not rely upon any particular ordering.</remarks>
  16. /// <typeparam name="TKey">The type of the keys.</typeparam>
  17. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  18. public struct NativeMultiHashMapIterator<TKey>
  19. where TKey : struct
  20. {
  21. internal TKey key;
  22. internal int NextEntryIndex;
  23. internal int EntryIndex;
  24. /// <summary>
  25. /// Returns the entry index.
  26. /// </summary>
  27. /// <returns>The entry index.</returns>
  28. public int GetEntryIndex() => EntryIndex;
  29. }
  30. /// <summary>
  31. /// An unordered, expandable associative array. Each key can have more than one associated value.
  32. /// </summary>
  33. /// <remarks>
  34. /// Unlike a regular NativeHashMap, a NativeMultiHashMap can store multiple key-value pairs with the same key.
  35. ///
  36. /// The keys are not deduplicated: two key-value pairs with the same key are stored as fully separate key-value pairs.
  37. /// </remarks>
  38. /// <typeparam name="TKey">The type of the keys.</typeparam>
  39. /// <typeparam name="TValue">The type of the values.</typeparam>
  40. [StructLayout(LayoutKind.Sequential)]
  41. [NativeContainer]
  42. [DebuggerTypeProxy(typeof(NativeMultiHashMapDebuggerTypeProxy<,>))]
  43. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  44. public unsafe struct NativeMultiHashMap<TKey, TValue>
  45. : INativeDisposable
  46. , IEnumerable<KeyValue<TKey, TValue>> // Used by collection initializers.
  47. where TKey : struct, IEquatable<TKey>
  48. where TValue : struct
  49. {
  50. internal UnsafeMultiHashMap<TKey, TValue> m_MultiHashMapData;
  51. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  52. internal AtomicSafetyHandle m_Safety;
  53. internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeMultiHashMap<TKey, TValue>>();
  54. #if REMOVE_DISPOSE_SENTINEL
  55. #else
  56. [NativeSetClassTypeToNullOnSchedule]
  57. internal DisposeSentinel m_DisposeSentinel;
  58. #endif
  59. #endif
  60. /// <summary>
  61. /// Returns a newly allocated multi hash map.
  62. /// </summary>
  63. /// <param name="capacity">The number of key-value pairs that should fit in the initial allocation.</param>
  64. /// <param name="allocator">The allocator to use.</param>
  65. public NativeMultiHashMap(int capacity, AllocatorManager.AllocatorHandle allocator)
  66. : this(capacity, allocator, 2)
  67. {
  68. }
  69. [BurstCompatible(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })]
  70. internal void Initialize<U>(int capacity, ref U allocator, int disposeSentinelStackDepth)
  71. where U : unmanaged, AllocatorManager.IAllocator
  72. {
  73. m_MultiHashMapData = new UnsafeMultiHashMap<TKey, TValue>(capacity, allocator.Handle);
  74. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  75. #if REMOVE_DISPOSE_SENTINEL
  76. m_Safety = CollectionHelper.CreateSafetyHandle(allocator);
  77. #else
  78. if (allocator.IsCustomAllocator)
  79. {
  80. m_Safety = AtomicSafetyHandle.Create();
  81. m_DisposeSentinel = null;
  82. }
  83. else
  84. {
  85. DisposeSentinel.Create(out m_Safety, out m_DisposeSentinel, disposeSentinelStackDepth, allocator.ToAllocator);
  86. }
  87. #endif
  88. CollectionHelper.SetStaticSafetyId<NativeMultiHashMap<TKey, TValue>>(ref m_Safety, ref s_staticSafetyId.Data);
  89. AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite(m_Safety, true);
  90. #endif
  91. }
  92. NativeMultiHashMap(int capacity, AllocatorManager.AllocatorHandle allocator, int disposeSentinelStackDepth)
  93. {
  94. this = default;
  95. Initialize(capacity, ref allocator, disposeSentinelStackDepth);
  96. }
  97. /// <summary>
  98. /// Whether this hash map is empty.
  99. /// </summary>
  100. /// <value>True if the hash map is empty or if the hash map has not been constructed.</value>
  101. public bool IsEmpty
  102. {
  103. get
  104. {
  105. CheckRead();
  106. return m_MultiHashMapData.IsEmpty;
  107. }
  108. }
  109. /// <summary>
  110. /// Returns the current number of key-value pairs in this hash map.
  111. /// </summary>
  112. /// <remarks>Key-value pairs with matching keys are counted as separate, individual pairs.</remarks>
  113. /// <returns>The current number of key-value pairs in this hash map.</returns>
  114. public int Count()
  115. {
  116. CheckRead();
  117. return m_MultiHashMapData.Count();
  118. }
  119. /// <summary>
  120. /// Returns the number of key-value pairs that fit in the current allocation.
  121. /// </summary>
  122. /// <value>The number of key-value pairs that fit in the current allocation.</value>
  123. /// <param name="value">A new capacity. Must be larger than the current capacity.</param>
  124. /// <exception cref="Exception">Thrown if `value` is less than the current capacity.</exception>
  125. public int Capacity
  126. {
  127. get
  128. {
  129. CheckRead();
  130. return m_MultiHashMapData.Capacity;
  131. }
  132. set
  133. {
  134. CheckWrite();
  135. m_MultiHashMapData.Capacity = value;
  136. }
  137. }
  138. /// <summary>
  139. /// Removes all key-value pairs.
  140. /// </summary>
  141. /// <remarks>Does not change the capacity.</remarks>
  142. public void Clear()
  143. {
  144. CheckWrite();
  145. m_MultiHashMapData.Clear();
  146. }
  147. /// <summary>
  148. /// Adds a new key-value pair.
  149. /// </summary>
  150. /// <remarks>
  151. /// If a key-value pair with this key is already present, an additional separate key-value pair is added.
  152. /// </remarks>
  153. /// <param name="key">The key to add.</param>
  154. /// <param name="item">The value to add.</param>
  155. public void Add(TKey key, TValue item)
  156. {
  157. CheckWrite();
  158. m_MultiHashMapData.Add(key, item);
  159. }
  160. /// <summary>
  161. /// Removes a key and its associated value(s).
  162. /// </summary>
  163. /// <param name="key">The key to remove.</param>
  164. /// <returns>The number of removed key-value pairs. If the key was not present, returns 0.</returns>
  165. public int Remove(TKey key)
  166. {
  167. CheckWrite();
  168. return m_MultiHashMapData.Remove(key);
  169. }
  170. /// <summary>
  171. /// Removes a single key-value pair.
  172. /// </summary>
  173. /// <param name="it">An iterator representing the key-value pair to remove.</param>
  174. /// <exception cref="InvalidOperationException">Thrown if the iterator is invalid.</exception>
  175. public void Remove(NativeMultiHashMapIterator<TKey> it)
  176. {
  177. CheckWrite();
  178. m_MultiHashMapData.Remove(it);
  179. }
  180. /// <summary>
  181. /// Gets an iterator for a key.
  182. /// </summary>
  183. /// <param name="key">The key.</param>
  184. /// <param name="item">Outputs the associated value represented by the iterator.</param>
  185. /// <param name="it">Outputs an iterator.</param>
  186. /// <returns>True if the key was present.</returns>
  187. public bool TryGetFirstValue(TKey key, out TValue item, out NativeMultiHashMapIterator<TKey> it)
  188. {
  189. CheckRead();
  190. return m_MultiHashMapData.TryGetFirstValue(key, out item, out it);
  191. }
  192. /// <summary>
  193. /// Advances an iterator to the next value associated with its key.
  194. /// </summary>
  195. /// <param name="item">Outputs the next value.</param>
  196. /// <param name="it">A reference to the iterator to advance.</param>
  197. /// <returns>True if the key was present and had another value.</returns>
  198. public bool TryGetNextValue(out TValue item, ref NativeMultiHashMapIterator<TKey> it)
  199. {
  200. CheckRead();
  201. return m_MultiHashMapData.TryGetNextValue(out item, ref it);
  202. }
  203. /// <summary>
  204. /// Returns true if a given key is present in this hash map.
  205. /// </summary>
  206. /// <param name="key">The key to look up.</param>
  207. /// <returns>True if the key was present in this hash map.</returns>
  208. public bool ContainsKey(TKey key)
  209. {
  210. return TryGetFirstValue(key, out var temp0, out var temp1);
  211. }
  212. /// <summary>
  213. /// Returns the number of values associated with a given key.
  214. /// </summary>
  215. /// <param name="key">The key to look up.</param>
  216. /// <returns>The number of values associated with the key. Returns 0 if the key was not present.</returns>
  217. public int CountValuesForKey(TKey key)
  218. {
  219. if (!TryGetFirstValue(key, out var value, out var iterator))
  220. {
  221. return 0;
  222. }
  223. var count = 1;
  224. while (TryGetNextValue(out value, ref iterator))
  225. {
  226. count++;
  227. }
  228. return count;
  229. }
  230. /// <summary>
  231. /// Sets a new value for an existing key-value pair.
  232. /// </summary>
  233. /// <param name="item">The new value.</param>
  234. /// <param name="it">The iterator representing a key-value pair.</param>
  235. /// <returns>True if a value was overwritten.</returns>
  236. public bool SetValue(TValue item, NativeMultiHashMapIterator<TKey> it)
  237. {
  238. CheckWrite();
  239. return m_MultiHashMapData.SetValue(item, it);
  240. }
  241. /// <summary>
  242. /// Whether this hash map has been allocated (and not yet deallocated).
  243. /// </summary>
  244. /// <value>True if this hash map has been allocated (and not yet deallocated).</value>
  245. public bool IsCreated => m_MultiHashMapData.IsCreated;
  246. /// <summary>
  247. /// Releases all resources (memory and safety handles).
  248. /// </summary>
  249. public void Dispose()
  250. {
  251. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  252. #if REMOVE_DISPOSE_SENTINEL
  253. CollectionHelper.DisposeSafetyHandle(ref m_Safety);
  254. #else
  255. DisposeSentinel.Dispose(ref m_Safety, ref m_DisposeSentinel);
  256. #endif
  257. #endif
  258. m_MultiHashMapData.Dispose();
  259. }
  260. /// <summary>
  261. /// Creates and schedules a job that will dispose this hash map.
  262. /// </summary>
  263. /// <param name="inputDeps">A job handle. The newly scheduled job will depend upon this handle.</param>
  264. /// <returns>The handle of a new job that will dispose this hash map.</returns>
  265. [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to IJobBurstSchedulable in the future */]
  266. public JobHandle Dispose(JobHandle inputDeps)
  267. {
  268. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  269. #if REMOVE_DISPOSE_SENTINEL
  270. #else
  271. // [DeallocateOnJobCompletion] is not supported, but we want the deallocation
  272. // to happen in a thread. DisposeSentinel needs to be cleared on main thread.
  273. // AtomicSafetyHandle can be destroyed after the job was scheduled (Job scheduling
  274. // will check that no jobs are writing to the container).
  275. DisposeSentinel.Clear(ref m_DisposeSentinel);
  276. #endif
  277. var jobHandle = new UnsafeHashMapDataDisposeJob { Data = new UnsafeHashMapDataDispose { m_Buffer = m_MultiHashMapData.m_Buffer, m_AllocatorLabel = m_MultiHashMapData.m_AllocatorLabel, m_Safety = m_Safety } }.Schedule(inputDeps);
  278. AtomicSafetyHandle.Release(m_Safety);
  279. #else
  280. var jobHandle = new UnsafeHashMapDataDisposeJob { Data = new UnsafeHashMapDataDispose { m_Buffer = m_MultiHashMapData.m_Buffer, m_AllocatorLabel = m_MultiHashMapData.m_AllocatorLabel } }.Schedule(inputDeps);
  281. #endif
  282. m_MultiHashMapData.m_Buffer = null;
  283. return jobHandle;
  284. }
  285. /// <summary>
  286. /// Returns an array with a copy of all the keys (in no particular order).
  287. /// </summary>
  288. /// <remarks>A key with *N* values is included *N* times in the array.
  289. ///
  290. /// Use `GetUniqueKeyArray` of <see cref="Unity.Collections.NativeHashMapExtensions"/> instead if you only want one occurrence of each key.</remarks>
  291. /// <param name="allocator">The allocator to use.</param>
  292. /// <returns>An array with a copy of all the keys (in no particular order).</returns>
  293. public NativeArray<TKey> GetKeyArray(AllocatorManager.AllocatorHandle allocator)
  294. {
  295. CheckRead();
  296. return m_MultiHashMapData.GetKeyArray(allocator);
  297. }
  298. /// <summary>
  299. /// Returns an array with a copy of all the values (in no particular order).
  300. /// </summary>
  301. /// <remarks>The values are not deduplicated. If you sort the returned array,
  302. /// you can use <see cref="Unity.Collections.NativeHashMapExtensions.Unique{T}"/> to remove duplicate values.</remarks>
  303. /// <param name="allocator">The allocator to use.</param>
  304. /// <returns>An array with a copy of all the values (in no particular order).</returns>
  305. public NativeArray<TValue> GetValueArray(AllocatorManager.AllocatorHandle allocator)
  306. {
  307. CheckRead();
  308. return m_MultiHashMapData.GetValueArray(allocator);
  309. }
  310. /// <summary>
  311. /// Returns a NativeKeyValueArrays with a copy of all the keys and values (in no particular order).
  312. /// </summary>
  313. /// <remarks>A key with *N* values is included *N* times in the array.
  314. /// </remarks>
  315. /// <param name="allocator">The allocator to use.</param>
  316. /// <returns>A NativeKeyValueArrays with a copy of all the keys and values (in no particular order).</returns>
  317. public NativeKeyValueArrays<TKey, TValue> GetKeyValueArrays(AllocatorManager.AllocatorHandle allocator)
  318. {
  319. CheckRead();
  320. return m_MultiHashMapData.GetKeyValueArrays(allocator);
  321. }
  322. /// <summary>
  323. /// Returns a parallel writer for this hash map.
  324. /// </summary>
  325. /// <returns>A parallel writer for this hash map.</returns>
  326. public ParallelWriter AsParallelWriter()
  327. {
  328. ParallelWriter writer;
  329. writer.m_Writer = m_MultiHashMapData.AsParallelWriter();
  330. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  331. writer.m_Safety = m_Safety;
  332. CollectionHelper.SetStaticSafetyId<ParallelWriter>(ref writer.m_Safety, ref s_staticSafetyId.Data);
  333. #endif
  334. return writer;
  335. }
  336. /// <summary>
  337. /// A parallel writer for a NativeMultiHashMap.
  338. /// </summary>
  339. /// <remarks>
  340. /// Use <see cref="AsParallelWriter"/> to create a parallel writer for a NativeMultiHashMap.
  341. /// </remarks>
  342. [NativeContainer]
  343. [NativeContainerIsAtomicWriteOnly]
  344. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  345. public unsafe struct ParallelWriter
  346. {
  347. internal UnsafeMultiHashMap<TKey, TValue>.ParallelWriter m_Writer;
  348. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  349. internal AtomicSafetyHandle m_Safety;
  350. internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<ParallelWriter>();
  351. #endif
  352. /// <summary>
  353. /// Returns the index of the current thread.
  354. /// </summary>
  355. /// <remarks>In a job, each thread gets its own copy of the ParallelWriter struct, and the job system assigns
  356. /// each copy the index of its thread.</remarks>
  357. /// <value>The index of the current thread.</value>
  358. public int m_ThreadIndex => m_Writer.m_ThreadIndex;
  359. /// <summary>
  360. /// Returns the number of key-value pairs that fit in the current allocation.
  361. /// </summary>
  362. /// <value>The number of key-value pairs that fit in the current allocation.</value>
  363. public int Capacity
  364. {
  365. get
  366. {
  367. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  368. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  369. #endif
  370. return m_Writer.Capacity;
  371. }
  372. }
  373. /// <summary>
  374. /// Adds a new key-value pair.
  375. /// </summary>
  376. /// <remarks>
  377. /// If a key-value pair with this key is already present, an additional separate key-value pair is added.
  378. /// </remarks>
  379. /// <param name="key">The key to add.</param>
  380. /// <param name="item">The value to add.</param>
  381. public void Add(TKey key, TValue item)
  382. {
  383. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  384. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  385. #endif
  386. m_Writer.Add(key, item);
  387. }
  388. }
  389. /// <summary>
  390. /// Returns an enumerator over the values of an individual key.
  391. /// </summary>
  392. /// <param name="key">The key to get an enumerator for.</param>
  393. /// <returns>An enumerator over the values of a key.</returns>
  394. public Enumerator GetValuesForKey(TKey key)
  395. {
  396. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  397. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  398. #endif
  399. return new Enumerator { hashmap = this, key = key, isFirst = true };
  400. }
  401. /// <summary>
  402. /// An enumerator over the values of an individual key in a multi hash map.
  403. /// </summary>
  404. /// <remarks>
  405. /// In an enumerator's initial state, <see cref="Current"/> is not valid to read.
  406. /// The first <see cref="MoveNext"/> call advances the enumerator to the first value of the key.
  407. /// </remarks>
  408. public struct Enumerator : IEnumerator<TValue>
  409. {
  410. internal NativeMultiHashMap<TKey, TValue> hashmap;
  411. internal TKey key;
  412. internal bool isFirst;
  413. TValue value;
  414. NativeMultiHashMapIterator<TKey> iterator;
  415. /// <summary>
  416. /// Does nothing.
  417. /// </summary>
  418. public void Dispose() { }
  419. /// <summary>
  420. /// Advances the enumerator to the next value of the key.
  421. /// </summary>
  422. /// <returns>True if <see cref="Current"/> is valid to read after the call.</returns>
  423. public bool MoveNext()
  424. {
  425. //Avoids going beyond the end of the collection.
  426. if (isFirst)
  427. {
  428. isFirst = false;
  429. return hashmap.TryGetFirstValue(key, out value, out iterator);
  430. }
  431. return hashmap.TryGetNextValue(out value, ref iterator);
  432. }
  433. /// <summary>
  434. /// Resets the enumerator to its initial state.
  435. /// </summary>
  436. public void Reset() => isFirst = true;
  437. /// <summary>
  438. /// The current value.
  439. /// </summary>
  440. /// <value>The current value.</value>
  441. public TValue Current => value;
  442. object IEnumerator.Current => Current;
  443. /// <summary>
  444. /// Returns this enumerator.
  445. /// </summary>
  446. /// <returns>This enumerator.</returns>
  447. public Enumerator GetEnumerator() { return this; }
  448. }
  449. /// <summary>
  450. /// Returns an enumerator over the key-value pairs of this hash map.
  451. /// </summary>
  452. /// <remarks>A key with *N* values is visited by the enumerator *N* times.</remarks>
  453. /// <returns>An enumerator over the key-value pairs of this hash map.</returns>
  454. public KeyValueEnumerator GetEnumerator()
  455. {
  456. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  457. AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow(m_Safety);
  458. var ash = m_Safety;
  459. AtomicSafetyHandle.UseSecondaryVersion(ref ash);
  460. #endif
  461. return new KeyValueEnumerator
  462. {
  463. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  464. m_Safety = ash,
  465. #endif
  466. m_Enumerator = new UnsafeHashMapDataEnumerator(m_MultiHashMapData.m_Buffer),
  467. };
  468. }
  469. /// <summary>
  470. /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
  471. /// </summary>
  472. /// <returns>Throws NotImplementedException.</returns>
  473. /// <exception cref="NotImplementedException">Method is not implemented.</exception>
  474. IEnumerator<KeyValue<TKey, TValue>> IEnumerable<KeyValue<TKey, TValue>>.GetEnumerator()
  475. {
  476. throw new NotImplementedException();
  477. }
  478. /// <summary>
  479. /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
  480. /// </summary>
  481. /// <returns>Throws NotImplementedException.</returns>
  482. /// <exception cref="NotImplementedException">Method is not implemented.</exception>
  483. IEnumerator IEnumerable.GetEnumerator()
  484. {
  485. throw new NotImplementedException();
  486. }
  487. /// <summary>
  488. /// An enumerator over the key-value pairs of a multi hash map.
  489. /// </summary>
  490. /// <remarks>A key with *N* values is visited by the enumerator *N* times.
  491. ///
  492. /// In an enumerator's initial state, <see cref="Current"/> is not valid to read.
  493. /// The first <see cref="MoveNext"/> call advances the enumerator to the first key-value pair.
  494. /// </remarks>
  495. [NativeContainer]
  496. [NativeContainerIsReadOnly]
  497. public struct KeyValueEnumerator : IEnumerator<KeyValue<TKey, TValue>>
  498. {
  499. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  500. internal AtomicSafetyHandle m_Safety;
  501. #endif
  502. internal UnsafeHashMapDataEnumerator m_Enumerator;
  503. /// <summary>
  504. /// Does nothing.
  505. /// </summary>
  506. public void Dispose() { }
  507. /// <summary>
  508. /// Advances the enumerator to the next key-value pair.
  509. /// </summary>
  510. /// <returns>True if <see cref="Current"/> is valid to read after the call.</returns>
  511. public unsafe bool MoveNext()
  512. {
  513. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  514. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  515. #endif
  516. return m_Enumerator.MoveNext();
  517. }
  518. /// <summary>
  519. /// Resets the enumerator to its initial state.
  520. /// </summary>
  521. public void Reset()
  522. {
  523. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  524. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  525. #endif
  526. m_Enumerator.Reset();
  527. }
  528. /// <summary>
  529. /// The current key-value pair.
  530. /// </summary>
  531. /// <value>The current key-value pair.</value>
  532. public KeyValue<TKey, TValue> Current
  533. {
  534. get
  535. {
  536. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  537. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  538. #endif
  539. return m_Enumerator.GetCurrent<TKey, TValue>();
  540. }
  541. }
  542. object IEnumerator.Current => Current;
  543. }
  544. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  545. void CheckRead()
  546. {
  547. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  548. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  549. #endif
  550. }
  551. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  552. void CheckWrite()
  553. {
  554. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  555. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  556. #endif
  557. }
  558. }
  559. internal sealed class NativeMultiHashMapDebuggerTypeProxy<TKey, TValue>
  560. where TKey : struct, IEquatable<TKey>, IComparable<TKey>
  561. where TValue : struct
  562. {
  563. #if !NET_DOTS
  564. NativeMultiHashMap<TKey, TValue> m_Target;
  565. public NativeMultiHashMapDebuggerTypeProxy(NativeMultiHashMap<TKey, TValue> target)
  566. {
  567. m_Target = target;
  568. }
  569. public List<ListPair<TKey, List<TValue>>> Items
  570. {
  571. get
  572. {
  573. var result = new List<ListPair<TKey, List<TValue>>>();
  574. var keys = m_Target.GetUniqueKeyArray(Allocator.Temp);
  575. using (keys.Item1)
  576. {
  577. for (var k = 0; k < keys.Item2; ++k)
  578. {
  579. var values = new List<TValue>();
  580. if (m_Target.TryGetFirstValue(keys.Item1[k], out var value, out var iterator))
  581. {
  582. do
  583. {
  584. values.Add(value);
  585. }
  586. while (m_Target.TryGetNextValue(out value, ref iterator));
  587. }
  588. result.Add(new ListPair<TKey, List<TValue>>(keys.Item1[k], values));
  589. }
  590. }
  591. return result;
  592. }
  593. }
  594. #endif
  595. }
  596. [BurstCompatible]
  597. public unsafe static class NativeMultiHashMapExtensions
  598. {
  599. [BurstCompatible(GenericTypeArguments = new[] { typeof(int), typeof(int), typeof(AllocatorManager.AllocatorHandle) })]
  600. internal static void Initialize<TKey, TValue, U>(ref this NativeMultiHashMap<TKey, TValue> nativeMultiHashMap,
  601. int capacity,
  602. ref U allocator,
  603. int disposeSentinelStackDepth = 2)
  604. where TKey : struct, IEquatable<TKey>
  605. where TValue : struct
  606. where U : unmanaged, AllocatorManager.IAllocator
  607. {
  608. nativeMultiHashMap.m_MultiHashMapData = new UnsafeMultiHashMap<TKey, TValue>(capacity, allocator.Handle);
  609. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  610. #if REMOVE_DISPOSE_SENTINEL
  611. nativeMultiHashMap.m_Safety = CollectionHelper.CreateSafetyHandle(allocator.Handle);
  612. #else
  613. if (allocator.IsCustomAllocator)
  614. {
  615. nativeMultiHashMap.m_Safety = AtomicSafetyHandle.Create();
  616. nativeMultiHashMap.m_DisposeSentinel = null;
  617. }
  618. else
  619. {
  620. DisposeSentinel.Create(out nativeMultiHashMap.m_Safety,
  621. out nativeMultiHashMap.m_DisposeSentinel,
  622. disposeSentinelStackDepth,
  623. allocator.ToAllocator);
  624. }
  625. #endif
  626. CollectionHelper.SetStaticSafetyId<NativeMultiHashMap<TKey, TValue>>(ref nativeMultiHashMap.m_Safety, ref NativeMultiHashMap<TKey, TValue>.s_staticSafetyId.Data);
  627. #endif
  628. }
  629. }
  630. }