HashTable.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheet;
  3. /**
  4. * @template T of IComparable
  5. */
  6. class HashTable
  7. {
  8. /**
  9. * HashTable elements.
  10. *
  11. * @var T[]
  12. */
  13. protected $items = [];
  14. /**
  15. * HashTable key map.
  16. *
  17. * @var string[]
  18. */
  19. protected $keyMap = [];
  20. /**
  21. * Create a new \PhpOffice\PhpSpreadsheet\HashTable.
  22. *
  23. * @param T[] $pSource Optional source array to create HashTable from
  24. */
  25. public function __construct($pSource = null)
  26. {
  27. if ($pSource !== null) {
  28. // Create HashTable
  29. $this->addFromSource($pSource);
  30. }
  31. }
  32. /**
  33. * Add HashTable items from source.
  34. *
  35. * @param T[] $pSource Source array to create HashTable from
  36. */
  37. public function addFromSource(?array $pSource = null): void
  38. {
  39. // Check if an array was passed
  40. if ($pSource == null) {
  41. return;
  42. }
  43. foreach ($pSource as $item) {
  44. $this->add($item);
  45. }
  46. }
  47. /**
  48. * Add HashTable item.
  49. *
  50. * @param T $pSource Item to add
  51. */
  52. public function add(IComparable $pSource): void
  53. {
  54. $hash = $pSource->getHashCode();
  55. if (!isset($this->items[$hash])) {
  56. $this->items[$hash] = $pSource;
  57. $this->keyMap[count($this->items) - 1] = $hash;
  58. }
  59. }
  60. /**
  61. * Remove HashTable item.
  62. *
  63. * @param T $pSource Item to remove
  64. */
  65. public function remove(IComparable $pSource): void
  66. {
  67. $hash = $pSource->getHashCode();
  68. if (isset($this->items[$hash])) {
  69. unset($this->items[$hash]);
  70. $deleteKey = -1;
  71. foreach ($this->keyMap as $key => $value) {
  72. if ($deleteKey >= 0) {
  73. $this->keyMap[$key - 1] = $value;
  74. }
  75. if ($value == $hash) {
  76. $deleteKey = $key;
  77. }
  78. }
  79. unset($this->keyMap[count($this->keyMap) - 1]);
  80. }
  81. }
  82. /**
  83. * Clear HashTable.
  84. */
  85. public function clear(): void
  86. {
  87. $this->items = [];
  88. $this->keyMap = [];
  89. }
  90. /**
  91. * Count.
  92. *
  93. * @return int
  94. */
  95. public function count()
  96. {
  97. return count($this->items);
  98. }
  99. /**
  100. * Get index for hash code.
  101. *
  102. * @param string $pHashCode
  103. *
  104. * @return int Index
  105. */
  106. public function getIndexForHashCode($pHashCode)
  107. {
  108. return array_search($pHashCode, $this->keyMap);
  109. }
  110. /**
  111. * Get by index.
  112. *
  113. * @param int $pIndex
  114. *
  115. * @return null|T
  116. */
  117. public function getByIndex($pIndex)
  118. {
  119. if (isset($this->keyMap[$pIndex])) {
  120. return $this->getByHashCode($this->keyMap[$pIndex]);
  121. }
  122. return null;
  123. }
  124. /**
  125. * Get by hashcode.
  126. *
  127. * @param string $pHashCode
  128. *
  129. * @return null|T
  130. */
  131. public function getByHashCode($pHashCode)
  132. {
  133. if (isset($this->items[$pHashCode])) {
  134. return $this->items[$pHashCode];
  135. }
  136. return null;
  137. }
  138. /**
  139. * HashTable to array.
  140. *
  141. * @return T[]
  142. */
  143. public function toArray()
  144. {
  145. return $this->items;
  146. }
  147. /**
  148. * Implement PHP __clone to create a deep clone, not just a shallow copy.
  149. */
  150. public function __clone()
  151. {
  152. $vars = get_object_vars($this);
  153. foreach ($vars as $key => $value) {
  154. // each member of this class is an array
  155. if (is_array($value)) {
  156. $array1 = $value;
  157. foreach ($array1 as $key1 => $value1) {
  158. if (is_object($value1)) {
  159. $array1[$key1] = clone $value1;
  160. }
  161. }
  162. $this->$key = $array1;
  163. }
  164. }
  165. }
  166. }