Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

771 lines
17KB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Threading;
  5. using UnityEngine;
  6. namespace Svelto.DataStructures
  7. {
  8. public struct FasterListEnumerator<T> : IEnumerator<T>
  9. {
  10. public T Current
  11. {
  12. get { return _current; }
  13. }
  14. public FasterListEnumerator(T[] buffer, int size)
  15. {
  16. _size = size;
  17. _counter = 0;
  18. _buffer = buffer;
  19. _current = default(T);
  20. }
  21. object IEnumerator.Current
  22. {
  23. get { return _current; }
  24. }
  25. T IEnumerator<T>.Current
  26. {
  27. get { return _current; }
  28. }
  29. public void Dispose()
  30. {
  31. _buffer = null;
  32. }
  33. public bool MoveNext()
  34. {
  35. if (_counter < _size)
  36. {
  37. _current = _buffer[_counter++];
  38. return true;
  39. }
  40. _current = default(T);
  41. return false;
  42. }
  43. public void Reset()
  44. {
  45. _counter = 0;
  46. }
  47. bool IEnumerator.MoveNext()
  48. {
  49. return MoveNext();
  50. }
  51. void IEnumerator.Reset()
  52. {
  53. Reset();
  54. }
  55. T[] _buffer;
  56. int _counter;
  57. int _size;
  58. T _current;
  59. }
  60. public struct FasterListEnumeratorCast<T, U> : IEnumerator<T> where T:U
  61. {
  62. public T Current
  63. {
  64. get { return (T)_buffer.Current; }
  65. }
  66. public FasterListEnumeratorCast(FasterListEnumerator<U> buffer)
  67. {
  68. _buffer = buffer;
  69. }
  70. object IEnumerator.Current
  71. {
  72. get { return (T)_buffer.Current; }
  73. }
  74. T IEnumerator<T>.Current
  75. {
  76. get { return (T)_buffer.Current; }
  77. }
  78. public void Dispose()
  79. {}
  80. public bool MoveNext()
  81. {
  82. return _buffer.MoveNext();
  83. }
  84. public void Reset()
  85. {
  86. _buffer.Reset();
  87. }
  88. bool IEnumerator.MoveNext()
  89. {
  90. return MoveNext();
  91. }
  92. void IEnumerator.Reset()
  93. {
  94. Reset();
  95. }
  96. FasterListEnumerator<U> _buffer;
  97. }
  98. public struct FasterReadOnlyList<T> : IList<T>
  99. {
  100. public int Count { get { return _list.Count; } }
  101. public bool IsReadOnly { get { return true; } }
  102. public FasterReadOnlyList(FasterList<T> list)
  103. {
  104. _list = list;
  105. }
  106. public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } }
  107. public FasterListEnumerator<T> GetEnumerator()
  108. {
  109. return _list.GetEnumerator();
  110. }
  111. public void Add(T item)
  112. {
  113. throw new NotImplementedException();
  114. }
  115. public void Clear()
  116. {
  117. throw new NotImplementedException();
  118. }
  119. public bool Contains(T item)
  120. {
  121. return _list.Contains(item);
  122. }
  123. public void CopyTo(T[] array, int arrayIndex)
  124. {
  125. _list.CopyTo(array, arrayIndex);
  126. }
  127. public bool Remove(T item)
  128. {
  129. throw new NotImplementedException();
  130. }
  131. public int IndexOf(T item)
  132. {
  133. return _list.IndexOf(item);
  134. }
  135. public void Insert(int index, T item)
  136. {
  137. throw new NotImplementedException();
  138. }
  139. public void RemoveAt(int index)
  140. {
  141. throw new NotImplementedException();
  142. }
  143. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  144. {
  145. return GetEnumerator();
  146. }
  147. IEnumerator IEnumerable.GetEnumerator()
  148. {
  149. return GetEnumerator();
  150. }
  151. readonly FasterList<T> _list;
  152. }
  153. public struct FasterListThreadSafe<T> : IList<T>
  154. {
  155. public FasterListThreadSafe(FasterList<T> list)
  156. {
  157. _list = list;
  158. _lockQ = new ReaderWriterLockSlim();
  159. }
  160. public int Count
  161. {
  162. get
  163. {
  164. _lockQ.EnterReadLock();
  165. try
  166. {
  167. return _list.Count;
  168. }
  169. finally
  170. {
  171. _lockQ.ExitReadLock();
  172. }
  173. }
  174. }
  175. public bool IsReadOnly { get { return false; } }
  176. public T this[int index]
  177. {
  178. get
  179. {
  180. _lockQ.EnterReadLock();
  181. try
  182. {
  183. return _list[index];
  184. }
  185. finally
  186. {
  187. _lockQ.ExitReadLock();
  188. }
  189. }
  190. set
  191. {
  192. _lockQ.EnterWriteLock();
  193. try
  194. {
  195. _list[index] = value;
  196. }
  197. finally
  198. {
  199. _lockQ.ExitWriteLock();
  200. }
  201. }
  202. }
  203. public FasterListEnumerator<T> GetEnumerator()
  204. {
  205. throw new NotImplementedException();
  206. }
  207. public void Add(T item)
  208. {
  209. _lockQ.EnterWriteLock();
  210. try
  211. {
  212. _list.Add(item);
  213. }
  214. finally
  215. {
  216. _lockQ.ExitWriteLock();
  217. }
  218. }
  219. public void Clear()
  220. {
  221. _lockQ.EnterWriteLock();
  222. try
  223. {
  224. _list.Clear();
  225. }
  226. finally
  227. {
  228. _lockQ.ExitWriteLock();
  229. }
  230. }
  231. public bool Contains(T item)
  232. {
  233. _lockQ.EnterReadLock();
  234. try
  235. {
  236. return _list.Contains(item);
  237. }
  238. finally
  239. {
  240. _lockQ.ExitReadLock();
  241. }
  242. }
  243. public void CopyTo(T[] array, int arrayIndex)
  244. {
  245. _lockQ.EnterWriteLock();
  246. try
  247. {
  248. _list.CopyTo(array, arrayIndex);
  249. }
  250. finally
  251. {
  252. _lockQ.ExitWriteLock();
  253. }
  254. }
  255. public bool Remove(T item)
  256. {
  257. _lockQ.EnterWriteLock();
  258. try
  259. {
  260. return _list.Remove(item);
  261. }
  262. finally
  263. {
  264. _lockQ.ExitWriteLock();
  265. }
  266. }
  267. public int IndexOf(T item)
  268. {
  269. _lockQ.EnterReadLock();
  270. try
  271. {
  272. return _list.IndexOf(item);
  273. }
  274. finally
  275. {
  276. _lockQ.ExitReadLock();
  277. }
  278. }
  279. public void Insert(int index, T item)
  280. {
  281. _lockQ.EnterWriteLock();
  282. try
  283. {
  284. _list.Insert(index, item);
  285. }
  286. finally
  287. {
  288. _lockQ.ExitWriteLock();
  289. }
  290. }
  291. public void RemoveAt(int index)
  292. {
  293. _lockQ.EnterWriteLock();
  294. try
  295. {
  296. _list.RemoveAt(index);
  297. }
  298. finally
  299. {
  300. _lockQ.ExitWriteLock();
  301. }
  302. }
  303. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  304. {
  305. throw new NotImplementedException();
  306. }
  307. IEnumerator IEnumerable.GetEnumerator()
  308. {
  309. throw new NotImplementedException();
  310. }
  311. readonly FasterList<T> _list;
  312. readonly ReaderWriterLockSlim _lockQ;
  313. }
  314. public struct FasterReadOnlyListCast<T, U> : IList<U> where U:T
  315. {
  316. public static FasterList<T> DefaultList = new FasterList<T>();
  317. public int Count { get { return _list.Count; } }
  318. public bool IsReadOnly { get { return true; } }
  319. public FasterReadOnlyListCast(FasterList<T> list)
  320. {
  321. _list = list;
  322. }
  323. public U this[int index] { get { return (U)_list[index]; } set { throw new NotImplementedException(); } }
  324. public FasterListEnumeratorCast<U, T> GetEnumerator()
  325. {
  326. return new FasterListEnumeratorCast<U, T>(_list.GetEnumerator());
  327. }
  328. public void Add(U item)
  329. {
  330. throw new NotImplementedException();
  331. }
  332. public void Clear()
  333. {
  334. throw new NotImplementedException();
  335. }
  336. public bool Contains(U item)
  337. {
  338. return _list.Contains(item);
  339. }
  340. public void CopyTo(U[] array, int arrayIndex)
  341. {
  342. throw new NotImplementedException();
  343. }
  344. public bool Remove(U item)
  345. {
  346. throw new NotImplementedException();
  347. }
  348. public int IndexOf(U item)
  349. {
  350. return _list.IndexOf(item);
  351. }
  352. public void Insert(int index, U item)
  353. {
  354. throw new NotImplementedException();
  355. }
  356. public void RemoveAt(int index)
  357. {
  358. throw new NotImplementedException();
  359. }
  360. IEnumerator<U> IEnumerable<U>.GetEnumerator()
  361. {
  362. return GetEnumerator();
  363. }
  364. IEnumerator IEnumerable.GetEnumerator()
  365. {
  366. return GetEnumerator();
  367. }
  368. readonly FasterList<T> _list;
  369. }
  370. public class FasterList<T> : IList<T>
  371. {
  372. const int MIN_SIZE = 4;
  373. public int Count
  374. {
  375. get { return _count; }
  376. }
  377. public bool IsReadOnly
  378. {
  379. get { return false; }
  380. }
  381. public FasterList()
  382. {
  383. _count = 0;
  384. _buffer = new T[MIN_SIZE];
  385. }
  386. public FasterList(int initialSize)
  387. {
  388. _count = 0;
  389. _buffer = new T[initialSize];
  390. }
  391. public FasterList(ICollection<T> collection)
  392. {
  393. _buffer = new T[collection.Count];
  394. collection.CopyTo(_buffer, 0);
  395. _count = _buffer.Length;
  396. }
  397. public FasterList(FasterList<T> listCopy)
  398. {
  399. _buffer = new T[listCopy.Count];
  400. listCopy.CopyTo(_buffer, 0);
  401. _count = listCopy.Count;
  402. }
  403. public T this[int i]
  404. {
  405. get { DesignByContract.Check.Require(i < _count, "out of bound index"); return _buffer[i]; }
  406. set { DesignByContract.Check.Require(i < _count, "out of bound index"); _buffer[i] = value; }
  407. }
  408. public void Add(T item)
  409. {
  410. if (_count == _buffer.Length)
  411. AllocateMore();
  412. _buffer[_count++] = item;
  413. }
  414. /// <summary>
  415. /// this is a dirtish trick to be able to use the index operastor
  416. /// before adding the elements through the Add functions
  417. /// </summary>
  418. /// <typeparam name="U"></typeparam>
  419. /// <param name="initialSize"></param>
  420. /// <returns></returns>
  421. public static FasterList<T> PreFill<U>(int initialSize) where U:T, new()
  422. {
  423. var list = new FasterList<T>(initialSize);
  424. for (int i = 0; i < initialSize; i++)
  425. list.Add(new U());
  426. list.Clear();
  427. return list;
  428. }
  429. public void AddRange(IEnumerable<T> items, int count)
  430. {
  431. AddRange(items.GetEnumerator(), count);
  432. }
  433. public void AddRange(IEnumerator<T> items, int count)
  434. {
  435. if (_count + count >= _buffer.Length)
  436. AllocateMore(_count + count);
  437. while (items.MoveNext())
  438. _buffer[_count++] = items.Current;
  439. }
  440. public void AddRange(ICollection<T> items)
  441. {
  442. AddRange(items.GetEnumerator(), items.Count);
  443. }
  444. public void AddRange(FasterList<T> items)
  445. {
  446. AddRange(items.ToArrayFast(), items.Count);
  447. }
  448. public void AddRange(T[] items, int count)
  449. {
  450. if (count == 0) return;
  451. if (_count + count >= _buffer.Length)
  452. AllocateMore(_count + count);
  453. Array.Copy(items, 0, _buffer, _count, count);
  454. _count += count;
  455. }
  456. public FasterReadOnlyList<T> AsReadOnly()
  457. {
  458. return new FasterReadOnlyList<T>(this);
  459. }
  460. /// <summary>
  461. /// Careful, you could keep on holding references you don't want to hold to anymore
  462. /// Use DeepClear in case.
  463. /// </summary>
  464. public void Clear()
  465. {
  466. _count = 0;
  467. }
  468. public void DeepClear()
  469. {
  470. Array.Clear(_buffer, 0, _buffer.Length);
  471. _count = 0;
  472. }
  473. public bool Contains(T item)
  474. {
  475. var index = IndexOf(item);
  476. return index != -1;
  477. }
  478. public void CopyTo(T[] array, int arrayIndex)
  479. {
  480. Array.Copy(_buffer, 0, array, arrayIndex, Count);
  481. }
  482. public FasterListEnumerator<T> GetEnumerator()
  483. {
  484. return new FasterListEnumerator<T>(_buffer, Count);
  485. }
  486. public int IndexOf(T item)
  487. {
  488. var comp = EqualityComparer<T>.Default;
  489. for (var index = _count - 1; index >= 0; --index)
  490. if (comp.Equals(_buffer[index], item))
  491. return index;
  492. return -1;
  493. }
  494. public void Insert(int index, T item)
  495. {
  496. DesignByContract.Check.Require(index < _count, "out of bound index");
  497. if (_count == _buffer.Length) AllocateMore();
  498. Array.Copy(_buffer, index, _buffer, index + 1, _count - index);
  499. _buffer[index] = item;
  500. ++_count;
  501. }
  502. public void Release()
  503. {
  504. _count = 0;
  505. _buffer = null;
  506. }
  507. public bool Remove(T item)
  508. {
  509. var index = IndexOf(item);
  510. if (index == -1)
  511. return false;
  512. RemoveAt(index);
  513. return true;
  514. }
  515. public void RemoveAt(int index)
  516. {
  517. DesignByContract.Check.Require(index < _count, "out of bound index");
  518. if (index == --_count)
  519. return;
  520. Array.Copy(_buffer, index + 1, _buffer, index, _count - index);
  521. _buffer[_count] = default(T);
  522. }
  523. public void Resize(int newSize)
  524. {
  525. if (newSize < MIN_SIZE)
  526. newSize = MIN_SIZE;
  527. Array.Resize(ref _buffer, newSize);
  528. _count = newSize;
  529. }
  530. public void SetAt(int index, T value)
  531. {
  532. if (index >= _buffer.Length)
  533. AllocateMore(index + 1);
  534. if (_count <= index)
  535. _count = index + 1;
  536. this[index] = value;
  537. }
  538. public void Sort(IComparer<T> comparer)
  539. {
  540. Array.Sort(_buffer, 0, _count, comparer);
  541. }
  542. public T[] ToArray()
  543. {
  544. T[] destinationArray = new T[_count];
  545. Array.Copy(_buffer, 0, destinationArray, 0, _count);
  546. return destinationArray;
  547. }
  548. /// <summary>
  549. /// This function exists to allow fast iterations. The size of the array returned cannot be
  550. /// used. The list count must be used instead.
  551. /// </summary>
  552. /// <returns></returns>
  553. public T[] ToArrayFast()
  554. {
  555. return _buffer;
  556. }
  557. public bool UnorderredRemove(T item)
  558. {
  559. var index = IndexOf(item);
  560. if (index == -1)
  561. return false;
  562. UnorderredRemoveAt(index);
  563. return true;
  564. }
  565. public T UnorderredRemoveAt(int index)
  566. {
  567. DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index");
  568. T item = _buffer[index];
  569. if (index == --_count)
  570. return item;
  571. T swap = _buffer[index];
  572. _buffer[index] = _buffer[_count];
  573. _buffer[_count] = swap;
  574. return item;
  575. }
  576. IEnumerator IEnumerable.GetEnumerator()
  577. {
  578. return GetEnumerator();
  579. }
  580. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  581. {
  582. return GetEnumerator();
  583. }
  584. void AllocateMore()
  585. {
  586. var newList = new T[Mathf.Max(_buffer.Length << 1, MIN_SIZE)];
  587. if (_count > 0) _buffer.CopyTo(newList, 0);
  588. _buffer = newList;
  589. }
  590. void AllocateMore(int newSize)
  591. {
  592. var oldLength = Mathf.Max(_buffer.Length, MIN_SIZE);
  593. while (oldLength < newSize)
  594. oldLength <<= 1;
  595. var newList = new T[oldLength];
  596. if (_count > 0) Array.Copy(_buffer, newList, _count);
  597. _buffer = newList;
  598. }
  599. public void Trim()
  600. {
  601. if (_count < _buffer.Length)
  602. Resize(_count);
  603. }
  604. public bool Reuse(int index, out T result)
  605. {
  606. result = default(T);
  607. if (index >= _buffer.Length)
  608. return false;
  609. result = _buffer[index];
  610. return result != null;
  611. }
  612. T[] _buffer;
  613. int _count;
  614. }
  615. }