⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sparsemap.pm

📁 package of develop dns
💻 PM
字号:
# $Id: SparseMap.pm,v 1.1.1.1 2003/06/04 00:27:53 marka Exp $## Copyright (c) 2001 Japan Network Information Center.  All rights reserved.## By using this file, you agree to the terms and conditions set forth bellow.# # 			LICENSE TERMS AND CONDITIONS # # The following License Terms and Conditions apply, unless a different# license is obtained from Japan Network Information Center ("JPNIC"),# a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,# Chiyoda-ku, Tokyo 101-0047, Japan.# # 1. Use, Modification and Redistribution (including distribution of any#    modified or derived work) in source and/or binary forms is permitted#    under this License Terms and Conditions.# # 2. Redistribution of source code must retain the copyright notices as they#    appear in each source code file, this License Terms and Conditions.# # 3. Redistribution in binary form must reproduce the Copyright Notice,#    this License Terms and Conditions, in the documentation and/or other#    materials provided with the distribution.  For the purposes of binary#    distribution the "Copyright Notice" refers to the following language:#    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."# # 4. The name of JPNIC may not be used to endorse or promote products#    derived from this Software without specific prior written approval of#    JPNIC.# # 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC#    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT#    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A#    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE#    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR#    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF#    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR#    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,#    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR#    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF#    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.#package SparseMap;use strict;use Carp;my $debug = 0;sub new {    # common options are:    #   BITS => [8, 7, 6],	# 3-level map, 2nd level bits=7, 3rd = 6.    #   MAX  => 0x110000	# actually, max + 1.    my $class = shift;    my $self = {@_};    croak "BITS unspecified" unless exists $self->{BITS};    croak "BITS is not an array reference"	unless ref($self->{BITS}) eq 'ARRAY';    croak "MAX unspecified" unless exists $self->{MAX};    $self->{MAXLV} = @{$self->{BITS}} - 1;    $self->{FIXED} = 0;    my $lv0size = (indices($self, $self->{MAX} - 1))[0] + 1;    my @map = (undef) x $lv0size;    $self->{MAP} = \@map;    bless $self, $class;}sub add1 {    my ($self, $n, $val) = @_;    croak "Already fixed" if $self->{FIXED};    carp("data ($n) out of range"), return if $n >= $self->{MAX};    my @index = $self->indices($n);    my $r = $self->{MAP};    my $maxlv = $self->{MAXLV};    my $idx;    my $lv;    for ($lv = 0; $lv < $maxlv - 1; $lv++) {	$idx = $index[$lv];	$r->[$idx] = $self->create_imap($lv + 1, undef)	    unless defined $r->[$idx];	$r = $r->[$idx];    }    $idx = $index[$lv];    $r->[$idx] = $self->create_dmap() unless defined $r->[$idx];    $self->add_to_dmap($r->[$idx], $index[$maxlv], $val);}sub fix {    my $self = shift;    my $map = $self->{MAP};    my $maxlv = $self->{MAXLV};    my @tmp;    my @zero;    carp "Already fixed" if $self->{FIXED};    $self->collapse_tree();    $self->fill_default();    $self->{FIXED} = 1;}sub indices {    my $self = shift;    my $v = shift;    my @bits = @{$self->{BITS}};    my @idx;    print "indices($v,", join(',', @bits), ") = " if $debug;    for (my $i = @bits - 1; $i >= 0; $i--) {	my $bit = $bits[$i];	unshift @idx, $v & ((1 << $bit) - 1);	$v = $v >> $bit;    }    print "(", join(',', @idx), ")\n" if $debug;    @idx;}sub get {    my $self = shift;    my $v = shift;    my $map = $self->{MAP};    my @index = $self->indices($v);    croak "Not yet fixed" unless $self->{FIXED};    my $lastidx = pop @index;    foreach my $idx (@index) {	return $map->{DEFAULT} unless defined $map->[$idx];	$map = $map->[$idx];    }    $map->[$lastidx];}sub indirectmap {    my $self = shift;    croak "Not yet fixed" unless $self->{FIXED};    my @maps = $self->collect_maps();    my $maxlv = $self->{MAXLV};    my @bits = @{$self->{BITS}};    my @indirect = ();    for (my $lv = 0; $lv < $maxlv; $lv++) {	my $offset;	my $chunksz;	my $mapsz = @{$maps[$lv]->[0]};	if ($lv < $maxlv - 1) {	    # indirect map	    $offset = @indirect + @{$maps[$lv]} * @{$maps[$lv]->[0]};	    $chunksz = (1 << $bits[$lv + 1]);	} else {	    # direct map	    $offset = 0;	    $chunksz = 1;	}	my $nextmaps = $maps[$lv + 1];	foreach my $mapref (@{$maps[$lv]}) {	    croak "mapsize inconsistent ", scalar(@$mapref),	        " should be ", $mapsz, " (lv $lv)\n" if @$mapref != $mapsz;	    foreach my $m (@$mapref) {		my $idx;		for ($idx = 0; $idx < @$nextmaps; $idx++) {		    last if $nextmaps->[$idx] == $m;		}		croak "internal error: map corrupted" if $idx >= @$nextmaps;		push @indirect, $offset + $chunksz * $idx;	    }	}    }    @indirect;}sub cprog_imap {    my $self = shift;    my %opt = @_;    my $name = $opt{NAME} || 'map';    my @indirect = $self->indirectmap();    my $prog;    my $i;    my ($idtype, $idcol, $idwid);    my $max = 0;    $max < $_ and $max = $_ foreach @indirect;    if ($max < 256) {	$idtype = 'char';	$idcol = 8;	$idwid = 3;    } elsif ($max < 65536) {	$idtype = 'short';	$idcol = 8;	$idwid = 5;    } else {	$idtype = 'long';	$idcol = 4;	$idwid = 10;    }    $prog = "static const unsigned $idtype ${name}_imap[] = {\n";    $i = 0;    foreach my $v (@indirect) {	if ($i % $idcol == 0) {	    $prog .= "\n" if $i != 0;	    $prog .= "\t";	}	$prog .= sprintf "%${idwid}d, ", $v;	$i++;    }    $prog .= "\n};\n";    $prog;}sub cprog {    my $self = shift;    $self->cprog_imap(@_) . "\n" . $self->cprog_dmap(@_);}sub stat {    my $self = shift;    my @maps = $self->collect_maps();    my $elsize = $self->{ELSIZE};    my $i;    my $total = 0;    my @lines;    for ($i = 0; $i < $self->{MAXLV}; $i++) {	my $nmaps = @{$maps[$i]};	my $mapsz = @{$maps[$i]->[0]};	push @lines, "level $i: $nmaps maps (size $mapsz) ";	push @lines, "[", $nmaps * $mapsz * $elsize, "]" if $elsize;	push @lines, "\n";    }    my $ndmaps = @{$maps[$i]};    push @lines, "level $i: $ndmaps dmaps";    my $r = $maps[$i]->[0];    if (ref($r) eq 'ARRAY') {	push @lines, " (size ", scalar(@$r), ")";    }    push @lines, "\n";    join '', @lines;}sub collapse_tree {    my $self = shift;    my @tmp;    $self->_collapse_tree_rec($self->{MAP}, 0, \@tmp);}sub _collapse_tree_rec {    my ($self, $r, $lv, $refs) = @_;    my $ref = $refs->[$lv];    my $maxlv = $self->{MAXLV};    my $found;    return $r unless defined $r;    $ref = $refs->[$lv] = [] unless defined $ref;    if ($lv == $maxlv) {	$found = $self->find_dmap($ref, $r);    } else {	for (my $i = 0; $i < @$r; $i++) {	    $r->[$i] = $self->_collapse_tree_rec($r->[$i], $lv + 1, $refs);	}	$found = $self->find_imap($ref, $r);    }    unless ($found) {	$found = $r;	push @$ref, $found;    }    return $found;}sub fill_default {    my $self = shift;    my $maxlv = $self->{MAXLV};    my $bits = $self->{BITS};    my @zeros;    $zeros[$maxlv] = $self->create_dmap();    for (my $lv = $maxlv - 1; $lv >= 0; $lv--) {	my $r = $zeros[$lv + 1];	$zeros[$lv] = $self->create_imap($lv, $r);    }    _fill_default_rec($self->{MAP}, 0, $maxlv, \@zeros);}sub _fill_default_rec {    my ($r, $lv, $maxlv, $zeros) = @_;    return if $lv == $maxlv;    for (my $i = 0; $i < @$r; $i++) {	if (defined($r->[$i])) {	    _fill_default_rec($r->[$i], $lv + 1, $maxlv, $zeros);	} else {	    $r->[$i] = $zeros->[$lv + 1];	}    }}sub create_imap {    my ($self, $lv, $v) = @_;    my @map;    @map = ($v) x (1 << $self->{BITS}->[$lv]);    \@map;}sub find_imap {    my ($self, $maps, $map) = @_;    my $i;    foreach my $el (@$maps) {	next unless @$el == @$map;	for ($i = 0; $i < @$el; $i++) {	    last unless ($el->[$i] || 0) == ($map->[$i] || 0);	}	return $el if $i >= @$el;    }    undef;}sub collect_maps {    my $self = shift;    my @maps;    _collect_maps_rec($self->{MAP}, 0, $self->{MAXLV}, \@maps);    @maps;}sub _collect_maps_rec {    my ($r, $lv, $maxlv, $maps) = @_;    my $mapref = $maps->[$lv];    return unless defined $r;    foreach my $ref (@{$mapref}) {	return if $ref == $r;    }    push @{$maps->[$lv]}, $r;    if ($lv < $maxlv) {	_collect_maps_rec($_, $lv + 1, $maxlv, $maps) foreach @{$r};    }}    sub add {confess "Subclass responsibility";}sub create_dmap {confess "Subclass responsibility";}sub add_to_dmap {confess "Subclass responsibility";}sub find_dmap {confess "Subclass responsibility";}sub cprog_dmap {confess "Subclass responsibility";}1;package SparseMap::Bit;use strict;use vars qw(@ISA);use Carp;#use SparseMap;@ISA = qw(SparseMap);sub new {    my $class = shift;    my $self = $class->SUPER::new(@_);    $self->{DEFAULT} = 0;    bless $self, $class;}sub add {    my $self = shift;    $self->add1($_, undef) foreach @_;}sub create_dmap {    my $self = shift;    my $bmbits = $self->{BITS}->[-1];    my $s = "\0" x (1 << ($bmbits - 3));    \$s;}sub add_to_dmap {    my ($self, $map, $idx, $val) = @_;    vec($$map, $idx, 1) = 1;}sub find_dmap {    my ($self, $ref, $r) = @_;    foreach my $map (@$ref) {	return $map if $$map eq $$r;    }    return undef;}sub cprog_dmap {    my $self = shift;    my %opt = @_;    my $name = $opt{NAME} || 'map';    my @maps = $self->collect_maps();    my @bitmap = @{$maps[-1]};    my $prog;    my $bmsize = 1 << ($self->{BITS}->[-1] - 3);    $prog = <<"END";static const struct {	unsigned char bm[$bmsize];} ${name}_bitmap[] = {END    foreach my $bm (@bitmap) {	my $i = 0;	$prog .= "\t{{\n";	foreach my $v (unpack 'C*', $$bm) {	    if ($i % 16 == 0) {		$prog .= "\n" if $i != 0;		$prog .= "\t";	    }	    $prog .= sprintf "%3d,", $v;	    $i++;	}	$prog .= "\n\t}},\n";    }    $prog .= "};\n";    $prog;}1;package SparseMap::Int;use strict;use vars qw(@ISA);use Carp;#use SparseMap;@ISA = qw(SparseMap);sub new {    my $class = shift;    my $self = $class->SUPER::new(@_);    $self->{DEFAULT} = 0 unless exists $self->{DEFAULT};    bless $self, $class;}sub add {    my $self = shift;    while (@_ > 0) {	my $n = shift;	my $val = shift;	$self->add1($n, $val);    }}sub create_dmap {    my $self = shift;    my $tblbits = $self->{BITS}->[-1];    my $default = $self->{DEFAULT};    my @tbl = ($default) x (1 << $tblbits);    \@tbl;}sub add_to_dmap {    my ($self, $map, $idx, $val) = @_;    $map->[$idx] = $val;}sub find_dmap {    my ($self, $ref, $r) = @_;    foreach my $map (@$ref) {	if (@$map == @$r) {	    my $i;	    for ($i = 0; $i < @$map; $i++) {		last if $map->[$i] != $r->[$i];	    }	    return $map if $i == @$map;	}    }    return undef;}sub cprog_dmap {    my $self = shift;    my %opt = @_;    my $name = $opt{NAME} || 'map';    my @maps = $self->collect_maps();    my @table = @{$maps[-1]};    my $prog;    my $i;    my ($idtype, $idcol, $idwid);    my $tblsize = 1 << $self->{BITS}->[-1];    my ($min, $max);    foreach my $a (@table) {	foreach my $v (@$a) {	    $min = $v if !defined($min) or $min > $v;	    $max = $v if !defined($max) or $max < $v;	}    }    if (exists $opt{MAPTYPE}) {	$idtype = $opt{MAPTYPE};    } else {	my $u = $min < 0 ? '' : 'unsigned ';	my $absmax = abs($max);	$absmax = abs($min) if abs($min) > $absmax;	if ($absmax < 256) {	    $idtype = "${u}char";	} elsif ($absmax < 65536) {	    $idtype = "${u}short";	} else {	    $idtype = "${u}long";	}    }    $idwid = decimalwidth($max);    $idwid = decimalwidth($min) if decimalwidth($min) > $idwid;    $prog = <<"END";static const struct {	$idtype tbl[$tblsize];} ${name}_table[] = {END    foreach my $a (@table) {	my $i = 0;	my $col = 0;	$prog .= "\t{{\n\t";	foreach my $v (@$a) {	    my $s = sprintf "%${idwid}d, ", $v;	    $col += length($s);	    if ($col > 70) {		$prog .= "\n\t";		$col = length($s);	    }	    $prog .= $s;	}	$prog .= "\n\t}},\n";    }    $prog .= "};\n";    $prog;}sub decimalwidth {    my $n = shift;    my $neg = 0;    my $w;    if ($n < 0) {	$neg = 1;	$n = -$n;    }    if ($n < 100) {	$w = 2;    } elsif ($n < 10000) {	$w = 4;    } elsif ($n < 1000000) {	$w = 6;    } elsif ($n < 100000000) {	$w = 8;    } else {	$w = 10;    }    $w + $neg;}1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -