| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package CommonsLang; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
CommonsLang - Commonly used functions for Perl language |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
8
|
|
|
|
|
|
|
use CommonsLang; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
print s_pad("a", 5, "0") . "\n"; |
|
11
|
|
|
|
|
|
|
# > "a0000" |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
print s_left("abc", 1) . "\n"; |
|
14
|
|
|
|
|
|
|
# > "a" |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
print s_right("abc", 1) . "\n"; |
|
17
|
|
|
|
|
|
|
# > "c" |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
print s_starts_with("abc", "ab") . "\n"; |
|
20
|
|
|
|
|
|
|
# > 1 |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
print s_ends_with("abc", "bc") . "\n"; |
|
23
|
|
|
|
|
|
|
# > 1 |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
* v_type_of - returns a string indicating the type of the variable. |
|
28
|
|
|
|
|
|
|
* v_cmp - compare function, usually it is used for sort. |
|
29
|
|
|
|
|
|
|
* v_max - returns the largest of the element given as input parameters, or undef if there are no parameters. |
|
30
|
|
|
|
|
|
|
* v_min - returns the smallest of the numbers given as input parameters, or undef if there are no parameters. |
|
31
|
|
|
|
|
|
|
* s_match_glob - check if a string matches a glob pattern. |
|
32
|
|
|
|
|
|
|
* s_left - returns a string containing a specified number of characters from the left side of a string. |
|
33
|
|
|
|
|
|
|
* s_right - returns a string containing a specified number of characters from the right side of a string. |
|
34
|
|
|
|
|
|
|
* s_starts_with - check whether the string begins with the characters of a specified string, returning 1 or 0 as appropriate. |
|
35
|
|
|
|
|
|
|
* s_ends_with - check whether the string ends with the characters of a specified string, returning 1 or 0 as appropriate. |
|
36
|
|
|
|
|
|
|
* s_pad - string padding. |
|
37
|
|
|
|
|
|
|
* s_trim - a new string representing str stripped of whitespace from both its beginning and end. Whitespace is defined as /\s/. |
|
38
|
|
|
|
|
|
|
* s_ellipsis - truncate the string to the specified length and add ellipsis "..." at the end of the string to indicate that the string has been truncated. |
|
39
|
|
|
|
|
|
|
* s_split - takes a pattern and divides this string into an ordered list of substrings by searching for the pattern, puts these substrings into an array, and returns the array. |
|
40
|
|
|
|
|
|
|
* a_splice - changes the contents of an array by removing or replacing existing elements and/or adding new elements in place. |
|
41
|
|
|
|
|
|
|
* a_slice - returns a shallow copy of a portion of an array into a new array |
|
42
|
|
|
|
|
|
|
* a_left - returns an array containing a specified number of elements from the left side of an array. |
|
43
|
|
|
|
|
|
|
* a_right - returns an array containing a specified number of elements from the right side of an array. |
|
44
|
|
|
|
|
|
|
* a_push - adds the specified elements to the end of an array and returns the new length of the array. |
|
45
|
|
|
|
|
|
|
* a_pop - removes the last element from an array and returns that element. This method changes the length of the array. |
|
46
|
|
|
|
|
|
|
* a_shift - removes the first element from an array and returns that removed element. This method changes the length of the array. |
|
47
|
|
|
|
|
|
|
* a_unshift - adds the specified elements to the beginning of an array and returns the new length of the array. |
|
48
|
|
|
|
|
|
|
* a_filter - creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function. |
|
49
|
|
|
|
|
|
|
* a_sort - returns a sorted array by callbackFn. The original array will not be modified. |
|
50
|
|
|
|
|
|
|
* a_concat - merge two or more arrays. This method does not change the existing arrays, but instead returns a new array. |
|
51
|
|
|
|
|
|
|
* a_find_index - returns the index of the first element in an array that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned. |
|
52
|
|
|
|
|
|
|
* a_find_last_index - iterates the array in reverse order and returns the index of the first element that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned. |
|
53
|
|
|
|
|
|
|
* a_find - returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undef is returned. |
|
54
|
|
|
|
|
|
|
* a_find_last - iterates the array in reverse order and returns the index of the first element that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned. |
|
55
|
|
|
|
|
|
|
* a_index_of - returns the first index at which a given element can be found in the array, or -1 if it is not present. |
|
56
|
|
|
|
|
|
|
* a_last_index_of - returns the first index at which a given element can be found in the array, or -1 if it is not present. |
|
57
|
|
|
|
|
|
|
* a_every - tests whether all elements in the array pass the test implemented by the provided function. It returns 1 or 0. It doesn't modify the array. |
|
58
|
|
|
|
|
|
|
* a_some - tests whether at least one element in the array passes the test implemented by the provided function. It returns 1 if, in the array, it finds an element for which the provided function returns 1; otherwise it returns 0. It doesn't modify the array. |
|
59
|
|
|
|
|
|
|
* a_map - creates a new array populated with the results of calling a provided function on every element in the calling array. |
|
60
|
|
|
|
|
|
|
* a_reduce - executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value. |
|
61
|
|
|
|
|
|
|
* a_join - creates and returns a new string by concatenating all of the elements in this array, separated by commas or a specified separator string. |
|
62
|
|
|
|
|
|
|
* h_keys - returns an array of a given hash's own enumerable names. |
|
63
|
|
|
|
|
|
|
* h_values - returns an array of a given hash's own enumerable values. |
|
64
|
|
|
|
|
|
|
* h_find - returns the k-v tuple in the provided hash that satisfies the provided testing function. If no values satisfy the testing function, undef is returned. |
|
65
|
|
|
|
|
|
|
* h_group_by - groups the elements of a given iterable according to the string values returned by a provided callback function. |
|
66
|
|
|
|
|
|
|
* h_assign - Copies all key/value from one or more source objects to a target object. |
|
67
|
|
|
|
|
|
|
* x_now_ts - get formated timestamp(YYYY-mm-ddTHH:MM:SS.SSS). |
|
68
|
|
|
|
|
|
|
* x_now_ms - get current timestamp. |
|
69
|
|
|
|
|
|
|
* x_log - print with the line number and subroutine name of caller to STDOUT. |
|
70
|
|
|
|
|
|
|
* x_debug - print with the line number and subroutine name of caller to STDOUT for debug. |
|
71
|
|
|
|
|
|
|
* x_error - print with the line number and subroutine name of caller to STDERR. |
|
72
|
|
|
|
|
|
|
* x_stack - print the call stack to STDERR. |
|
73
|
|
|
|
|
|
|
* x_fatal - print the error, and exit the perl process with code 1. |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head1 AUTHOR |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
YUPEN 12/23/24 - new |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=cut |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
our $VERSION = 0.02; |
|
82
|
|
|
|
|
|
|
|
|
83
|
30
|
|
|
30
|
|
288440
|
use Exporter; |
|
|
30
|
|
|
|
|
64
|
|
|
|
30
|
|
|
|
|
5282
|
|
|
84
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
|
85
|
|
|
|
|
|
|
@EXPORT_OK = ( |
|
86
|
|
|
|
|
|
|
v_type_of, v_cmp, |
|
87
|
|
|
|
|
|
|
v_max, v_min, |
|
88
|
|
|
|
|
|
|
s_match_glob, s_left, s_right, |
|
89
|
|
|
|
|
|
|
s_starts_with, s_ends_with, |
|
90
|
|
|
|
|
|
|
s_pad, s_trim, |
|
91
|
|
|
|
|
|
|
s_ellipsis, s_split, |
|
92
|
|
|
|
|
|
|
a_splice, a_slice, |
|
93
|
|
|
|
|
|
|
a_left, a_right, |
|
94
|
|
|
|
|
|
|
a_push, a_pop, |
|
95
|
|
|
|
|
|
|
a_shift, a_unshift, |
|
96
|
|
|
|
|
|
|
a_filter, a_sort, a_concat, |
|
97
|
|
|
|
|
|
|
a_find_index, a_find_last_index, |
|
98
|
|
|
|
|
|
|
a_find, a_find_last, |
|
99
|
|
|
|
|
|
|
a_index_of, a_last_index_of, |
|
100
|
|
|
|
|
|
|
a_every, a_some, |
|
101
|
|
|
|
|
|
|
a_map, a_reduce, a_join, |
|
102
|
|
|
|
|
|
|
h_keys, h_values, h_find, h_group_by, h_assign, |
|
103
|
|
|
|
|
|
|
x_now_ts, x_now_ms, |
|
104
|
|
|
|
|
|
|
x_log, x_debug, x_error, x_stack, x_fatal |
|
105
|
|
|
|
|
|
|
); |
|
106
|
|
|
|
|
|
|
@EXPORT = @EXPORT_OK; |
|
107
|
|
|
|
|
|
|
|
|
108
|
30
|
|
|
30
|
|
328
|
use strict; |
|
|
30
|
|
|
|
|
94
|
|
|
|
30
|
|
|
|
|
1271
|
|
|
109
|
30
|
|
|
30
|
|
19367
|
use Data::Dumper; |
|
|
30
|
|
|
|
|
300003
|
|
|
|
30
|
|
|
|
|
2836
|
|
|
110
|
30
|
|
|
30
|
|
240
|
use Carp 'croak'; |
|
|
30
|
|
|
|
|
82
|
|
|
|
30
|
|
|
|
|
2235
|
|
|
111
|
30
|
|
|
30
|
|
15848
|
use POSIX qw(floor ceil); |
|
|
30
|
|
|
|
|
237118
|
|
|
|
30
|
|
|
|
|
183
|
|
|
112
|
|
|
|
|
|
|
|
|
113
|
30
|
|
|
30
|
|
89869
|
use Env; |
|
|
30
|
|
|
|
|
85486
|
|
|
|
30
|
|
|
|
|
194
|
|
|
114
|
30
|
|
|
30
|
|
35545
|
use Time::HiRes; |
|
|
30
|
|
|
|
|
40493
|
|
|
|
30
|
|
|
|
|
195
|
|
|
115
|
30
|
|
|
30
|
|
2490
|
use File::Basename; |
|
|
30
|
|
|
|
|
136
|
|
|
|
30
|
|
|
|
|
3423
|
|
|
116
|
30
|
|
|
30
|
|
18517
|
use Time::Piece; |
|
|
30
|
|
|
|
|
498491
|
|
|
|
30
|
|
|
|
|
186
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
######################################## |
|
119
|
|
|
|
|
|
|
######################################## |
|
120
|
|
|
|
|
|
|
######################################## |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
################## |
|
123
|
|
|
|
|
|
|
# Subroutine : x_now_ms |
|
124
|
|
|
|
|
|
|
# Purpose : get current timestamp |
|
125
|
|
|
|
|
|
|
sub x_now_ms { |
|
126
|
3
|
|
|
3
|
0
|
303709
|
return int(Time::HiRes::time * 1000); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
################## |
|
130
|
|
|
|
|
|
|
# Subroutine : x_now_ts |
|
131
|
|
|
|
|
|
|
# Purpose : get formated timestamp(YYYY-mm-ddTHH:MM:SS.SSS) |
|
132
|
|
|
|
|
|
|
sub x_now_ts { |
|
133
|
2
|
|
|
2
|
0
|
13
|
my $t = localtime(); |
|
134
|
2
|
|
|
|
|
195
|
my $ms = int(x_now_ms() % 1000); |
|
135
|
2
|
|
|
|
|
12
|
return $t->strftime("%Y-%m-%dT%H:%M:%S") . "." . sprintf("%03d", $ms); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
################## |
|
139
|
|
|
|
|
|
|
sub i_log { |
|
140
|
0
|
|
|
0
|
0
|
0
|
my $dest = shift; |
|
141
|
0
|
|
|
|
|
0
|
my $level = shift; |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# locate the call info |
|
144
|
0
|
|
|
|
|
0
|
my ($package, $filename, $lineno) = caller(1); |
|
145
|
0
|
|
|
|
|
0
|
my @next_caller_info = caller(2); |
|
146
|
0
|
0
|
|
|
|
0
|
my $next_subroutine = @next_caller_info ? $next_caller_info[3] : "::"; |
|
147
|
|
|
|
|
|
|
## |
|
148
|
0
|
|
|
|
|
0
|
my ($pkg_name, $sub_name) = split("::", $next_subroutine); |
|
149
|
0
|
|
|
|
|
0
|
my ($basename, $dirname) = fileparse($filename); |
|
150
|
|
|
|
|
|
|
# |
|
151
|
0
|
|
|
|
|
0
|
my $now_ts = x_now_ts(); |
|
152
|
|
|
|
|
|
|
## print the msg string line by line |
|
153
|
0
|
|
|
|
|
0
|
my $joined_str = join("", @_); |
|
154
|
0
|
|
|
|
|
0
|
my @lines = split(/\r?\n/, $joined_str); |
|
155
|
0
|
|
|
|
|
0
|
foreach my $line (@lines) { |
|
156
|
0
|
|
|
|
|
0
|
my $msg = |
|
157
|
|
|
|
|
|
|
( "[" |
|
158
|
|
|
|
|
|
|
. $now_ts . "] " |
|
159
|
|
|
|
|
|
|
. $basename . ":" |
|
160
|
|
|
|
|
|
|
. sprintf("%4d", $lineno) . ":" |
|
161
|
|
|
|
|
|
|
. sprintf("%-20s", $sub_name) . " - " |
|
162
|
|
|
|
|
|
|
. $level . ": " |
|
163
|
|
|
|
|
|
|
. $line |
|
164
|
|
|
|
|
|
|
. "\n"); |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# https://www.perlmonks.org/?node_id=791373 |
|
167
|
|
|
|
|
|
|
# sub print_to { |
|
168
|
|
|
|
|
|
|
# print {$_[0]} $_[1]; |
|
169
|
|
|
|
|
|
|
# } |
|
170
|
|
|
|
|
|
|
# print_to (*STDOUT, "test stdout"); |
|
171
|
|
|
|
|
|
|
# print_to (*STDERR, "test stderr"); |
|
172
|
0
|
|
|
|
|
0
|
print {$dest} $msg; |
|
|
0
|
|
|
|
|
0
|
|
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
################## |
|
177
|
|
|
|
|
|
|
# Subroutine : x_log |
|
178
|
|
|
|
|
|
|
# Purpose : print with the line number and subroutine name of caller to STDOUT. |
|
179
|
|
|
|
|
|
|
sub x_log { |
|
180
|
0
|
|
|
0
|
0
|
0
|
i_log(*STDOUT, "LOG", @_); |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
################## |
|
184
|
|
|
|
|
|
|
# Subroutine : x_debug |
|
185
|
|
|
|
|
|
|
# Purpose : print with the line number and subroutine name of caller to STDOUT for debug |
|
186
|
|
|
|
|
|
|
sub x_debug { |
|
187
|
0
|
|
|
0
|
0
|
0
|
i_log(*STDOUT, "DEBUG", @_); |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
################## |
|
191
|
|
|
|
|
|
|
# Subroutine : x_error |
|
192
|
|
|
|
|
|
|
# Purpose : print with the line number and subroutine name of caller to STDERR |
|
193
|
|
|
|
|
|
|
sub x_error { |
|
194
|
0
|
|
|
0
|
0
|
0
|
i_log(*STDERR, "ERROR", @_); |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
################## |
|
198
|
|
|
|
|
|
|
# Subroutine : x_stack |
|
199
|
|
|
|
|
|
|
# Purpose : print the call stack to STDERR. |
|
200
|
|
|
|
|
|
|
sub x_stack { |
|
201
|
1
|
|
|
1
|
0
|
2
|
my $capture = shift; |
|
202
|
|
|
|
|
|
|
## |
|
203
|
1
|
|
|
|
|
2
|
my $output = []; |
|
204
|
1
|
|
|
|
|
1
|
my $level = 0; |
|
205
|
1
|
|
|
|
|
6
|
my @info = caller($level++); |
|
206
|
1
|
|
|
|
|
2
|
while (@info) { |
|
207
|
3
|
|
|
|
|
6
|
my $prefix = " " x ($level - 1); |
|
208
|
3
|
|
|
|
|
6
|
my ($package, $filename, $lineno) = @info; |
|
209
|
3
|
|
|
|
|
44
|
my ($basename) = fileparse($filename); |
|
210
|
3
|
|
|
|
|
9
|
@info = caller($level++); |
|
211
|
3
|
100
|
|
|
|
6
|
if (@info) { |
|
212
|
2
|
|
|
|
|
6
|
my ($pkg_name, $sub_name) = split("::", $info[3]); |
|
213
|
2
|
100
|
|
|
|
6
|
my $msg = "$prefix$basename:$lineno" . ($sub_name ? ", subroutine: $sub_name" : ""); |
|
214
|
2
|
50
|
|
|
|
3
|
if ($capture) { |
|
215
|
2
|
|
|
|
|
5
|
push(@$output, $msg); |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
else { |
|
218
|
0
|
|
|
|
|
0
|
i_log(*STDERR, "STACK", $msg); |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
} |
|
222
|
1
|
|
|
|
|
2
|
return $output; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
################## |
|
226
|
|
|
|
|
|
|
# Subroutine : x_fatal |
|
227
|
|
|
|
|
|
|
# Purpose : print the error, and exit the perl process with code 1. |
|
228
|
|
|
|
|
|
|
sub x_fatal { |
|
229
|
0
|
|
|
0
|
0
|
0
|
i_log(*STDERR, "FATAL", @_); |
|
230
|
0
|
|
|
|
|
0
|
exit(1); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
######################################## |
|
234
|
|
|
|
|
|
|
######################################## (scalar)variable |
|
235
|
|
|
|
|
|
|
######################################## |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
################## |
|
238
|
|
|
|
|
|
|
# Subroutine : v_type_of |
|
239
|
|
|
|
|
|
|
# Purpose : The v_type_of method returns a string indicating the type of the variable. |
|
240
|
|
|
|
|
|
|
# Input : var |
|
241
|
|
|
|
|
|
|
# Returns : string of (UNDEF, ARRAY, HASH, CODE, ..., STRING, NUMBER) |
|
242
|
|
|
|
|
|
|
sub v_type_of { |
|
243
|
574
|
|
|
574
|
0
|
1122
|
my $var = shift; |
|
244
|
574
|
50
|
|
|
|
1131
|
if (!defined($var)) { |
|
245
|
0
|
|
|
|
|
0
|
return "UNDEF"; |
|
246
|
|
|
|
|
|
|
} |
|
247
|
574
|
|
|
|
|
933
|
my $ref_type = ref($var); |
|
248
|
574
|
100
|
|
|
|
1022
|
if ($ref_type ne "") { |
|
249
|
51
|
|
|
|
|
176
|
return uc($ref_type); |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
else { |
|
252
|
523
|
50
|
|
|
|
927
|
if ($var eq "") { |
|
253
|
0
|
|
|
|
|
0
|
return "STRING"; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
else { |
|
256
|
523
|
100
|
|
|
|
1068
|
my $scalar_type = ($var ^ $var) ? "STRING" : "NUMBER"; |
|
257
|
523
|
|
|
|
|
1209
|
return $scalar_type; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
################## |
|
263
|
|
|
|
|
|
|
# Subroutine : v_cmp |
|
264
|
|
|
|
|
|
|
# Purpose : compare function, usually it is used for sort. |
|
265
|
|
|
|
|
|
|
# Input : x, y |
|
266
|
|
|
|
|
|
|
# Returns : > 0: x after y, < 0: x before y, = 0: they are equals |
|
267
|
|
|
|
|
|
|
sub v_cmp { |
|
268
|
218
|
|
|
218
|
0
|
367838
|
my ($x, $y) = @_; |
|
269
|
|
|
|
|
|
|
|
|
270
|
218
|
100
|
100
|
|
|
1250
|
if (!defined($x) and !defined($y)) { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
271
|
1
|
|
|
|
|
5
|
return 0; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
elsif (!defined($x) and defined($y)) { |
|
274
|
1
|
|
|
|
|
6
|
return -1; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
elsif (defined($x) and !defined($y)) { ## undef first |
|
277
|
1
|
|
|
|
|
24
|
return 1; |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
else { |
|
280
|
215
|
|
|
|
|
405
|
my $tx = v_type_of($x); |
|
281
|
215
|
|
|
|
|
390
|
my $ty = v_type_of($y); |
|
282
|
215
|
100
|
|
|
|
461
|
if ($tx eq $ty) { |
|
283
|
214
|
100
|
|
|
|
508
|
if ($tx eq "NUMBER") { # https://www.tutorialspoint.com/perl/perl_operators.htm |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
284
|
101
|
|
|
|
|
338
|
return $x <=> $y; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
elsif ($tx eq "STRING") { |
|
287
|
107
|
|
|
|
|
367
|
return $x cmp $y; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
elsif ($tx eq "UNDEF") { |
|
290
|
0
|
|
|
|
|
0
|
return 0; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
else { |
|
293
|
|
|
|
|
|
|
# https://stackoverflow.com/questions/37220558/how-can-i-check-for-reference-equality-in-perl |
|
294
|
6
|
100
|
|
|
|
17
|
if ($x == $y) { # check if there are same references |
|
295
|
2
|
|
|
|
|
11
|
return 0; |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
else { |
|
298
|
|
|
|
|
|
|
# -1, only mean they are not same. |
|
299
|
|
|
|
|
|
|
# return -1; |
|
300
|
|
|
|
|
|
|
# if ($tx eq "ARRAY") { |
|
301
|
|
|
|
|
|
|
# my $a_size = scalar @$x; |
|
302
|
|
|
|
|
|
|
# my $b_size = scalar @$y; |
|
303
|
|
|
|
|
|
|
# return $a_size <=> $b_size; |
|
304
|
|
|
|
|
|
|
# } elsif ($tx eq "HASH") { |
|
305
|
|
|
|
|
|
|
# my $a_size = scalar keys %$x; |
|
306
|
|
|
|
|
|
|
# my $b_size = scalar keys %$y; |
|
307
|
|
|
|
|
|
|
# return $a_size <=> $b_size; |
|
308
|
|
|
|
|
|
|
# } else { |
|
309
|
|
|
|
|
|
|
# # not able to compare. |
|
310
|
|
|
|
|
|
|
# # die "Since they are different type of variables, not able to compare. type of x is $tx, type of y is $ty"; |
|
311
|
|
|
|
|
|
|
# return -1; |
|
312
|
|
|
|
|
|
|
# } |
|
313
|
|
|
|
|
|
|
# die "Not able to compare. type of x & y is $tx."; |
|
314
|
4
|
|
|
|
|
43
|
die "Not able to compare."; |
|
315
|
|
|
|
|
|
|
} |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
else { |
|
319
|
|
|
|
|
|
|
## undef first |
|
320
|
1
|
50
|
33
|
|
|
4
|
if ($tx eq "UNDEF" and $ty ne "UNDEF") { |
|
321
|
0
|
|
|
|
|
0
|
return -1; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
1
|
50
|
33
|
|
|
13
|
if ($tx ne "UNDEF" and $ty eq "UNDEF") { |
|
324
|
0
|
|
|
|
|
0
|
return 1; |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
################## |
|
327
|
1
|
50
|
33
|
|
|
6
|
if ($tx eq "NUMBER" and $ty eq "STRING") { |
|
328
|
0
|
|
|
|
|
0
|
return $x <=> $y; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
1
|
50
|
33
|
|
|
4
|
if ($tx eq "STRING" and $ty eq "NUMBER") { |
|
331
|
0
|
|
|
|
|
0
|
return $x cmp $y; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
####### |
|
334
|
|
|
|
|
|
|
# die "Since they are different type of variables, not able to compare. type of x is $tx, type of y is $ty"; |
|
335
|
1
|
|
|
|
|
3
|
my $stack = x_stack(1); |
|
336
|
1
|
|
|
|
|
2
|
unshift(@$stack, "Not able to compare. type of x is $tx, type of y is $ty."); |
|
337
|
1
|
|
|
|
|
9
|
die join("\n", @$stack); |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
################## |
|
343
|
|
|
|
|
|
|
# Subroutine : v_max |
|
344
|
|
|
|
|
|
|
# Purpose : returns the largest of the element given as input parameters, or undef if there are no parameters. |
|
345
|
|
|
|
|
|
|
# Input : array |
|
346
|
|
|
|
|
|
|
# Returns : returns the largest element |
|
347
|
|
|
|
|
|
|
sub v_max { |
|
348
|
50
|
|
|
50
|
0
|
365997
|
my $the_one = undef; |
|
349
|
50
|
|
|
|
|
141
|
my $cmp_func = \&v_cmp; |
|
350
|
50
|
|
|
|
|
90
|
my $idx = 0; |
|
351
|
50
|
|
|
|
|
101
|
foreach my $x (@_) { |
|
352
|
100
|
50
|
66
|
|
|
302
|
if ($idx == 0 and v_type_of($x) eq "CODE") { |
|
353
|
0
|
|
|
|
|
0
|
$cmp_func = $x; |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
else { |
|
356
|
100
|
100
|
|
|
|
189
|
if ($idx == 0) { |
|
357
|
49
|
|
|
|
|
101
|
$the_one = $x; |
|
358
|
|
|
|
|
|
|
} |
|
359
|
|
|
|
|
|
|
else { |
|
360
|
51
|
100
|
|
|
|
136
|
if ($cmp_func->($the_one, $x) <= 0) { |
|
361
|
33
|
|
|
|
|
54
|
$the_one = $x; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
} |
|
364
|
100
|
|
|
|
|
216
|
$idx = $idx + 1; |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
} |
|
367
|
50
|
|
|
|
|
145
|
return $the_one; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
################## |
|
371
|
|
|
|
|
|
|
# Subroutine : v_min |
|
372
|
|
|
|
|
|
|
# Purpose : returns the smallest of the numbers given as input parameters, or undef if there are no parameters. |
|
373
|
|
|
|
|
|
|
# Input : array |
|
374
|
|
|
|
|
|
|
# Returns : returns the smallest element |
|
375
|
|
|
|
|
|
|
sub v_min { |
|
376
|
50
|
|
|
50
|
0
|
89
|
my $the_one = undef; |
|
377
|
50
|
|
|
|
|
124
|
my $cmp_func = \&v_cmp; |
|
378
|
50
|
|
|
|
|
103
|
my $idx = 0; |
|
379
|
50
|
|
|
|
|
106
|
foreach my $x (@_) { |
|
380
|
100
|
50
|
66
|
|
|
285
|
if ($idx == 0 and v_type_of($x) eq "CODE") { |
|
381
|
0
|
|
|
|
|
0
|
$cmp_func = $x; |
|
382
|
|
|
|
|
|
|
} |
|
383
|
|
|
|
|
|
|
else { |
|
384
|
100
|
100
|
|
|
|
179
|
if ($idx == 0) { |
|
385
|
49
|
|
|
|
|
108
|
$the_one = $x; |
|
386
|
|
|
|
|
|
|
} |
|
387
|
|
|
|
|
|
|
else { |
|
388
|
51
|
100
|
|
|
|
103
|
if ($cmp_func->($the_one, $x) >= 0) { |
|
389
|
14
|
|
|
|
|
27
|
$the_one = $x; |
|
390
|
|
|
|
|
|
|
} |
|
391
|
|
|
|
|
|
|
} |
|
392
|
100
|
|
|
|
|
190
|
$idx = $idx + 1; |
|
393
|
|
|
|
|
|
|
} |
|
394
|
|
|
|
|
|
|
} |
|
395
|
50
|
|
|
|
|
155
|
return $the_one; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
######################################## |
|
399
|
|
|
|
|
|
|
######################################## string |
|
400
|
|
|
|
|
|
|
######################################## |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
################## |
|
403
|
|
|
|
|
|
|
# Subroutine : s_pad |
|
404
|
|
|
|
|
|
|
# Purpose : String padding. |
|
405
|
|
|
|
|
|
|
# Input : 1. text |
|
406
|
|
|
|
|
|
|
# 2. width - can be undef or -1 if you supply multiple texts, in which case the width will be determined from the longest text. |
|
407
|
|
|
|
|
|
|
# 3. which(optional) - is either "r" or "right" for padding on the right (the default if not specified), |
|
408
|
|
|
|
|
|
|
# "l" or "left" for padding on the right, or "c" or "center" or "centre" for left+right padding to center the text. |
|
409
|
|
|
|
|
|
|
# Note that "r" will mean "left justified", while "l" will mean "right justified". |
|
410
|
|
|
|
|
|
|
# 4. padchar(optional) - is whitespace if not specified. It should be string having the width of 1 column. |
|
411
|
|
|
|
|
|
|
# 5. is_trunc(optional) - is boolean. When set to 1, then text will be truncated when it is longer than $width. |
|
412
|
|
|
|
|
|
|
# Returns : Return $text padded with $padchar to $width columns. |
|
413
|
|
|
|
|
|
|
# Can accept multiple texts (\@texts); in which case will return a new arrayref of padded texts. |
|
414
|
|
|
|
|
|
|
sub s_pad { |
|
415
|
18
|
|
|
18
|
0
|
362011
|
my ($text0, $width, $which, $padchar, $is_trunc) = @_; |
|
416
|
18
|
100
|
|
|
|
51
|
if ($which) { |
|
417
|
9
|
|
|
|
|
22
|
$which = substr($which, 0, 1); |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
else { |
|
420
|
9
|
|
|
|
|
19
|
$which = "r"; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
18
|
|
100
|
|
|
78
|
$padchar //= " "; |
|
423
|
|
|
|
|
|
|
|
|
424
|
18
|
100
|
|
|
|
66
|
my $texts = ref $text0 eq 'ARRAY' ? [@$text0] : [$text0]; |
|
425
|
|
|
|
|
|
|
|
|
426
|
18
|
100
|
66
|
|
|
106
|
if (!defined($width) || $width < 0) { |
|
427
|
3
|
|
|
|
|
6
|
my $longest = 0; |
|
428
|
3
|
|
|
|
|
9
|
for (@$texts) { |
|
429
|
3
|
|
|
|
|
6
|
my $len = length($_); |
|
430
|
3
|
50
|
|
|
|
11
|
$longest = $len if $longest < $len; |
|
431
|
|
|
|
|
|
|
} |
|
432
|
3
|
|
|
|
|
7
|
$width = $longest; |
|
433
|
|
|
|
|
|
|
} |
|
434
|
|
|
|
|
|
|
|
|
435
|
18
|
|
|
|
|
70
|
for my $text (@$texts) { |
|
436
|
19
|
|
|
|
|
36
|
my $w = length($text); |
|
437
|
19
|
100
|
66
|
|
|
62
|
if ($is_trunc && $w > $width) { |
|
438
|
1
|
|
|
|
|
5
|
$text = substr($text, 0, $width, 1); |
|
439
|
1
|
|
|
|
|
4
|
$w = $width; |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
else { |
|
442
|
18
|
100
|
|
|
|
72
|
if ($which eq 'l') { |
|
|
|
100
|
|
|
|
|
|
|
443
|
30
|
|
|
30
|
|
55347
|
no warnings; # negative repeat count |
|
|
30
|
|
|
|
|
62
|
|
|
|
30
|
|
|
|
|
3482
|
|
|
444
|
1
|
|
|
|
|
6
|
$text = ($padchar x ($width - $w)) . $text; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
|
|
|
|
|
|
elsif ($which eq 'c') { |
|
447
|
3
|
|
|
|
|
11
|
my $n = int(($width - $w) / 2); |
|
448
|
3
|
|
|
|
|
15
|
$text = ($padchar x $n) . $text . ($padchar x ($width - $w - $n)); |
|
449
|
|
|
|
|
|
|
} |
|
450
|
|
|
|
|
|
|
else { |
|
451
|
30
|
|
|
30
|
|
188
|
no warnings; # negative repeat count |
|
|
30
|
|
|
|
|
57
|
|
|
|
30
|
|
|
|
|
27950
|
|
|
452
|
14
|
|
|
|
|
52
|
$text .= ($padchar x ($width - $w)); |
|
453
|
|
|
|
|
|
|
} |
|
454
|
|
|
|
|
|
|
} |
|
455
|
|
|
|
|
|
|
} # for $text |
|
456
|
|
|
|
|
|
|
|
|
457
|
18
|
100
|
|
|
|
122
|
return ref $text0 eq 'ARRAY' ? $texts : $texts->[0]; |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
################## |
|
461
|
|
|
|
|
|
|
# Subroutine : s_left |
|
462
|
|
|
|
|
|
|
# Purpose : Returns a string containing a specified number of characters from the left side of a string. |
|
463
|
|
|
|
|
|
|
# Input : 1. string |
|
464
|
|
|
|
|
|
|
# 2. length - a number indicating how many characters to return. |
|
465
|
|
|
|
|
|
|
# If 0, a zero-length string ("") is returned. |
|
466
|
|
|
|
|
|
|
# If greater than or equal to the number of characters in string, the entire string is returned. |
|
467
|
|
|
|
|
|
|
# Returns : string |
|
468
|
|
|
|
|
|
|
sub s_left { |
|
469
|
10
|
|
|
10
|
0
|
346232
|
my $str = shift; |
|
470
|
10
|
|
|
|
|
15
|
my $length = shift; |
|
471
|
|
|
|
|
|
|
### |
|
472
|
10
|
100
|
|
|
|
33
|
return "" if ($length <= 0); |
|
473
|
8
|
|
|
|
|
11
|
my $str_length = length($str); |
|
474
|
8
|
100
|
|
|
|
20
|
if ($length > $str_length) { |
|
475
|
1
|
|
|
|
|
3
|
return $str; |
|
476
|
|
|
|
|
|
|
} |
|
477
|
7
|
|
|
|
|
26
|
return substr($str, 0, $length); |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
################## |
|
481
|
|
|
|
|
|
|
# Subroutine : s_starts_with |
|
482
|
|
|
|
|
|
|
# Purpose : Check whether the string begins with the characters of a specified string, returning 1 or 0 as appropriate. |
|
483
|
|
|
|
|
|
|
# Input : 1. string |
|
484
|
|
|
|
|
|
|
# 2. string |
|
485
|
|
|
|
|
|
|
# Returns : |
|
486
|
|
|
|
|
|
|
sub s_starts_with { |
|
487
|
2
|
|
|
2
|
0
|
309609
|
my $str1 = shift; |
|
488
|
2
|
|
|
|
|
3
|
my $str2 = shift; |
|
489
|
2
|
|
|
|
|
4
|
my $len1 = length($str1); |
|
490
|
2
|
|
|
|
|
3
|
my $len2 = length($str2); |
|
491
|
2
|
50
|
|
|
|
5
|
if ($len1 < $len2) { |
|
492
|
0
|
|
|
|
|
0
|
return 0; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
2
|
|
|
|
|
4
|
my $cutted = s_left($str1, $len2); |
|
495
|
2
|
100
|
|
|
|
5
|
if ($cutted eq $str2) { |
|
496
|
1
|
|
|
|
|
6
|
return 1; |
|
497
|
|
|
|
|
|
|
} |
|
498
|
1
|
|
|
|
|
3
|
return 0; |
|
499
|
|
|
|
|
|
|
} |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
################## |
|
502
|
|
|
|
|
|
|
# Subroutine : s_right |
|
503
|
|
|
|
|
|
|
# Purpose : Returns a string containing a specified number of characters from the right side of a string. |
|
504
|
|
|
|
|
|
|
# Input : 1. string |
|
505
|
|
|
|
|
|
|
# 2. length - a number indicating how many characters to return. |
|
506
|
|
|
|
|
|
|
# If 0, a zero-length string ("") is returned. |
|
507
|
|
|
|
|
|
|
# If greater than or equal to the number of characters in string, the entire string is returned. |
|
508
|
|
|
|
|
|
|
# Returns : string |
|
509
|
|
|
|
|
|
|
sub s_right { |
|
510
|
10
|
|
|
10
|
0
|
391981
|
my $str = shift; |
|
511
|
10
|
|
|
|
|
21
|
my $length = shift; |
|
512
|
|
|
|
|
|
|
### |
|
513
|
10
|
100
|
|
|
|
57
|
return "" if ($length <= 0); |
|
514
|
8
|
|
|
|
|
15
|
my $str_length = length($str); |
|
515
|
8
|
100
|
|
|
|
29
|
if ($length > $str_length) { |
|
516
|
1
|
|
|
|
|
8
|
return $str; |
|
517
|
|
|
|
|
|
|
} |
|
518
|
7
|
|
|
|
|
52
|
return substr($str, $str_length - $length, $length); |
|
519
|
|
|
|
|
|
|
} |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
################## |
|
522
|
|
|
|
|
|
|
# Subroutine : s_ends_with |
|
523
|
|
|
|
|
|
|
# Purpose : Check whether the string ends with the characters of a specified string, returning 1 or 0 as appropriate. |
|
524
|
|
|
|
|
|
|
# Input : 1. string |
|
525
|
|
|
|
|
|
|
# 2. string |
|
526
|
|
|
|
|
|
|
# Returns : |
|
527
|
|
|
|
|
|
|
sub s_ends_with { |
|
528
|
2
|
|
|
2
|
0
|
4
|
my $str1 = shift; |
|
529
|
2
|
|
|
|
|
2
|
my $str2 = shift; |
|
530
|
2
|
|
|
|
|
3
|
my $len1 = length($str1); |
|
531
|
2
|
|
|
|
|
3
|
my $len2 = length($str2); |
|
532
|
2
|
50
|
|
|
|
6
|
if ($len1 < $len2) { |
|
533
|
0
|
|
|
|
|
0
|
return 0; |
|
534
|
|
|
|
|
|
|
} |
|
535
|
2
|
|
|
|
|
4
|
my $cutted = s_right($str1, $len2); |
|
536
|
2
|
100
|
|
|
|
5
|
if ($cutted eq $str2) { |
|
537
|
1
|
|
|
|
|
3
|
return 1; |
|
538
|
|
|
|
|
|
|
} |
|
539
|
1
|
|
|
|
|
4
|
return 0; |
|
540
|
|
|
|
|
|
|
} |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
################## |
|
543
|
|
|
|
|
|
|
# Subroutine : s_trim |
|
544
|
|
|
|
|
|
|
# Purpose : A new string representing str stripped of whitespace from both its beginning and end. |
|
545
|
|
|
|
|
|
|
# Whitespace is defined as /\s/. |
|
546
|
|
|
|
|
|
|
# Input : 1. string |
|
547
|
|
|
|
|
|
|
# Returns : string |
|
548
|
|
|
|
|
|
|
sub s_trim { |
|
549
|
6
|
|
|
6
|
0
|
241203
|
my $str = shift; |
|
550
|
|
|
|
|
|
|
### |
|
551
|
6
|
|
|
|
|
51
|
$str =~ s/^\s+|\s+$//g; |
|
552
|
6
|
|
|
|
|
43
|
return $str; |
|
553
|
|
|
|
|
|
|
} |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
################## |
|
556
|
|
|
|
|
|
|
# Subroutine : s_ellipsis |
|
557
|
|
|
|
|
|
|
# Purpose : truncate the string to the specified length and add ellipsis "..." at the end of the string to indicate that the string has been truncated. |
|
558
|
|
|
|
|
|
|
# Input : 1. string |
|
559
|
|
|
|
|
|
|
# 2. width |
|
560
|
|
|
|
|
|
|
# 3. align |
|
561
|
|
|
|
|
|
|
# 4. padchar |
|
562
|
|
|
|
|
|
|
# Returns : string |
|
563
|
|
|
|
|
|
|
sub s_ellipsis { |
|
564
|
5
|
|
|
5
|
0
|
309305
|
my ($str, $width, $align, $padchar) = @_; |
|
565
|
5
|
100
|
|
|
|
19
|
$align = defined($align) ? $align : "l"; |
|
566
|
5
|
|
|
|
|
16
|
$align = lc(substr($align, 0, 1)); |
|
567
|
|
|
|
|
|
|
## |
|
568
|
5
|
100
|
|
|
|
15
|
$padchar = defined($padchar) ? $padchar : " "; |
|
569
|
|
|
|
|
|
|
## |
|
570
|
5
|
|
|
|
|
15
|
$str =~ s/\r?\n//g; |
|
571
|
|
|
|
|
|
|
## |
|
572
|
5
|
|
|
|
|
9
|
my $length = length($str); |
|
573
|
|
|
|
|
|
|
# |
|
574
|
5
|
100
|
|
|
|
13
|
if ($length <= $width) { |
|
575
|
2
|
50
|
|
|
|
13
|
$str = s_pad($str, $width, ($align eq "r" ? "l" : "r"), $padchar); |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
else { |
|
578
|
3
|
100
|
|
|
|
15
|
if ($align eq "r") { |
|
|
|
100
|
|
|
|
|
|
|
579
|
1
|
|
|
|
|
6
|
$str = "..." . s_right($str, $width - 3); |
|
580
|
|
|
|
|
|
|
} |
|
581
|
|
|
|
|
|
|
elsif ($align eq "c") { |
|
582
|
1
|
|
|
|
|
3
|
my $m_odd = $width % 2; |
|
583
|
1
|
|
|
|
|
30
|
my $m_mid_len = floor($width / 2); |
|
584
|
1
|
|
|
|
|
8
|
my $head_str = s_left($str, $m_mid_len - 1); |
|
585
|
1
|
50
|
|
|
|
7
|
my $tail_str = s_right($str, $m_mid_len - ($m_odd ? 1 : 2)); |
|
586
|
1
|
|
|
|
|
4
|
$str = $head_str . "..." . $tail_str; |
|
587
|
|
|
|
|
|
|
} |
|
588
|
|
|
|
|
|
|
else { |
|
589
|
1
|
|
|
|
|
7
|
$str = s_left($str, $width - 3) . "..."; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
|
|
593
|
5
|
|
|
|
|
30
|
return $str; |
|
594
|
|
|
|
|
|
|
} |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
################## |
|
597
|
|
|
|
|
|
|
# Subroutine : s_split |
|
598
|
|
|
|
|
|
|
# Purpose : takes a pattern and divides this string into an ordered list of substrings by searching for the pattern, puts these substrings into an array, and returns the array. |
|
599
|
|
|
|
|
|
|
# Input : 1. string |
|
600
|
|
|
|
|
|
|
# 2. separator |
|
601
|
|
|
|
|
|
|
# Returns : array |
|
602
|
|
|
|
|
|
|
sub s_split { |
|
603
|
1
|
|
|
1
|
0
|
323579
|
my ($str, $sep) = @_; |
|
604
|
1
|
|
|
|
|
11
|
my @arr = split($sep, $str); |
|
605
|
1
|
|
|
|
|
5
|
return \@arr; |
|
606
|
|
|
|
|
|
|
} |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
################## |
|
609
|
|
|
|
|
|
|
# Subroutine : s_match_glob |
|
610
|
|
|
|
|
|
|
# Purpose : match globbing patterns against text |
|
611
|
|
|
|
|
|
|
# Input : 1. pattern |
|
612
|
|
|
|
|
|
|
# 2. string to match |
|
613
|
|
|
|
|
|
|
# Returns : Returns the list of things which match the glob from the source list. |
|
614
|
|
|
|
|
|
|
# Example : |
|
615
|
|
|
|
|
|
|
# ``` |
|
616
|
|
|
|
|
|
|
# print "matched\n" if s_match_glob( "foo.*", "foo.bar" ); |
|
617
|
|
|
|
|
|
|
# > matched |
|
618
|
|
|
|
|
|
|
# ``` |
|
619
|
|
|
|
|
|
|
# Reference : https://metacpan.org/pod/Text::Glob |
|
620
|
|
|
|
|
|
|
sub s_match_glob { |
|
621
|
30
|
|
|
30
|
|
254
|
use constant debug => 0; |
|
|
30
|
|
|
|
|
54
|
|
|
|
30
|
|
|
|
|
2595
|
|
|
622
|
30
|
|
|
30
|
|
182
|
use constant strict_leading_dot => 0; |
|
|
30
|
|
|
|
|
69
|
|
|
|
30
|
|
|
|
|
1835
|
|
|
623
|
30
|
|
|
30
|
|
170
|
use constant strict_wildcard_slash => 0; |
|
|
30
|
|
|
|
|
60
|
|
|
|
30
|
|
|
|
|
97627
|
|
|
624
|
|
|
|
|
|
|
### |
|
625
|
|
|
|
|
|
|
sub glob_to_regex_string { |
|
626
|
2
|
|
|
2
|
0
|
4
|
my $glob = shift; |
|
627
|
2
|
|
|
|
|
4
|
my $seperator = quotemeta("/"); |
|
628
|
2
|
|
|
|
|
5
|
my ($regex, $in_curlies, $escaping); |
|
629
|
2
|
|
|
|
|
4
|
local $_; |
|
630
|
2
|
|
|
|
|
3
|
my $first_byte = 1; |
|
631
|
2
|
|
|
|
|
19
|
for ($glob =~ m/(.)/gs) { |
|
632
|
11
|
100
|
|
|
|
28
|
if ($first_byte) { |
|
633
|
2
|
|
|
|
|
4
|
if (strict_leading_dot) { |
|
634
|
|
|
|
|
|
|
$regex .= '(?=[^\.])' unless $_ eq '.'; |
|
635
|
|
|
|
|
|
|
} |
|
636
|
2
|
|
|
|
|
4
|
$first_byte = 0; |
|
637
|
|
|
|
|
|
|
} |
|
638
|
11
|
50
|
|
|
|
28
|
if ($_ eq '/') { |
|
639
|
0
|
|
|
|
|
0
|
$first_byte = 1; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
11
|
100
|
66
|
|
|
172
|
if ( $_ eq '.' |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
642
|
|
|
|
|
|
|
|| $_ eq '(' |
|
643
|
|
|
|
|
|
|
|| $_ eq ')' |
|
644
|
|
|
|
|
|
|
|| $_ eq '|' |
|
645
|
|
|
|
|
|
|
|| $_ eq '+' |
|
646
|
|
|
|
|
|
|
|| $_ eq '^' |
|
647
|
|
|
|
|
|
|
|| $_ eq '$' |
|
648
|
|
|
|
|
|
|
|| $_ eq '@' |
|
649
|
|
|
|
|
|
|
|| $_ eq '%') { |
|
650
|
2
|
|
|
|
|
5
|
$regex .= "\\$_"; |
|
651
|
|
|
|
|
|
|
} |
|
652
|
|
|
|
|
|
|
elsif ($_ eq '*') { |
|
653
|
2
|
50
|
|
|
|
6
|
$regex .= |
|
654
|
|
|
|
|
|
|
$escaping ? "\\*" |
|
655
|
|
|
|
|
|
|
: strict_wildcard_slash ? "(?:(?!$seperator).)*" |
|
656
|
|
|
|
|
|
|
: ".*"; |
|
657
|
|
|
|
|
|
|
} |
|
658
|
|
|
|
|
|
|
elsif ($_ eq '?') { |
|
659
|
0
|
0
|
|
|
|
0
|
$regex .= |
|
660
|
|
|
|
|
|
|
$escaping ? "\\?" |
|
661
|
|
|
|
|
|
|
: strict_wildcard_slash ? "(?!$seperator)." |
|
662
|
|
|
|
|
|
|
: "."; |
|
663
|
|
|
|
|
|
|
} |
|
664
|
|
|
|
|
|
|
elsif ($_ eq '{') { |
|
665
|
0
|
0
|
|
|
|
0
|
$regex .= $escaping ? "\\{" : "("; |
|
666
|
0
|
0
|
|
|
|
0
|
++$in_curlies unless $escaping; |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
elsif ($_ eq '}' && $in_curlies) { |
|
669
|
0
|
0
|
|
|
|
0
|
$regex .= $escaping ? "}" : ")"; |
|
670
|
0
|
0
|
|
|
|
0
|
--$in_curlies unless $escaping; |
|
671
|
|
|
|
|
|
|
} |
|
672
|
|
|
|
|
|
|
elsif ($_ eq ',' && $in_curlies) { |
|
673
|
0
|
0
|
|
|
|
0
|
$regex .= $escaping ? "," : "|"; |
|
674
|
|
|
|
|
|
|
} |
|
675
|
|
|
|
|
|
|
elsif ($_ eq "\\") { |
|
676
|
0
|
0
|
|
|
|
0
|
if ($escaping) { |
|
677
|
0
|
|
|
|
|
0
|
$regex .= "\\\\"; |
|
678
|
0
|
|
|
|
|
0
|
$escaping = 0; |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
else { |
|
681
|
0
|
|
|
|
|
0
|
$escaping = 1; |
|
682
|
|
|
|
|
|
|
} |
|
683
|
0
|
|
|
|
|
0
|
next; |
|
684
|
|
|
|
|
|
|
} |
|
685
|
|
|
|
|
|
|
else { |
|
686
|
7
|
|
|
|
|
32
|
$regex .= $_; |
|
687
|
7
|
|
|
|
|
12
|
$escaping = 0; |
|
688
|
|
|
|
|
|
|
} |
|
689
|
11
|
|
|
|
|
22
|
$escaping = 0; |
|
690
|
|
|
|
|
|
|
} |
|
691
|
2
|
|
|
|
|
5
|
x_debug "# $glob $regex" if debug; |
|
692
|
|
|
|
|
|
|
|
|
693
|
2
|
|
|
|
|
8
|
return $regex; |
|
694
|
|
|
|
|
|
|
} |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
sub glob_to_regex { |
|
697
|
2
|
|
|
2
|
0
|
4
|
my $glob = shift; |
|
698
|
2
|
|
|
|
|
7
|
my $regex = glob_to_regex_string($glob); |
|
699
|
2
|
|
|
|
|
47
|
return qr/^$regex$/; |
|
700
|
|
|
|
|
|
|
} |
|
701
|
|
|
|
|
|
|
### |
|
702
|
2
|
|
|
2
|
0
|
242652
|
my ($glob, $str) = @_; |
|
703
|
2
|
|
|
|
|
9
|
my $regex = glob_to_regex($glob); |
|
704
|
2
|
|
|
|
|
16
|
my $matched = $str =~ $regex; |
|
705
|
2
|
|
|
|
|
5
|
x_debug "$str =~ $regex = $matched " if debug; |
|
706
|
2
|
100
|
|
|
|
19
|
return $matched ? 1 : 0; |
|
707
|
|
|
|
|
|
|
} |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
######################################## |
|
710
|
|
|
|
|
|
|
######################################## array |
|
711
|
|
|
|
|
|
|
######################################## |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
################## |
|
714
|
|
|
|
|
|
|
# Subroutine : a_join |
|
715
|
|
|
|
|
|
|
# Purpose : creates and returns a new string by concatenating all of the elements in this array, separated by commas or a specified separator string. |
|
716
|
|
|
|
|
|
|
# If the array has only one item, then that item will be returned without using the separator. |
|
717
|
|
|
|
|
|
|
# Input : array, separator |
|
718
|
|
|
|
|
|
|
# Returns : joined string |
|
719
|
|
|
|
|
|
|
sub a_join { |
|
720
|
5
|
|
|
5
|
0
|
293760
|
my ($arr, $separator) = @_; |
|
721
|
5
|
50
|
|
|
|
16
|
$separator = defined($separator) ? $separator : ","; |
|
722
|
5
|
|
|
|
|
36
|
return join($separator, @$arr); |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
################## |
|
726
|
|
|
|
|
|
|
# Subroutine : a_concat |
|
727
|
|
|
|
|
|
|
# Purpose : merge two or more arrays. This method does not change the existing arrays, but instead returns a new array. |
|
728
|
|
|
|
|
|
|
# Input : ...array_list |
|
729
|
|
|
|
|
|
|
# Returns : A new array |
|
730
|
|
|
|
|
|
|
sub a_concat { |
|
731
|
3
|
|
|
3
|
0
|
322637
|
my $result = []; |
|
732
|
3
|
|
|
|
|
11
|
foreach my $x (@_) { |
|
733
|
6
|
|
|
|
|
12
|
a_push($result, @{$x}); |
|
|
6
|
|
|
|
|
16
|
|
|
734
|
|
|
|
|
|
|
} |
|
735
|
3
|
|
|
|
|
29
|
return $result; |
|
736
|
|
|
|
|
|
|
} |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
################## |
|
739
|
|
|
|
|
|
|
# Subroutine : a_push |
|
740
|
|
|
|
|
|
|
# Purpose : adds the specified elements to the end of an array and returns the new length of the array. |
|
741
|
|
|
|
|
|
|
# |
|
742
|
|
|
|
|
|
|
# Input : ...elements |
|
743
|
|
|
|
|
|
|
# Returns : new length of the array |
|
744
|
|
|
|
|
|
|
sub a_push { |
|
745
|
29
|
|
|
29
|
0
|
307642
|
my $target = shift; |
|
746
|
29
|
|
|
|
|
68
|
push(@$target, @_); |
|
747
|
29
|
|
|
|
|
62
|
return scalar @$target; |
|
748
|
|
|
|
|
|
|
} |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
################## |
|
751
|
|
|
|
|
|
|
# Subroutine : a_pop |
|
752
|
|
|
|
|
|
|
# Purpose : removes the last element from an array and returns that element. This method changes the length of the array. |
|
753
|
|
|
|
|
|
|
# |
|
754
|
|
|
|
|
|
|
# Input : array |
|
755
|
|
|
|
|
|
|
# Returns : The removed element from the array; undef if the array is empty. |
|
756
|
|
|
|
|
|
|
sub a_pop { |
|
757
|
3
|
|
|
3
|
0
|
7
|
my $arr = shift; |
|
758
|
3
|
|
|
|
|
5
|
my $item = pop(@$arr); |
|
759
|
3
|
|
|
|
|
14
|
return $item; |
|
760
|
|
|
|
|
|
|
} |
|
761
|
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
################## |
|
763
|
|
|
|
|
|
|
# Subroutine : a_splice |
|
764
|
|
|
|
|
|
|
# Purpose : changes the contents of an array by removing or replacing existing elements and/or adding new elements in place. |
|
765
|
|
|
|
|
|
|
# |
|
766
|
|
|
|
|
|
|
# Input : array |
|
767
|
|
|
|
|
|
|
# a_splice(array, start) |
|
768
|
|
|
|
|
|
|
# a_splice(array, start, deleteCount) |
|
769
|
|
|
|
|
|
|
# a_splice(array, start, deleteCount, item1) |
|
770
|
|
|
|
|
|
|
# a_splice(array, start, deleteCount, item1, item2) |
|
771
|
|
|
|
|
|
|
# a_splice(array, start, deleteCount, item1, item2, /* …, */ itemN) |
|
772
|
|
|
|
|
|
|
# Returns : An array containing the deleted elements. |
|
773
|
|
|
|
|
|
|
sub a_splice { |
|
774
|
5
|
|
|
5
|
0
|
343210
|
my $arr = shift; |
|
775
|
5
|
|
|
|
|
9
|
my $start = shift; |
|
776
|
|
|
|
|
|
|
#### |
|
777
|
5
|
|
|
|
|
9
|
my $deleted = []; |
|
778
|
|
|
|
|
|
|
#### |
|
779
|
5
|
|
|
|
|
8
|
my $arr_size = scalar @$arr; |
|
780
|
5
|
|
|
|
|
8
|
my $optional_args_size = scalar @_; |
|
781
|
5
|
100
|
|
|
|
14
|
my $deleteCount = ($optional_args_size == 0 ? ($arr_size - $start) : shift); |
|
782
|
5
|
|
|
|
|
16
|
my $count = v_max(v_min($deleteCount, $arr_size - $start), 0); |
|
783
|
|
|
|
|
|
|
|
|
784
|
5
|
|
|
|
|
13
|
for my $i (1 .. $count) { |
|
785
|
8
|
|
|
|
|
16
|
my $the_one_item = splice(@$arr, $start, 1); |
|
786
|
8
|
|
|
|
|
16
|
a_push($deleted, $the_one_item); |
|
787
|
|
|
|
|
|
|
} |
|
788
|
5
|
|
|
|
|
13
|
splice(@$arr, $start, 0, @_); |
|
789
|
5
|
|
|
|
|
27
|
return $deleted; |
|
790
|
|
|
|
|
|
|
} |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
################## |
|
793
|
|
|
|
|
|
|
# Subroutine : a_shift |
|
794
|
|
|
|
|
|
|
# Purpose : removes the first element from an array and returns that removed element. This method changes the length of the array. |
|
795
|
|
|
|
|
|
|
# |
|
796
|
|
|
|
|
|
|
# Input : array |
|
797
|
|
|
|
|
|
|
# Returns : The removed element from the array; undef if the array is empty. |
|
798
|
|
|
|
|
|
|
sub a_shift { |
|
799
|
1
|
|
|
1
|
0
|
1
|
my $arr = shift; |
|
800
|
1
|
|
|
|
|
4
|
return shift(@$arr); |
|
801
|
|
|
|
|
|
|
} |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
################## |
|
804
|
|
|
|
|
|
|
# Subroutine : a_unshift |
|
805
|
|
|
|
|
|
|
# Purpose : adds the specified elements to the beginning of an array and returns the new length of the array. |
|
806
|
|
|
|
|
|
|
# |
|
807
|
|
|
|
|
|
|
# Input : element1, …, elementN |
|
808
|
|
|
|
|
|
|
# Returns : The new length property of the object upon which the method was called. |
|
809
|
|
|
|
|
|
|
sub a_unshift { |
|
810
|
3
|
|
|
3
|
0
|
331007
|
my $arr = shift; |
|
811
|
3
|
|
|
|
|
16
|
return unshift(@$arr, @_); |
|
812
|
|
|
|
|
|
|
} |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
################# |
|
815
|
|
|
|
|
|
|
# Subroutine : a_filter |
|
816
|
|
|
|
|
|
|
# Purpose : creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function. |
|
817
|
|
|
|
|
|
|
# Input : array, callback |
|
818
|
|
|
|
|
|
|
# Returns : A shallow copy of the given array containing just the elements that pass the test. If no elements pass the test, an empty array is returned. |
|
819
|
|
|
|
|
|
|
sub a_filter { |
|
820
|
2
|
|
|
2
|
0
|
310216
|
my ($arr, $callbackFn) = @_; |
|
821
|
2
|
|
|
|
|
5
|
my $result = []; |
|
822
|
2
|
|
|
|
|
40
|
my $count = scalar @$arr; |
|
823
|
2
|
50
|
|
|
|
11
|
if ($count > 0) { |
|
824
|
2
|
|
|
|
|
7
|
for my $i (0 .. ($count - 1)) { |
|
825
|
8
|
100
|
|
|
|
38
|
if ($callbackFn->($arr->[$i], $i, $arr)) { |
|
826
|
2
|
|
|
|
|
19
|
a_push($result, $arr->[$i]); |
|
827
|
|
|
|
|
|
|
} |
|
828
|
|
|
|
|
|
|
} |
|
829
|
|
|
|
|
|
|
} |
|
830
|
2
|
|
|
|
|
23
|
return $result; |
|
831
|
|
|
|
|
|
|
} |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
################## |
|
834
|
|
|
|
|
|
|
# Subroutine : a_find_index |
|
835
|
|
|
|
|
|
|
# Purpose : returns the index of the first element in an array that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned. |
|
836
|
|
|
|
|
|
|
# Input : array, callback, |
|
837
|
|
|
|
|
|
|
# Returns : The index of the first element in the array that passes the test. Otherwise, -1. |
|
838
|
|
|
|
|
|
|
sub a_find_index { |
|
839
|
23
|
|
|
23
|
0
|
293577
|
my ($arr, $callbackFn, $fromIndex) = @_; |
|
840
|
|
|
|
|
|
|
my $callbackFnA = v_type_of($callbackFn) eq "CODE" ? $callbackFn : sub { |
|
841
|
0
|
|
|
0
|
|
0
|
my ($itm, $idx) = @_; |
|
842
|
0
|
|
|
|
|
0
|
return v_cmp($itm, $callbackFn) == 0; |
|
843
|
23
|
50
|
|
|
|
58
|
}; |
|
844
|
|
|
|
|
|
|
|
|
845
|
23
|
|
|
|
|
61
|
my $idx = -1; |
|
846
|
23
|
|
|
|
|
42
|
my $count = scalar @$arr; |
|
847
|
23
|
50
|
|
|
|
71
|
if ($count > 0) { |
|
848
|
23
|
100
|
|
|
|
81
|
my $sidx = v_max(v_min((defined($fromIndex) ? $fromIndex : 0), $count - 1), 0); |
|
849
|
23
|
|
|
|
|
46
|
my $eidx = $count - 1; |
|
850
|
|
|
|
|
|
|
## |
|
851
|
23
|
|
|
|
|
32
|
my $i = $sidx; |
|
852
|
23
|
|
|
|
|
63
|
while ($i <= $eidx) { |
|
853
|
70
|
100
|
|
|
|
149
|
if ($callbackFnA->($arr->[$i], $i, $arr)) { |
|
854
|
20
|
|
|
|
|
44
|
$idx = $i; |
|
855
|
20
|
|
|
|
|
40
|
last; |
|
856
|
|
|
|
|
|
|
} |
|
857
|
|
|
|
|
|
|
##### |
|
858
|
50
|
|
|
|
|
143
|
$i++; |
|
859
|
|
|
|
|
|
|
} |
|
860
|
|
|
|
|
|
|
} |
|
861
|
23
|
|
|
|
|
60
|
return $idx; |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
################## |
|
865
|
|
|
|
|
|
|
# Subroutine : a_find_last_index |
|
866
|
|
|
|
|
|
|
# Purpose : iterates the array in reverse order and returns the index of the first element that satisfies the provided testing function. |
|
867
|
|
|
|
|
|
|
# If no elements satisfy the testing function, -1 is returned. |
|
868
|
|
|
|
|
|
|
# Input : array, callback, |
|
869
|
|
|
|
|
|
|
# Returns : The index of the last (highest-index) element in the array that passes the test. Otherwise -1 if no matching element is found. |
|
870
|
|
|
|
|
|
|
sub a_find_last_index { |
|
871
|
7
|
|
|
7
|
0
|
17
|
my ($arr, $callbackFn, $toIndex) = @_; |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
my $callbackFnA = v_type_of($callbackFn) eq "CODE" ? $callbackFn : sub { |
|
874
|
0
|
|
|
0
|
|
0
|
my ($itm, $idx) = @_; |
|
875
|
0
|
|
|
|
|
0
|
return v_cmp($itm, $callbackFn) == 0; |
|
876
|
7
|
50
|
|
|
|
19
|
}; |
|
877
|
7
|
|
|
|
|
14
|
my $idx = -1; |
|
878
|
7
|
|
|
|
|
13
|
my $count = scalar @$arr; |
|
879
|
7
|
50
|
|
|
|
21
|
if ($count > 0) { |
|
880
|
7
|
100
|
|
|
|
26
|
my $sidx = v_min(v_max((defined($toIndex) ? $toIndex : $count - 1), 0), $count - 1); |
|
881
|
7
|
|
|
|
|
12
|
my $eidx = 0; |
|
882
|
|
|
|
|
|
|
## |
|
883
|
7
|
|
|
|
|
10
|
my $i = $sidx; |
|
884
|
7
|
|
|
|
|
17
|
while ($i >= $eidx) { |
|
885
|
21
|
100
|
|
|
|
93
|
if ($callbackFnA->($arr->[$i], $i, $arr)) { |
|
886
|
4
|
|
|
|
|
14
|
$idx = $i; |
|
887
|
4
|
|
|
|
|
10
|
last; |
|
888
|
|
|
|
|
|
|
} |
|
889
|
|
|
|
|
|
|
##### |
|
890
|
17
|
|
|
|
|
81
|
$i--; |
|
891
|
|
|
|
|
|
|
} |
|
892
|
|
|
|
|
|
|
} |
|
893
|
7
|
|
|
|
|
20
|
return $idx; |
|
894
|
|
|
|
|
|
|
} |
|
895
|
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
################## |
|
897
|
|
|
|
|
|
|
# Subroutine : a_find |
|
898
|
|
|
|
|
|
|
# Purpose : returns the first element in the provided array that satisfies the provided testing function. |
|
899
|
|
|
|
|
|
|
# If no values satisfy the testing function, undef is returned. |
|
900
|
|
|
|
|
|
|
# Input : array, callback, |
|
901
|
|
|
|
|
|
|
# Returns : The first element in the array that satisfies the provided testing function. Otherwise, undef is returned. |
|
902
|
|
|
|
|
|
|
sub a_find { |
|
903
|
2
|
|
|
2
|
0
|
270398
|
my ($arr, $callbackFn, $fromIndex) = @_; |
|
904
|
|
|
|
|
|
|
my $callbackFnA = v_type_of($callbackFn) eq "CODE" ? $callbackFn : sub { |
|
905
|
0
|
|
|
0
|
|
0
|
my ($itm, $idx) = @_; |
|
906
|
0
|
|
|
|
|
0
|
return v_cmp($itm, $callbackFn) == 0; |
|
907
|
2
|
50
|
|
|
|
8
|
}; |
|
908
|
2
|
|
|
|
|
9
|
my $idx = a_find_index($arr, $callbackFnA, $fromIndex); |
|
909
|
2
|
100
|
|
|
|
7
|
if ($idx != -1) { |
|
910
|
1
|
|
|
|
|
9
|
return $arr->[$idx]; |
|
911
|
|
|
|
|
|
|
} |
|
912
|
1
|
|
|
|
|
5
|
return undef; |
|
913
|
|
|
|
|
|
|
} |
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
################## |
|
916
|
|
|
|
|
|
|
# Subroutine : a_find_last |
|
917
|
|
|
|
|
|
|
# Purpose : iterates the array in reverse order and returns the value of the first element that satisfies the provided testing function. |
|
918
|
|
|
|
|
|
|
# If no elements satisfy the testing function, undef is returned. |
|
919
|
|
|
|
|
|
|
# Input : array, callback, |
|
920
|
|
|
|
|
|
|
# Returns : The last (highest-index) element in the array that satisfies the provided testing function; undef if no matching element is found. |
|
921
|
|
|
|
|
|
|
sub a_find_last { |
|
922
|
2
|
|
|
2
|
0
|
7
|
my ($arr, $callbackFn, $toIndex) = @_; |
|
923
|
|
|
|
|
|
|
my $callbackFnA = v_type_of($callbackFn) eq "CODE" ? $callbackFn : sub { |
|
924
|
0
|
|
|
0
|
|
0
|
my ($itm, $idx) = @_; |
|
925
|
0
|
|
|
|
|
0
|
return v_cmp($itm, $callbackFn) == 0; |
|
926
|
2
|
50
|
|
|
|
6
|
}; |
|
927
|
2
|
|
|
|
|
9
|
my $idx = a_find_last_index($arr, $callbackFnA, $toIndex); |
|
928
|
2
|
100
|
|
|
|
7
|
if ($idx != -1) { |
|
929
|
1
|
|
|
|
|
6
|
return $arr->[$idx]; |
|
930
|
|
|
|
|
|
|
} |
|
931
|
1
|
|
|
|
|
10
|
return undef; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
################## |
|
935
|
|
|
|
|
|
|
# Subroutine : a_index_of |
|
936
|
|
|
|
|
|
|
# Purpose : returns the first index at which a given element can be found in the array, or -1 if it is not present. |
|
937
|
|
|
|
|
|
|
# Input : array, searchElement, fromIndex(optional) |
|
938
|
|
|
|
|
|
|
# Returns : The first index of searchElement in the array; -1 if not found. |
|
939
|
|
|
|
|
|
|
sub a_index_of { |
|
940
|
19
|
|
|
19
|
0
|
234415
|
my ($arr, $searchElement, $fromIndex) = @_; |
|
941
|
|
|
|
|
|
|
my $idx = a_find_index( |
|
942
|
|
|
|
|
|
|
$arr, |
|
943
|
|
|
|
|
|
|
sub { |
|
944
|
58
|
|
|
58
|
|
107
|
my ($itm) = @_; |
|
945
|
58
|
|
|
|
|
127
|
return v_cmp($searchElement, $itm) == 0; |
|
946
|
|
|
|
|
|
|
}, |
|
947
|
19
|
|
|
|
|
112
|
$fromIndex |
|
948
|
|
|
|
|
|
|
); |
|
949
|
19
|
|
|
|
|
112
|
return $idx; |
|
950
|
|
|
|
|
|
|
} |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
################## |
|
953
|
|
|
|
|
|
|
# Subroutine : a_last_index_of |
|
954
|
|
|
|
|
|
|
# Purpose : returns the first index at which a given element can be found in the array, or -1 if it is not present. |
|
955
|
|
|
|
|
|
|
# Input : array, searchElement, fromIndex(optional) |
|
956
|
|
|
|
|
|
|
# Returns : The first index of searchElement in the array; -1 if not found. |
|
957
|
|
|
|
|
|
|
sub a_last_index_of { |
|
958
|
3
|
|
|
3
|
0
|
6
|
my ($arr, $searchElement, $toIndex) = @_; |
|
959
|
|
|
|
|
|
|
my $idx = a_find_last_index( |
|
960
|
|
|
|
|
|
|
$arr, |
|
961
|
|
|
|
|
|
|
sub { |
|
962
|
9
|
|
|
9
|
|
11
|
my ($itm) = @_; |
|
963
|
9
|
|
|
|
|
10
|
return v_cmp($searchElement, $itm) == 0; |
|
964
|
|
|
|
|
|
|
}, |
|
965
|
3
|
|
|
|
|
14
|
$toIndex |
|
966
|
|
|
|
|
|
|
); |
|
967
|
3
|
|
|
|
|
19
|
return $idx; |
|
968
|
|
|
|
|
|
|
} |
|
969
|
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
################## |
|
971
|
|
|
|
|
|
|
# Subroutine : a_every |
|
972
|
|
|
|
|
|
|
# Purpose : tests whether all elements in the array pass the test implemented by the provided function. |
|
973
|
|
|
|
|
|
|
# It returns 1 or 0. |
|
974
|
|
|
|
|
|
|
# It doesn't modify the array. |
|
975
|
|
|
|
|
|
|
# Input : array, callback(element, index, the_array) |
|
976
|
|
|
|
|
|
|
# Returns : 1 unless callbackFn returns a falsy value for an array element, in which case 0 is immediately returned. |
|
977
|
|
|
|
|
|
|
sub a_every { |
|
978
|
2
|
|
|
2
|
0
|
287107
|
my ($arr, $callbackFn) = @_; |
|
979
|
|
|
|
|
|
|
|
|
980
|
2
|
|
|
|
|
5
|
my $count = scalar @$arr; |
|
981
|
2
|
50
|
|
|
|
9
|
if ($count > 0) { |
|
982
|
2
|
|
|
|
|
27
|
my $sidx = 0; |
|
983
|
2
|
|
|
|
|
5
|
my $eidx = $count - 1; |
|
984
|
|
|
|
|
|
|
## |
|
985
|
2
|
|
|
|
|
5
|
my $i = $sidx; |
|
986
|
2
|
|
|
|
|
6
|
while ($i <= $eidx) { |
|
987
|
7
|
100
|
|
|
|
21
|
if (!$callbackFn->($arr->[$i], $i, $arr)) { |
|
988
|
1
|
|
|
|
|
13
|
return 0; |
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
##### |
|
991
|
6
|
|
|
|
|
40
|
$i++; |
|
992
|
|
|
|
|
|
|
} |
|
993
|
|
|
|
|
|
|
} |
|
994
|
1
|
|
|
|
|
7
|
return 1; |
|
995
|
|
|
|
|
|
|
} |
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
################## |
|
998
|
|
|
|
|
|
|
# Subroutine : a_some |
|
999
|
|
|
|
|
|
|
# Purpose : tests whether at least one element in the array passes the test implemented by the provided function. |
|
1000
|
|
|
|
|
|
|
# It returns 1 if, in the array, it finds an element for which the provided function returns 1; |
|
1001
|
|
|
|
|
|
|
# otherwise it returns 0. |
|
1002
|
|
|
|
|
|
|
# It doesn't modify the array. |
|
1003
|
|
|
|
|
|
|
# Input : array, callback(element, index, the_array) |
|
1004
|
|
|
|
|
|
|
# Returns : 0 unless callbackFn returns a truthy value for an array element, in which case 1 is immediately returned. |
|
1005
|
|
|
|
|
|
|
sub a_some { |
|
1006
|
2
|
|
|
2
|
0
|
8
|
my ($arr, $callbackFn) = @_; |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
2
|
|
|
|
|
5
|
my $count = scalar @$arr; |
|
1009
|
2
|
50
|
|
|
|
8
|
if ($count > 0) { |
|
1010
|
2
|
|
|
|
|
5
|
my $sidx = 0; |
|
1011
|
2
|
|
|
|
|
6
|
my $eidx = $count - 1; |
|
1012
|
|
|
|
|
|
|
## |
|
1013
|
2
|
|
|
|
|
3
|
my $i = $sidx; |
|
1014
|
2
|
|
|
|
|
8
|
while ($i <= $eidx) { |
|
1015
|
8
|
100
|
|
|
|
20
|
if ($callbackFn->($arr->[$i], $i, $arr)) { |
|
1016
|
1
|
|
|
|
|
11
|
return 1; |
|
1017
|
|
|
|
|
|
|
} |
|
1018
|
|
|
|
|
|
|
##### |
|
1019
|
7
|
|
|
|
|
79
|
$i++; |
|
1020
|
|
|
|
|
|
|
} |
|
1021
|
|
|
|
|
|
|
} |
|
1022
|
1
|
|
|
|
|
6
|
return 0; |
|
1023
|
|
|
|
|
|
|
} |
|
1024
|
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
################## |
|
1026
|
|
|
|
|
|
|
# Subroutine : a_map |
|
1027
|
|
|
|
|
|
|
# Purpose : creates a new array populated with the results of calling a provided function on every element in the calling array. |
|
1028
|
|
|
|
|
|
|
# Input : array, callback(element, index, the_array) |
|
1029
|
|
|
|
|
|
|
# Returns : A new array with each element being the result of the callback function. |
|
1030
|
|
|
|
|
|
|
sub a_map { |
|
1031
|
1
|
|
|
1
|
0
|
344133
|
my ($arr, $callbackFn) = @_; |
|
1032
|
1
|
50
|
|
|
|
6
|
if (!defined($arr)) { |
|
1033
|
0
|
|
|
|
|
0
|
return $arr; |
|
1034
|
|
|
|
|
|
|
} |
|
1035
|
1
|
|
|
|
|
3
|
my $result = []; |
|
1036
|
1
|
|
|
|
|
3
|
my $count = scalar @$arr; |
|
1037
|
1
|
50
|
|
|
|
5
|
if ($count > 0) { |
|
1038
|
1
|
|
|
|
|
5
|
for my $i (0 .. ($count - 1)) { |
|
1039
|
5
|
|
|
|
|
14
|
a_push($result, $callbackFn->($arr->[$i], $i, $arr)); |
|
1040
|
|
|
|
|
|
|
} |
|
1041
|
|
|
|
|
|
|
} |
|
1042
|
1
|
|
|
|
|
11
|
return $result; |
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
################## |
|
1046
|
|
|
|
|
|
|
# Subroutine : a_reduce |
|
1047
|
|
|
|
|
|
|
# Purpose : executes a user-supplied "reducer" callback function on each element of the array, |
|
1048
|
|
|
|
|
|
|
# in order, passing in the return value from the calculation on the preceding element. |
|
1049
|
|
|
|
|
|
|
# The final result of running the reducer across all elements of the array is a single value. |
|
1050
|
|
|
|
|
|
|
# Input : array, callback(accumulator, currentValue, currentIndex, theArray), initialValue |
|
1051
|
|
|
|
|
|
|
# Returns : The value that results from running the "reducer" callback function to completion over the entire array. |
|
1052
|
|
|
|
|
|
|
sub a_reduce { |
|
1053
|
3
|
|
|
3
|
0
|
734224
|
my ($arr, $callbackFn, $initialValue) = @_; |
|
1054
|
3
|
|
|
|
|
20
|
my $result = $initialValue; |
|
1055
|
3
|
|
|
|
|
9
|
my $count = scalar @$arr; |
|
1056
|
3
|
50
|
|
|
|
31
|
if ($count > 0) { |
|
1057
|
3
|
|
|
|
|
14
|
for my $i (0 .. ($count - 1)) { |
|
1058
|
16
|
|
|
|
|
108
|
$result = $callbackFn->($result, $arr->[$i], $i, $arr); |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
|
|
|
|
|
|
} |
|
1061
|
3
|
|
|
|
|
23
|
return $result; |
|
1062
|
|
|
|
|
|
|
} |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
################## |
|
1065
|
|
|
|
|
|
|
# Subroutine : a_slice |
|
1066
|
|
|
|
|
|
|
# Purpose : returns a shallow copy of a portion of an array into a new array |
|
1067
|
|
|
|
|
|
|
# The original array will not be modified. |
|
1068
|
|
|
|
|
|
|
# Input : 1. array |
|
1069
|
|
|
|
|
|
|
# 2. start index |
|
1070
|
|
|
|
|
|
|
# 3. end index (optional) |
|
1071
|
|
|
|
|
|
|
# Returns : A new array containing the extracted elements. |
|
1072
|
|
|
|
|
|
|
sub a_slice { |
|
1073
|
9
|
|
|
9
|
0
|
232055
|
my ($arr, $sidx, $eidx) = @_; |
|
1074
|
9
|
50
|
|
|
|
15
|
if (!defined($arr)) { |
|
1075
|
0
|
|
|
|
|
0
|
return $arr; |
|
1076
|
|
|
|
|
|
|
} |
|
1077
|
9
|
|
|
|
|
19
|
my $count = scalar @$arr; |
|
1078
|
9
|
|
|
|
|
11
|
my $result = []; |
|
1079
|
9
|
50
|
|
|
|
15
|
if ($count > 0) { |
|
1080
|
9
|
100
|
|
|
|
15
|
$eidx = defined($eidx) ? $eidx : $count; |
|
1081
|
9
|
|
|
|
|
17
|
for my $j ($sidx .. $eidx - 1) { |
|
1082
|
20
|
|
|
|
|
50
|
push(@$result, $arr->[$j]); |
|
1083
|
|
|
|
|
|
|
} |
|
1084
|
|
|
|
|
|
|
} |
|
1085
|
9
|
|
|
|
|
51
|
return $result; |
|
1086
|
|
|
|
|
|
|
} |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
################## |
|
1089
|
|
|
|
|
|
|
# Subroutine : a_left |
|
1090
|
|
|
|
|
|
|
# Purpose : Returns an array containing a specified number of elements from the left side of an array. |
|
1091
|
|
|
|
|
|
|
# Input : 1. array |
|
1092
|
|
|
|
|
|
|
# 2. length - a number indicating how many elements to return. |
|
1093
|
|
|
|
|
|
|
# Returns : array |
|
1094
|
|
|
|
|
|
|
sub a_left { |
|
1095
|
5
|
|
|
5
|
0
|
298888
|
my ($arr, $length) = @_; |
|
1096
|
|
|
|
|
|
|
### |
|
1097
|
5
|
100
|
|
|
|
19
|
return [] if ($length <= 0); |
|
1098
|
|
|
|
|
|
|
## |
|
1099
|
4
|
|
|
|
|
5
|
my $arr_length = scalar @$arr; |
|
1100
|
4
|
50
|
|
|
|
7
|
return [] if ($arr_length <= 0); |
|
1101
|
|
|
|
|
|
|
## |
|
1102
|
4
|
|
|
|
|
9
|
my $end_idx = v_min($length, $arr_length) - 1; |
|
1103
|
4
|
|
|
|
|
10
|
return a_slice($arr, 0, $end_idx + 1); |
|
1104
|
|
|
|
|
|
|
} |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
################## |
|
1107
|
|
|
|
|
|
|
# Subroutine : a_right |
|
1108
|
|
|
|
|
|
|
# Purpose : Returns an array containing a specified number of elements from the right side of an array. |
|
1109
|
|
|
|
|
|
|
# Input : 1. array |
|
1110
|
|
|
|
|
|
|
# 2. length - a number indicating how many elements to return. |
|
1111
|
|
|
|
|
|
|
# Returns : array |
|
1112
|
|
|
|
|
|
|
sub a_right { |
|
1113
|
5
|
|
|
5
|
0
|
10
|
my ($arr, $length) = @_; |
|
1114
|
|
|
|
|
|
|
### |
|
1115
|
5
|
100
|
|
|
|
14
|
return [] if ($length <= 0); |
|
1116
|
|
|
|
|
|
|
## |
|
1117
|
4
|
|
|
|
|
6
|
my $arr_length = scalar @$arr; |
|
1118
|
4
|
50
|
|
|
|
6
|
return [] if ($arr_length <= 0); |
|
1119
|
|
|
|
|
|
|
## |
|
1120
|
4
|
|
|
|
|
9
|
my $start_idx = v_max($arr_length - $length, 0); |
|
1121
|
4
|
|
|
|
|
6
|
return a_slice($arr, $start_idx); |
|
1122
|
|
|
|
|
|
|
} |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
################## |
|
1125
|
|
|
|
|
|
|
# Subroutine : a_sort |
|
1126
|
|
|
|
|
|
|
# Purpose : The a_sort method returns a sorted array by callbackFn |
|
1127
|
|
|
|
|
|
|
# The original array will not be modified. |
|
1128
|
|
|
|
|
|
|
# Input : array, callback(a, b), |
|
1129
|
|
|
|
|
|
|
# Returns : The new sorted array by the callbackFn |
|
1130
|
|
|
|
|
|
|
# Example : |
|
1131
|
|
|
|
|
|
|
# my $sorted_arr = a_sort(@array, sub { |
|
1132
|
|
|
|
|
|
|
# my ($a, $b) = @_; |
|
1133
|
|
|
|
|
|
|
# return $a cmp $b; |
|
1134
|
|
|
|
|
|
|
# }); |
|
1135
|
|
|
|
|
|
|
sub a_sort { |
|
1136
|
5
|
|
|
5
|
0
|
320786
|
my ($arr, $callbackFn) = @_; |
|
1137
|
5
|
100
|
|
|
|
39
|
$callbackFn = defined($callbackFn) ? $callbackFn : \&v_cmp; |
|
1138
|
5
|
|
|
|
|
28
|
my @sorted_arr = sort { $callbackFn->($a, $b) } @$arr; |
|
|
41
|
|
|
|
|
117
|
|
|
1139
|
5
|
|
|
|
|
54
|
return \@sorted_arr; |
|
1140
|
|
|
|
|
|
|
} |
|
1141
|
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
######################################## |
|
1143
|
|
|
|
|
|
|
######################################## hash |
|
1144
|
|
|
|
|
|
|
######################################## |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
################## |
|
1148
|
|
|
|
|
|
|
# Subroutine : h_keys |
|
1149
|
|
|
|
|
|
|
# Purpose : returns an array of a given hash's own enumerable names. |
|
1150
|
|
|
|
|
|
|
# Input : hash |
|
1151
|
|
|
|
|
|
|
# Returns : An array of strings representing the given hash's own enumerable keys. |
|
1152
|
|
|
|
|
|
|
sub h_keys { |
|
1153
|
1
|
|
|
1
|
0
|
10
|
my $hash = shift; |
|
1154
|
1
|
|
|
|
|
5
|
my @ks = keys %$hash; |
|
1155
|
1
|
|
|
|
|
5
|
return \@ks; |
|
1156
|
|
|
|
|
|
|
} |
|
1157
|
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
################## |
|
1159
|
|
|
|
|
|
|
# Subroutine : h_values |
|
1160
|
|
|
|
|
|
|
# Purpose : returns an array of a given hash's own enumerable values. |
|
1161
|
|
|
|
|
|
|
# Input : hash |
|
1162
|
|
|
|
|
|
|
# Returns : An array containing the given object's own enumerable values. |
|
1163
|
|
|
|
|
|
|
sub h_values { |
|
1164
|
1
|
|
|
1
|
0
|
3
|
my $hash = shift; |
|
1165
|
1
|
|
|
|
|
4
|
my @vs = values %$hash; |
|
1166
|
1
|
|
|
|
|
5
|
return \@vs; |
|
1167
|
|
|
|
|
|
|
} |
|
1168
|
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
################## |
|
1170
|
|
|
|
|
|
|
# Subroutine : h_find |
|
1171
|
|
|
|
|
|
|
# Purpose : returns the k-v tuple in the provided hash that satisfies the provided testing function. |
|
1172
|
|
|
|
|
|
|
# If no values satisfy the testing function, undef is returned. |
|
1173
|
|
|
|
|
|
|
# Input : $hash, callback, |
|
1174
|
|
|
|
|
|
|
# Returns : The he k-v tuple in the provided hash that satisfies the provided testing function. Otherwise, undef is returned. |
|
1175
|
|
|
|
|
|
|
sub h_find { |
|
1176
|
2
|
|
|
2
|
0
|
3920
|
my ($hash, $callbackFn) = @_; |
|
1177
|
|
|
|
|
|
|
### |
|
1178
|
|
|
|
|
|
|
my $callbackFnA = v_type_of($callbackFn) eq "CODE" ? $callbackFn : sub { |
|
1179
|
0
|
|
|
0
|
|
0
|
my ($val, $key) = @_; |
|
1180
|
0
|
|
|
|
|
0
|
return v_cmp($val, $callbackFn) == 0; |
|
1181
|
2
|
50
|
|
|
|
8
|
}; |
|
1182
|
|
|
|
|
|
|
########### |
|
1183
|
|
|
|
|
|
|
# my $ks = h_keys($hash); |
|
1184
|
|
|
|
|
|
|
# my $count = scalar @$ks; |
|
1185
|
|
|
|
|
|
|
# if ($count > 0) { |
|
1186
|
|
|
|
|
|
|
# my $eidx = $count - 1; |
|
1187
|
|
|
|
|
|
|
# my $i = 0; |
|
1188
|
|
|
|
|
|
|
# while ($i <= $eidx) { |
|
1189
|
|
|
|
|
|
|
# my $key = $ks->[$i]; |
|
1190
|
|
|
|
|
|
|
# my $val = $hash->{$key}; |
|
1191
|
|
|
|
|
|
|
# ## |
|
1192
|
|
|
|
|
|
|
# if ($callbackFnA->($val, $key, $hash)) { |
|
1193
|
|
|
|
|
|
|
# return ($key, $val); |
|
1194
|
|
|
|
|
|
|
# } |
|
1195
|
|
|
|
|
|
|
# ##### |
|
1196
|
|
|
|
|
|
|
# $i++; |
|
1197
|
|
|
|
|
|
|
# } |
|
1198
|
|
|
|
|
|
|
# } |
|
1199
|
|
|
|
|
|
|
########### |
|
1200
|
2
|
|
|
|
|
10
|
while (my ($key, $val) = each %$hash) { |
|
1201
|
6
|
100
|
|
|
|
65
|
if ($callbackFnA->($val, $key, $hash)) { |
|
1202
|
1
|
|
|
|
|
9
|
return ($key, $val); |
|
1203
|
|
|
|
|
|
|
} |
|
1204
|
|
|
|
|
|
|
} |
|
1205
|
1
|
|
|
|
|
12
|
return undef; |
|
1206
|
|
|
|
|
|
|
} |
|
1207
|
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
################## |
|
1209
|
|
|
|
|
|
|
# Subroutine : h_group_by |
|
1210
|
|
|
|
|
|
|
# Purpose : groups the elements of a given iterable according to the string values returned by a provided callback function. |
|
1211
|
|
|
|
|
|
|
# Input : array, callback(element, idx) |
|
1212
|
|
|
|
|
|
|
# the callback function should return a value that can get coerced into a key |
|
1213
|
|
|
|
|
|
|
# Returns : A hash object with keys for all groups, |
|
1214
|
|
|
|
|
|
|
# each assigned to an array containing the elements of the associated group. |
|
1215
|
|
|
|
|
|
|
sub h_group_by { |
|
1216
|
1
|
|
|
1
|
0
|
1745
|
my ($arr, $callbackFn) = @_; |
|
1217
|
|
|
|
|
|
|
my $group_hash = a_reduce( |
|
1218
|
|
|
|
|
|
|
$arr, |
|
1219
|
|
|
|
|
|
|
sub { |
|
1220
|
6
|
|
|
6
|
|
16
|
my ($hash, $element, $idx) = @_; |
|
1221
|
6
|
|
|
|
|
14
|
my $group_key = $callbackFn->($element, $idx); |
|
1222
|
6
|
50
|
|
|
|
33
|
if (v_type_of($group_key) ne "STRING") { |
|
1223
|
0
|
|
|
|
|
0
|
my $stack = x_stack(1); |
|
1224
|
0
|
|
|
|
|
0
|
unshift(@$stack, "the callback function of group_by should return a string"); |
|
1225
|
0
|
|
|
|
|
0
|
die join("\n", @$stack); |
|
1226
|
|
|
|
|
|
|
} |
|
1227
|
6
|
100
|
|
|
|
17
|
if (!defined($hash->{$group_key})) { |
|
1228
|
5
|
|
|
|
|
40
|
$hash->{$group_key} = []; |
|
1229
|
|
|
|
|
|
|
} |
|
1230
|
6
|
|
|
|
|
18
|
a_push($hash->{$group_key}, $element); |
|
1231
|
|
|
|
|
|
|
##### |
|
1232
|
6
|
|
|
|
|
11
|
return $hash; |
|
1233
|
|
|
|
|
|
|
}, |
|
1234
|
|
|
|
|
|
|
{} |
|
1235
|
1
|
|
|
|
|
10
|
); |
|
1236
|
1
|
|
|
|
|
37
|
return $group_hash; |
|
1237
|
|
|
|
|
|
|
} |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
################## |
|
1240
|
|
|
|
|
|
|
# Subroutine : h_assign |
|
1241
|
|
|
|
|
|
|
# Purpose : Copies all key/value from one or more source objects to a target object. |
|
1242
|
|
|
|
|
|
|
# Input : target_hash, source_hash_1, source_hash_2, .... |
|
1243
|
|
|
|
|
|
|
# Returns : returns the modified target object. |
|
1244
|
|
|
|
|
|
|
sub h_assign { |
|
1245
|
2
|
|
|
2
|
0
|
1006
|
my $target_hash = shift; |
|
1246
|
2
|
|
|
|
|
7
|
foreach my $source_hash (@_) { |
|
1247
|
2
|
50
|
|
|
|
8
|
if (v_type_of($source_hash) eq "HASH") { |
|
1248
|
2
|
|
|
|
|
36
|
while (my ($key, $val) = each %$source_hash) { |
|
1249
|
7
|
|
|
|
|
56
|
$target_hash->{$key} = $val; |
|
1250
|
|
|
|
|
|
|
} |
|
1251
|
|
|
|
|
|
|
} |
|
1252
|
|
|
|
|
|
|
else { |
|
1253
|
|
|
|
|
|
|
## raise an error? |
|
1254
|
|
|
|
|
|
|
} |
|
1255
|
|
|
|
|
|
|
} |
|
1256
|
2
|
|
|
|
|
7
|
return $target_hash; |
|
1257
|
|
|
|
|
|
|
} |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
1; |