DataStructures.pm
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:11k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Utility Functions
  3. #
  4. #  Copyright (c) 2004,2005,2006,2007 OpenKore Development Team
  5. #
  6. #  This software is open source, licensed under the GNU General Public
  7. #  License, version 2.
  8. #  Basically, this means that you're allowed to modify and distribute
  9. #  this software. However, if you distribute modified versions, you MUST
  10. #  also distribute the source code.
  11. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  12. #########################################################################
  13. ##
  14. # MODULE DESCRIPTION: Utility functions for data structure manipulation
  15. #
  16. # Various functions for manipulating data structures.
  17. package Utils::DataStructures;
  18. use strict;
  19. use Exporter;
  20. use base qw(Exporter);
  21. use FastUtils;
  22. our %EXPORT_TAGS = (
  23. # Manipulation functions for arrays which can contain "holes".
  24. arrays  => [qw( binAdd binFind binFindReverse binRemove binRemoveAndShift
  25. binRemoveAndShiftByIndex binSize )],
  26. # Functions for searching in arrays and nested data structures.
  27. finders => [qw( existsInList findIndex findIndexString findIndexString_lc findIndexString_lc_not_equip
  28. findIndexStringList_lc findLastIndex findKey findKeyString )],
  29. # Misc array functions.
  30. misc    => [qw( compactArray hashCopyByKey minHeapAdd shuffleArray )]
  31. );
  32. our @EXPORT_OK = (
  33. @{$EXPORT_TAGS{arrays}},
  34. @{$EXPORT_TAGS{finders}},
  35. @{$EXPORT_TAGS{misc}}
  36. );
  37. $EXPORT_TAGS{all} = @EXPORT_OK;
  38. ##
  39. # void binAdd(Array* array, ID)
  40. # array: a reference to an array.
  41. # ID: the element to add to @array.
  42. # Requires: defined($array)
  43. # Returns: the index of the added element.
  44. #
  45. # Add $ID to the first empty slot (that is, a slot which is set to undef)
  46. # in @array, or append it to the end of @array if there are no empty
  47. # slots.
  48. #
  49. # Example:
  50. # @list = ("ID1", undef, "ID2");
  51. # binAdd(@list, "New");   # --> Returns: 1
  52. # # Result:
  53. # # $list[0] eq "ID1"
  54. # # $list[1] eq "New"
  55. # # $list[2] eq "ID2"
  56. #
  57. # @list = ("ID1", "ID2");
  58. # binAdd(@list, "New");   # --> Returns: 2
  59. # # Result:
  60. # # $list[0] eq "ID1"
  61. # # $list[1] eq "ID2"
  62. # # $list[2] eq "New"
  63. sub binAdd {
  64. my $r_array = shift;
  65. my $ID = shift;
  66. my $i;
  67. for ($i = 0; $i <= @{$r_array};$i++) {
  68. if ($$r_array[$i] eq "") {
  69. $$r_array[$i] = $ID;
  70. return $i;
  71. }
  72. }
  73. }
  74. ##
  75. # binFind(Array *array, ID)
  76. # array: a reference to an array.
  77. # ID: the element to search for.
  78. # Returns: the index of the element for $ID, or undef is $ID
  79. #          is not an element in $array.
  80. #
  81. # Look for element $ID in $array.
  82. #
  83. # Example:
  84. # our @array = ("hello", "world", "!");
  85. # binFind(@array, "world");   # => 1
  86. # binFind(@array, "?");       # => undef
  87. # This function is written in src/auto/XSTools/misc/fastutils.xs
  88. ##
  89. # binFindReverse(Array *array, ID)
  90. #
  91. # Same as binFind() but starts looking from the end of the array
  92. # instead of from the beginning.
  93. sub binFindReverse {
  94. my $r_array = shift;
  95. my $ID = shift;
  96. my $i;
  97. for ($i = @{$r_array} - 1; $i >= 0;$i--) {
  98. if ($$r_array[$i] eq $ID) {
  99. return $i;
  100. }
  101. }
  102. }
  103. ##
  104. # void binRemove(Array *array, ID)
  105. # array: a reference to an array
  106. # ID: the element to remove.
  107. #
  108. # Find a value in $array which has the same value as $ID,
  109. # and remove it.
  110. #
  111. # Example:
  112. # our @array = ("hello", "world", "!");
  113. # # Same as: delete $array[1];
  114. # binRemove(@array, "world");
  115. sub binRemove {
  116. my $r_array = shift;
  117. my $ID = shift;
  118. my $i;
  119. for ($i = 0; $i < @{$r_array};$i++) {
  120. if ($$r_array[$i] eq $ID) {
  121. delete $$r_array[$i];
  122. last;
  123. }
  124. }
  125. }
  126. sub binRemoveAndShift {
  127. my $r_array = shift;
  128. my $ID = shift;
  129. my $found;
  130. my $i;
  131. my @newArray;
  132. for ($i = 0; $i < @{$r_array};$i++) {
  133. if ($$r_array[$i] ne $ID || $found ne "") {
  134. push @newArray, $$r_array[$i];
  135. } else {
  136. $found = $i;
  137. }
  138. }
  139. @{$r_array} = @newArray;
  140. return $found;
  141. }
  142. sub binRemoveAndShiftByIndex {
  143. my $r_array = shift;
  144. my $index = shift;
  145. my $found;
  146. my $i;
  147. my @newArray;
  148. for ($i = 0; $i < @{$r_array};$i++) {
  149. if ($i != $index) {
  150. push @newArray, $$r_array[$i];
  151. } else {
  152. $found = 1;
  153. }
  154. }
  155. @{$r_array} = @newArray;
  156. return $found;
  157. }
  158. ##
  159. # int binSize(Array *array)
  160. # r_array: a reference to an array.
  161. #
  162. # Calculates the size of $array, excluding undefined values.
  163. #
  164. # Example:
  165. # our @array = ("hello", undef, "world");
  166. # scalar @array;        # -> 3
  167. # binSize(@array);     # -> 2
  168. sub binSize {
  169. my $r_array = shift;
  170. return 0 if !defined $r_array;
  171. my $found = 0;
  172. my $i;
  173. for ($i = 0; $i < @{$r_array};$i++) {
  174. if ($$r_array[$i] ne "") {
  175. $found++;
  176. }
  177. }
  178. return $found;
  179. }
  180. ##
  181. # void compactArray(Array *array)
  182. #
  183. # Resize an array by removing undefined items.
  184. sub compactArray {
  185. my ($array) = @_;
  186. for (my $i = $#{$array}; $i >= 0; $i--) {
  187. if (!defined $array->[$i]) {
  188. splice @{$array}, $i, 1;
  189. }
  190. }
  191. }
  192. ##
  193. # boolean existsInList(list, val)
  194. # list: a string containing a list of comma-seperated items.
  195. # val: the value to check for.
  196. #
  197. # Check whether $val exists in $list. This function is case-insensitive.
  198. #
  199. # Example:
  200. # my $list = "Apple,Orange Juice";
  201. # existsInList($list, "apple"); # => 1
  202. # existsInList($list, "Orange Juice"); # => 1
  203. # existsInList($list, "juice"); # => 0
  204. sub existsInList {
  205. my ($list, $val) = @_;
  206. return 0 if ($val eq "");
  207. my @array = split / *, */, $list;
  208. $val = lc($val);
  209. foreach (@array) {
  210. s/^s+//;
  211. s/s+$//;
  212. s/s+/ /g;
  213. next if ($_ eq "");
  214. return 1 if (lc($_) eq $val);
  215. }
  216. return 0;
  217. }
  218. ##
  219. # findIndex(r_array, key, [num])
  220. # r_array: A reference to an array, which contains a hash in each element.
  221. # key: The name of the key to lookup.
  222. # num: The number to compare with.
  223. # Returns: The index in r_array of the found item, or undef if not found. Or, if not found and $num is not given: returns the index of first undefined array element, or the index of the last array element + 1.
  224. #
  225. # This function loops through the entire array, looking for a hash item whose
  226. # value equals $num.
  227. #
  228. # Example:
  229. # my @inventory;
  230. # $inventory[0]{amount} = 50;
  231. # $inventory[1]{amount} = 100;
  232. # $inventory[2] = undef;
  233. # $inventory[3]{amount} = 200;
  234. # findIndex(@inventory, "amount", 100);    # 1
  235. # findIndex(@inventory, "amount", 99);     # undef
  236. # findIndex(@inventory, "amount");         # 2
  237. #
  238. # @inventory = ();
  239. # $inventory[0]{amount} = 50;
  240. # findIndex(@inventory, "amount");         # 1
  241. sub findIndex {
  242. my $r_array = shift;
  243. return undef if !$r_array;
  244. my $key = shift;
  245. my $num = shift;
  246. if ($num ne "") {
  247. my $max = @{$r_array};
  248. for (my $i = 0; $i < $max; $i++) {
  249. return $i if (exists $r_array->[$i] && $r_array->[$i]{$key} == $num);
  250. }
  251. return undef;
  252. } else {
  253. my $max = @{$r_array};
  254. my $i;
  255. for ($i = 0; $i < $max; $i++) {
  256. return $i if (!$r_array->[$i] || !%{$r_array->[$i]});
  257. }
  258. return $i;
  259. }
  260. }
  261. ##
  262. # findIndexString(r_array, key, [str])
  263. #
  264. # Same as findIndex(), except this function compares strings, not numbers.
  265. sub findIndexString {
  266. my $r_array = shift;
  267. return undef if !$r_array;
  268. my $key = shift;
  269. my $str = shift;
  270. if ($str ne "") {
  271. my $max = @{$r_array};
  272. for (my $i = 0; $i < $max; $i++) {
  273. if (exists $r_array->[$i] && $r_array->[$i]{$key} eq $str) {
  274. return $i;
  275. }
  276. }
  277. return undef;
  278. } else {
  279. my $max = @{$r_array};
  280. my $i;
  281. for ($i = 0; $i < $max; $i++) {
  282. return $i if (!$r_array->[$i] || !%{$r_array->[$i]});
  283. }
  284. return $i;
  285. }
  286. }
  287. ##
  288. # findIndexString_lc(r_array, key, [str])
  289. #
  290. # Same has findIndexString(), except this function does case-insensitive string comparisons.
  291. sub findIndexString_lc {
  292. my $r_array = shift;
  293. return undef if !$r_array;
  294. my $key = shift;
  295. my $str = shift;
  296. if ($str ne "") {
  297. $str = lc $str;
  298. my $max = @{$r_array};
  299. for (my $i = 0; $i < $max; $i++) {
  300. return $i if (exists $r_array->[$i] && lc($r_array->[$i]{$key}) eq $str);
  301. }
  302. return undef;
  303. } else {
  304. my $max = @{$r_array};
  305. my $i;
  306. for ($i = 0; $i < $max; $i++) {
  307. return $i if (!$r_array->[$i] || !%{$r_array->[$i]});
  308. }
  309. return $i;
  310. }
  311. }
  312. our %findIndexStringList_lc_cache;
  313. sub findIndexStringList_lc {
  314. my $r_array = shift;
  315. return undef if !defined $r_array;
  316. my $match = shift;
  317. my $ID = shift;
  318. my $skipID = shift;
  319. my $max = @{$r_array};
  320. my ($i, $arr);
  321. if (exists $findIndexStringList_lc_cache{$ID}) {
  322. $arr = $findIndexStringList_lc_cache{$ID};
  323. } else {
  324. my @tmp = split / *, */, lc($ID);
  325. $arr = @tmp;
  326. %findIndexStringList_lc_cache = () if (scalar(keys %findIndexStringList_lc_cache) > 30);
  327. $findIndexStringList_lc_cache{$ID} = $arr;
  328. }
  329. foreach (@{$arr}) {
  330. for ($i = 0; $i < $max; $i++) {
  331. next if $i eq $skipID;
  332. if (exists $r_array->[$i] && lc($r_array->[$i]{$match}) eq $_) {
  333. return $i;
  334. }
  335. }
  336. }
  337. if ($ID eq "") {
  338. return $i;
  339. } else {
  340. return undef;
  341. }
  342. }
  343. ##
  344. # findIndexString_lc_not_equip(r_array, key, [str])
  345. #
  346. # Same has findIndexString(), except this function does case-insensitive string comparisons.
  347. # It only finds items which are not equipped AND are able to be equipped (identified).
  348. sub findIndexString_lc_not_equip {
  349. my $r_array = shift;
  350. return undef if !defined $r_array;
  351. my $match = shift;
  352. my $ID = lc(shift);
  353. my $i;
  354. for ($i = 0; $i < @{$r_array} ;$i++) {
  355. if ((exists $r_array->[$i] && lc($$r_array[$i]{$match}) eq $ID && ($$r_array[$i]{'identified'}) && !($$r_array[$i]{'equipped'}))
  356.  || (!$$r_array[$i] && $ID eq "")) {
  357. return $i;
  358. }
  359. }
  360. if ($ID eq "") {
  361. return $i;
  362. } else {
  363. return undef;
  364. }
  365. }
  366. sub findLastIndex {
  367. my $r_array = shift;
  368. return undef if !$r_array;
  369. my $key = shift;
  370. my $num = shift;
  371. if ($num ne "") {
  372. my $max = @{$r_array};
  373. for (my $i = $max-1; $i > -1; $i--) {
  374. return $i if (exists $r_array->[$i] && $r_array->[$i]{$key} == $num);
  375. }
  376. return undef;
  377. } else {
  378. my $max = @{$r_array};
  379. my $i;
  380. for ($i = $max-1; $i > -1; $i--) {
  381. return $i if (!$r_array->[$i] || !%{$r_array->[$i]});
  382. }
  383. return $i;
  384. }
  385. }
  386. sub findKey {
  387. my $r_hash = shift;
  388. my $match = shift;
  389. my $ID = shift;
  390. foreach (keys %{$r_hash}) {
  391. if (exists $r_hash->{$_} && $r_hash->{$_}{$match} == $ID) {
  392. return $_;
  393. }
  394. }
  395. }
  396. sub findKeyString {
  397. my $r_hash = shift;
  398. my $match = shift;
  399. my $ID = shift;
  400. foreach (keys %{$r_hash}) {
  401. if (ref($r_hash->{$_}) && $r_hash->{$_}{$match} eq $ID) {
  402. return $_;
  403. }
  404. }
  405. }
  406. ##
  407. # hashCopyByKey(Hash* target, Hash* source, keys...)
  408. #
  409. # Copies each key from the target to the source.
  410. #
  411. # For example,
  412. # <pre class="example">
  413. # hashCopyByKey(%target, %source, qw(some keys));
  414. # </pre>
  415. # would copy 'some' and 'keys' from the source hash to the
  416. # target hash.
  417. sub hashCopyByKey {
  418. my ($target, $source, @keys) = @_;
  419. foreach (@keys) {
  420. $target->{$_} = $source->{$_} if exists $source->{$_};
  421. }
  422. }
  423. sub minHeapAdd {
  424. my $r_array = shift;
  425. my $r_hash = shift;
  426. my $match = shift;
  427. my $i;
  428. my $found;
  429. my @newArray;
  430. for ($i = 0; $i < @{$r_array};$i++) {
  431. if (!$found && exists $r_array->[$i] && $$r_hash{$match} < $$r_array[$i]{$match}) {
  432. push @newArray, $r_hash;
  433. $found = 1;
  434. }
  435. push @newArray, $$r_array[$i];
  436. }
  437. if (!$found) {
  438. push @newArray, $r_hash;
  439. }
  440. @{$r_array} = @newArray;
  441. }
  442. ##
  443. # void shuffleArray(Array* array)
  444. # array: A reference to an array.
  445. #
  446. # Randomize the order of the items in the array.
  447. sub shuffleArray {
  448. my $r_array = shift;
  449. my $i = @{$r_array};
  450. my $j;
  451.         while ($i--) {
  452.                $j = int rand ($i+1);
  453.                @$r_array[$i,$j] = @$r_array[$j,$i];
  454.         }
  455. }
  456. 1;