package Object::InsideOut::Util; {
require 5.006;
use strict;
use warnings;
our $VERSION = '3.21';
$VERSION = eval $VERSION;
use Object::InsideOut::Metadata 3.21;
### Module Initialization ###
BEGIN {
# 1. Install our own 'no-op' version of Internals::SvREADONLY for Perl < 5.8
if (! Internals->can('SvREADONLY')) {
*Internals::SvREADONLY = sub (\$;$) { return; };
}
# Import 'share' and 'bless' if threads::shared
if ($threads::shared::threads_shared) {
import threads::shared;
}
}
# 2. Export requested subroutines
sub import
{
my $class = shift; # Not used
# Exportable subroutines
my %EXPORT_OK;
@EXPORT_OK{qw(create_object hash_re is_it make_shared shared_copy)} = undef;
# Handle entries in the import list
my $caller = caller();
my %meta;
while (my $sym = shift) {
if (exists($EXPORT_OK{lc($sym)})) {
# Export subroutine name
no strict 'refs';
*{$caller.'::'.$sym} = \&{lc($sym)};
$meta{$sym}{'hidden'} = 1;
} else {
OIO::Code->die(
'message' => "Symbol '$sym' is not exported by Object::InsideOut::Util",
'Info' => 'Exportable symbols: ' . join(' ', keys(%EXPORT_OK)),
'ignore_package' => __PACKAGE__);
}
}
if (%meta) {
add_meta($caller, \%meta);
}
}
### Subroutines ###
# Returns a blessed (optional), readonly (Perl 5.8) anonymous scalar reference
# containing either:
# the value returned by a user-specified subroutine; or
# a user-supplied scalar
sub create_object
{
my ($class, $id) = @_;
# Create the object from an anonymous scalar reference
my $obj = \do{ my $scalar; };
# Set the scalar equal to ...
if (my $ref_type = ref($id)) {
if ($ref_type eq 'CODE') {
# ... the value returned by the user-specified subroutine
local $SIG{__DIE__} = 'OIO::trap';
$$obj = $id->($class);
} else {
# Complain if something other than code ref
OIO::Args->die(
'message' => q/2nd argument to create_object() is not a code ref or scalar/,
'Usage' => 'create_object($class, $scalar) or create_object($class, $code_ref, ...)',
'ignore_package' => __PACKAGE__);
}
} else {
# ... the user-supplied scalar
$$obj = $id;
}
# Bless the object into the specified class (optional)
if ($class) {
bless($obj, $class);
}
# Make the object 'readonly' (Perl 5.8)
Internals::SvREADONLY($$obj, 1) if ($] >= 5.008003);
# Done - return the object
return ($obj);
}
# Make a thread-shared version of a complex data structure or object
sub make_shared
{
my $in = $_[0];
# If not sharing or already thread-shared, then just return the input
if (! $threads::shared::threads_shared ||
threads::shared::_id($in))
{
return ($in);
}
# Make copies of array, hash and scalar refs
my $out;
if (my $ref_type = Scalar::Util::reftype($in)) {
# Copy an array ref
if ($ref_type eq 'ARRAY') {
# Make empty shared array ref
$out = &threads::shared::share([]);
# Recursively copy and add contents
foreach my $val (@$in) {
push(@$out, make_shared($val));
}
}
# Copy a hash ref
elsif ($ref_type eq 'HASH') {
# Make empty shared hash ref
$out = &threads::shared::share({});
# Recursively copy and add contents
foreach my $key (keys(%{$in})) {
$out->{$key} = make_shared($in->{$key});
}
}
# Copy a scalar ref
elsif ($ref_type eq 'SCALAR') {
$out = \do{ my $scalar = $$in; };
threads::shared::share($out);
}
}
# If copy created above ...
if ($out) {
# Clone READONLY flag
if (Internals::SvREADONLY($in)) {
Internals::SvREADONLY($out, 1);
}
# Return blessed copy, if applicable
if (my $class = Scalar::Util::blessed($in)) {
return (bless($out, $class));
}
# Return clone
return ($out);
}
# Just return anything else
# NOTE: This will generate an error if we're thread-sharing,
# and $in is not an ordinary scalar.
return ($in);
}
# Make a copy of a complex data structure or object.
# If thread-sharing, then make the copy thread-shared.
sub shared_copy
{
return (($threads::shared::threads_shared) ? shared_clone(@_) : clone(@_));
}
# Recursively make a copy of a complex data structure or object that is
# thread-shared
sub shared_clone
{
my $in = $_[0];
# Make copies of array, hash and scalar refs
my $out;
if (my $ref_type = ref($in)) {
# Copy an array ref
if ($ref_type eq 'ARRAY') {
# Make empty shared array ref
$out = &threads::shared::share([]);
# Recursively copy and add contents
foreach my $val (@$in) {
push(@$out, shared_clone($val));
}
}
# Copy a hash ref
elsif ($ref_type eq 'HASH') {
# Make empty shared hash ref
$out = &threads::shared::share({});
# Recursively copy and add contents
foreach my $key (keys(%{$in})) {
$out->{$key} = shared_clone($in->{$key});
}
}
# Copy a scalar ref
elsif ($ref_type eq 'SCALAR') {
$out = \do{ my $scalar = $$in; };
threads::shared::share($out);
}
}
# If copy created above ...
if ($out) {
# Clone READONLY flag
if (Internals::SvREADONLY($in)) {
Internals::SvREADONLY($out, 1);
}
# Return clone
return ($out);
}
# Just return anything else
# NOTE: This will generate an error if we're thread-sharing,
# and $in is not an ordinary scalar.
return ($in);
}
# Recursively make a copy of a complex data structure or object
sub clone
{
my $in = $_[0];
# Make copies of array, hash and scalar refs
my $out;
if (my $ref_type = ref($in)) {
# Copy an array ref
if ($ref_type eq 'ARRAY') {
# Make empty shared array ref
$out = [];
# Recursively copy and add contents
foreach my $val (@$in) {
push(@$out, clone($val));
}
}
# Copy a hash ref
if ($ref_type eq 'HASH') {
# Make empty shared hash ref
$out = {};
# Recursively copy and add contents
foreach my $key (keys(%{$in})) {
$out->{$key} = clone($in->{$key});
}
}
# Copy a scalar ref
if ($ref_type eq 'SCALAR') {
$out = \do{ my $scalar = $$in; };
}
}
# If copy created above ...
if ($out) {
# Clone READONLY flag
if (Internals::SvREADONLY($in)) {
Internals::SvREADONLY($out, 1);
}
return ($out);
}
# Just return anything else
return ($in);
}
# Access hash value using regex
sub hash_re
{
my $hash = $_[0]; # Hash ref to search through
my $re = $_[1]; # Regex to match keys against
foreach (keys(%{$hash})) {
if (/$re/) {
return ($hash->{$_});
}
}
return;
}
# Checks if a scalar is a specified type
sub is_it
{
my ($thing, $what) = @_;
return ((Scalar::Util::blessed($thing))
? $thing->isa($what)
: (ref($thing) eq $what));
}
} # End of package's lexical scope
1;
syntax highlighted by Code2HTML, v. 0.9.1