Class-EHierarchy
view release on metacpan or search on metacpan
lib/Class/EHierarchy.pm view on Meta::CPAN
# Class::EHierarchy -- Base class for hierarchally ordered objects
#
# (c) 2017, Arthur Corliss <corliss@digitalmages.com>
#
# $Id: lib/Class/EHierarchy.pm, 2.01 2019/05/23 07:29:49 acorliss Exp $
#
# This software is licensed under the same terms as Perl, itself.
# Please see http://dev.perl.org/licenses/ for more information.
#
#####################################################################
#####################################################################
#
# Environment definitions
#
#####################################################################
package Class::EHierarchy;
use 5.008003;
use strict;
use warnings;
use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS);
use base qw(Exporter);
use Carp;
use Scalar::Util qw(weaken);
($VERSION) = ( q$Revision: 2.01 $ =~ /(\d+(?:\.(\d+))+)/sm );
# Ordinal indexes for the @objects element records
use constant CEH_OREF => 0;
use constant CEH_PID => 1;
use constant CEH_PKG => 2;
use constant CEH_CLASSES => 3;
use constant CEH_CREF => 4;
# Ordinal indexes for the @properties element records
use constant CEH_PATTR => 0;
use constant CEH_PNAME => 1;
use constant CEH_PPKG => 1;
use constant CEH_PVAL => 2;
# Property attribute masks
use constant CEH_PATTR_SCOPE => 7;
use constant CEH_PATTR_TYPE => 504;
# Property attribute scopes
use constant CEH_PUB => 1;
use constant CEH_RESTR => 2;
use constant CEH_PRIV => 4;
# Property attribute types
use constant CEH_SCALAR => 8;
use constant CEH_ARRAY => 16;
use constant CEH_HASH => 32;
use constant CEH_CODE => 64;
use constant CEH_REF => 128;
use constant CEH_GLOB => 256;
# Property flags
use constant CEH_NO_UNDEF => 512;
@EXPORT = qw();
@EXPORT_OK = qw(CEH_PUB CEH_RESTR CEH_PRIV CEH_SCALAR CEH_ARRAY
CEH_HASH CEH_CODE CEH_REF CEH_GLOB CEH_NO_UNDEF _declProperty
_declMethod );
%EXPORT_TAGS = ( all => [@EXPORT_OK] );
#####################################################################
#
# Module code follows
#
#####################################################################
##########################################################
# Hierarchal code support
##########################################################
{
# Array of object references and metadata
my @objects;
# Array of recycled IDs availabe for use
my @recoveredIDs;
sub _dumpObjects {
# Purpose: Provides a list of objects
# Returns: List of refs
# Usage: @objects = _dumpObjects();
return map { $$_[CEH_OREF] } grep {defined} @objects;
}
sub _getID {
# Purpose: Generates and assigns a unique ID to the passed
# object, and initializes the internal records
# Returns: Integer
# Usage: $id = _genID();
my $obj = CORE::shift;
my $id = @recoveredIDs ? CORE::shift @recoveredIDs : $#objects + 1;
$$obj = $id;
$objects[$id] = [];
$objects[$id][CEH_CREF] = [];
$objects[$id][CEH_CLASSES] = [];
$objects[$id][CEH_OREF] = $obj;
$objects[$id][CEH_PKG] = ref $obj;
weaken( $objects[$$obj][CEH_OREF] );
$id = '0 but true' if $id == 0;
# Build object class list
{
no strict 'refs';
my ( $isaref, $tclass, $nclass, @classes, $n, $l );
my $class = ref $obj;
# Get the first level of classes we're subclassed from
$isaref = *{"${class}::ISA"}{ARRAY};
$isaref = [] unless defined $isaref;
foreach $tclass (@$isaref) {
CORE::push @classes, $tclass
if $tclass ne __PACKAGE__
and "$tclass"->isa(__PACKAGE__);
}
# Now, recurse into parent classes.
$n = 0;
$l = scalar @classes;
while ( $n < $l ) {
foreach $tclass ( @classes[ $n .. ( $l - 1 ) ] ) {
$isaref = *{"${tclass}::ISA"}{ARRAY};
$isaref = [] unless defined $isaref;
foreach $nclass (@$isaref) {
CORE::push @classes, $nclass
if $nclass ne __PACKAGE__
and "$nclass"->isa(__PACKAGE__);
}
}
$n = scalar @classes - $l + 1;
$l = scalar @classes;
}
# Add our current class
CORE::push @classes, $class;
# Save the list
foreach (@classes) { _addClass( $obj, $_ ) }
}
return $id;
}
sub _delID {
# Purpose: Recovers the ID for re-use while deleting the
# old data structures
# Returns: Boolean
# Usage: _recoverID($id);
my $obj = CORE::shift;
my $pid = $objects[$$obj][CEH_PID];
my @children = @{ $objects[$$obj][CEH_CREF] };
# Have the parent disown this child
_disown( $objects[$pid][CEH_OREF], $obj ) if defined $pid;
_disown( $obj, $objects[$_][CEH_OREF] ) if @children;
( run in 2.633 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )