/usr/share/perl5/perl5i/1/ARRAY.pm is in libperl5i-perl 2.13.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | # vi: set ts=4 sw=4 ht=4 et :
package perl5i::1::ARRAY;
use 5.010;
use strict;
use warnings;
no if $] >= 5.018000, warnings => 'experimental::smartmatch';
use perl5i::1::autobox;
sub first {
my ( $array, $filter ) = @_;
# Deep recursion and segfault (lines 90 and 91 in first.t) if we use
# the same elegant approach as in grep().
if ( ref $filter eq 'Regexp' ) {
return List::Util::first( sub { $_ ~~ $filter }, @$array );
}
return List::Util::first( sub { $filter->() }, @$array );
}
sub grep {
my ( $array, $filter ) = @_;
my @result = CORE::grep { $_ ~~ $filter } @$array;
return wantarray ? @result : \@result;
}
sub all {
require List::MoreUtils;
return List::MoreUtils::all($_[1], @{$_[0]});
}
sub any {
require List::MoreUtils;
return List::MoreUtils::any($_[1], @{$_[0]});
}
sub none {
require List::MoreUtils;
return List::MoreUtils::none($_[1], @{$_[0]});
}
sub true {
require List::MoreUtils;
return List::MoreUtils::true($_[1], @{$_[0]});
}
sub false {
require List::MoreUtils;
return List::MoreUtils::false($_[1], @{$_[0]});
}
sub uniq {
require List::MoreUtils;
my @uniq = List::MoreUtils::uniq(@{$_[0]});
return wantarray ? @uniq : \@uniq;
}
sub minmax {
require List::MoreUtils;
my @minmax = List::MoreUtils::minmax(@{$_[0]});
return wantarray ? @minmax : \@minmax;
}
sub mesh {
require List::MoreUtils;
my @mesh = List::MoreUtils::zip(@_);
return wantarray ? @mesh : \@mesh;
}
# Returns the code which will run when the object is used as a string
require overload;
my $overload_type = sub {
return unless ref $_[0];
my $str = overload::Method($_[0], q[""]);
my $num = overload::Method($_[0], "0+");
return "both" if $str and $num;
return "" if !$str and !$num;
return "str" if $str;
return "num" if $num;
};
my $are_equal;
# Two objects, possibly different classes, both overloaded.
my $equal_overload = sub {
my($obj1, $obj2) = @_;
my $type1 = $overload_type->($obj1);
my $type2 = $overload_type->($obj2);
# One of them is not overloaded
return if !$type1 or !$type2;
if( $type1 eq 'both' and $type2 eq 'both' ) {
return $obj1 == $obj2 || $obj1 eq $obj2;
}
elsif(
($type1 eq 'num' and $type2 eq 'str') or
($type1 eq 'str' and $type2 eq 'num')
)
{
# They're not both numbers, not both strings, and not both both
# Must be str vs num.
return $type1 eq 'num' ? $obj1+0 eq "$obj2"
: $obj2+0 eq "$obj1";
}
elsif( 'num' ~~ [$type1, $type2] ) {
return $obj1 == $obj2;
}
elsif( 'str' ~~ [$type1, $type2] ) {
return $obj1 eq $obj2;
}
else {
die "Should never be reached";
}
};
# Two objects, same class
my $equal_objects = sub {
my($r1, $r2) = @_;
# No need to check both, they're the same class
my $is_overloaded = overload::Overloaded($r1);
if( !$is_overloaded ) {
# Neither are overloaded, they're the same class, are they the same object?
return $r1 eq $r2;
}
else {
return $equal_overload->( $r1, $r2 );
}
};
# One overloaded object, one plain scalar
# STRING != OBJ
# NUMBER != OBJ
# STRING eq OBJeq
# STRING eq OBJboth
# STRING != OBJ== (using == will throw a warning)
# NUMBER == OBJ==
# NUMBER eq OBJeq
# NUMBER == OBJboth
my $equal_overload_vs_scalar = sub {
my($obj, $scalar) = @_;
my $type = $overload_type->($obj);
return unless $type;
if( $scalar->is_number ) {
if( $type eq 'str' ) {
$obj eq $scalar;
}
else {
$obj == $scalar;
}
}
else {
if( $type eq 'num' ) {
# Can't reliably compare
return;
}
else {
$obj eq $scalar;
}
}
};
my $equal_arrays = sub {
my ($r1, $r2) = @_;
# They can only be equal if they have the same nÂș of elements.
return if @$r1 != @$r2;
foreach my $i (0 .. @$r1 - 1) {
return unless $are_equal->($r1->[$i], $r2->[$i]);
}
return 1;
};
my $equal_hashes = sub {
my ($r1, $r2) = @_;
# Hashes can't be equal unless their keys are equal.
return unless ( %$r1 ~~ %$r2 );
# Compare the equality of the values for each key.
foreach my $key (keys %$r1) {
return unless $are_equal->( $r1->{$key}, $r2->{$key} );
}
return 1;
};
$are_equal = sub {
my ($r1, $r2) = @_;
# given two scalars, decide whether they are identical or not,
# recursing over deep data structures. Since it uses recursion,
# traversal is done depth-first.
# Warning: complex if-then-else decision tree ahead. It's ordered on
# my perceived and anecdotical take on the frequency of occurrence
# of each reftype: most popular on top, most rare on the bottom.
# This way we return as early as possible.
# undef eq undef
return 1 if !defined $r1 and !defined $r2;
# One is defined, one isn't
return if defined $r1 xor defined $r2;
my( $ref1, $ref2 ) = (ref $r1, ref $r2);
if( !$ref1 and !$ref2 ) {
my $is_num1 = $r1->is_number;
my $is_num2 = $r2->is_number;
if( $is_num1 xor $is_num2 ) {
# One's looks like a number, the other doesn't.
# Can't be equal.
return 0;
}
elsif( $is_num1 ) {
# They're both numbers
return $r1 == $r2;
}
else {
# They're both strings
return $r1 eq $r2;
}
}
elsif( $ref1 eq $ref2 ) {
if ( $ref1 ~~ [qw(Regexp GLOB CODE)] ) {
return $r1 eq $r2;
}
elsif ( $ref1 eq 'ARRAY' ) {
return $equal_arrays->( $r1, $r2 );
}
elsif ( $ref1 eq 'HASH' ) {
return $equal_hashes->( $r1, $r2 );
}
elsif ( $ref1 ~~ [qw(SCALAR REF)] ) {
return $are_equal->($$r1, $$r2);
}
else {
# Must be an object
return $equal_objects->( $r1, $r2 );
}
}
elsif( $ref1 and $ref2 ) {
# They're both refs, but not of the same type
my $is_overloaded1 = overload::Overloaded($r1);
my $is_overloaded2 = overload::Overloaded($r2);
if( $is_overloaded1 and $is_overloaded2 ) {
# Two overloaded objects
return $equal_overload->( $r1, $r2 );
}
else {
# One's an overloaded object, the other is not or
# Two plain refs different type or
# non-overloaded objects of different type.
return 0;
}
}
else {
# One is a ref, one is not
my $is_overloaded = $ref1 ? overload::Overloaded($r1)
: overload::Overloaded($r2);
if( $is_overloaded ) {
# One's an overloaded object, one's a plain scalar
return $ref1 ? $equal_overload_vs_scalar->($r1, $r2)
: $equal_overload_vs_scalar->($r2, $r1);
}
else {
# One's a plain ref or object, one's a plain scalar
return 0;
}
}
};
my $diff_two = sub {
# Compare differences between two arrays.
my ($c, $d) = @_;
my $diff = [];
# For each element of $c, try to find if it is equal to any of the
# elements of $d. If not, it's unique, and has to be pushed into
# $diff.
require List::MoreUtils;
foreach my $item (@$c) {
unless (
List::MoreUtils::any( sub { $are_equal->( $item, $_ ) }, @$d )
)
{
push @$diff, $item;
}
}
return $diff;
};
sub diff {
my ($base, @rest) = @_;
unless (@rest) {
return wantarray ? @$base : $base;
}
# XXX If I use carp here, the exception is "bizarre copy of ARRAY in
# ssasign ... "
die "Arguments must be array references" if grep { ref $_ ne 'ARRAY' } @rest;
foreach my $array (@rest) {
$base = $diff_two->($base, $array);
}
return wantarray ? @$base : $base;
}
my $intersect_two = sub {
# Compare differences between two arrays.
my ($c, $d) = @_;
my $intersect = [];
# For each element of $c, try to find if it is equal to any of the
# elements of $d. If it is, it's shared, and has to be pushed into
# $intersect.
require List::MoreUtils;
foreach my $item (@$c) {
if (
List::MoreUtils::any( sub { $are_equal->( $item, $_ ) }, @$d )
)
{
push @$intersect, $item;
}
}
return $intersect;
};
sub intersect {
my ($base, @rest) = @_;
unless (@rest) {
return wantarray ? @$base : $base;
}
# XXX If I use carp here, the exception is "bizarre copy of ARRAY in
# ssasign ... "
die "Arguments must be array references" if grep { ref $_ ne 'ARRAY' } @rest;
foreach my $array (@rest) {
$base = $intersect_two->($base, $array);
}
return wantarray ? @$base : $base;
}
1;
|