File Coverage

blib/lib/Math/PartialOrder/CMasked.pm
Criterion Covered Total %
statement 387 594 65.1
branch 82 226 36.2
condition 34 131 25.9
subroutine 60 98 61.2
pod 36 38 94.7
total 599 1087 55.1


line stmt bran cond sub pod time code
1             # -*- Mode: Perl -*-
2              
3             #
4             # Copyright (c) 2001, Bryan Jurish. All rights reserved.
5             #
6             # This package is free software. You may redistribute it
7             # and/or modify it under the same terms as Perl itself.
8             #
9              
10             ###############################################################
11             #
12             # File: Math::PartialOrder::CMasked.pm
13             # Author: Bryan Jurish
14             #
15             # Description: Compilingt Math::PartialOrder class using
16             # Bit::Vector objects to store hierarchy information,
17             # internal storage of parents/children as 'Enum' strings.
18             #
19             ###############################################################
20              
21              
22             package Math::PartialOrder::CMasked;
23             # System modules
24 7     7   7091 use Carp;
  7         16  
  7         530  
25             require Exporter;
26             # 3rd party exstensions
27 7     7   5456 use Bit::Vector;
  7         9009  
  7         345  
28             # user extension modules
29 7     7   41 use Math::PartialOrder::Base;
  7         13  
  7         254  
30 7     7   3620 use Math::PartialOrder::Loader qw(:trvars);
  7         63  
  7         80089  
31             @ISA = qw(Math::PartialOrder::Base);
32             @EXPORT = qw();
33             @EXPORT_OK = (
34             qw($INITIAL_VECTOR_SIZE $VECTOR_GROW_STEP),
35             qw(%BIN_COMPAT &_get_bin_compat $_tr_index),
36             qw(&_bv_make_comparable &_bv_ensure_size
37             &_bv_bit_test &_bv_bit_on &_bv_bit_off
38             &_bv_union_d &_bv_intersection_d &_bv_difference_d),
39             qw(&_enum2indices &_enum_bit_test &_enum_bit_on &_enum_bit_off
40             &_enum_union &_enum_intersection &_enum_difference),
41             );
42             %EXPORT_TAGS =
43             (
44             sizevars => [qw($INITIAL_VECTOR_SIZE $VECTOR_GROW_STEP)],
45             bincompat => [qw(%BIN_COMPAT &_get_bin_compat $_tr_index)],
46             bvutils => [qw(&_bv_make_comparable &_bv_ensure_size
47             &_bv_bit_test &_bv_bit_on &_bv_bit_off
48             &_bv_union_d &_bv_intersection_d &_bv_difference_d)],
49             enumutils => [qw(&_enum2indices &_enum_bit_test &_enum_bit_on &_enum_bit_off
50             &_enum_union &_enum_intersection &_enum_difference)],
51             );
52              
53              
54             ###############################################################
55             # Package Variables
56             ###############################################################
57              
58             our $VERSION = 0.01;
59              
60             our $INITIAL_VECTOR_SIZE = 32;
61             our $VECTOR_GROW_STEP = 32;
62              
63             # for storage/binary compatibility
64             our %BIN_COMPAT =
65             (
66             Math::PartialOrder::CMasked => 0.01,
67             Math::PartialOrder::CEnum => 0.01,
68             QuD::Hierarchy::CMasked => 0.03,
69             QuD::Hierarchy::CEnum => 0.04,
70             QuD::Hierarchy::CVec => 0.02,
71             );
72             our $_tr_index = 3;
73              
74              
75             ###############################################################
76             # Initialization
77             # + object structure:
78             # {
79             # indices => { Type0 => Index0, ... }
80             # types => [ Type0, Type1, ... ]
81             # root => scalar type-name
82             # parents => [ Type0Parents, Type1Parents, ... ]
83             # children => [ Type0Children, Type1Children, ... ]
84             # attributes => [ { attr1.1 => val1.1, ... }, ... ]
85             # removed => [ FirstFreeIndex, SecondFreeIndex, ... ]
86             # vectors => [ Bit::Vector0, Bit::Vector1 ]
87             # ancestors => [ Type0Ancs, Type1Ancs, ... ] #-- Ancs are Bit::Vectors!
88             # descendants => [ Type0Decs, Type1Decs, ... ] #-- Decs are Bit::Vectors!
89             # compiled => scalar boolean
90             # hattributes => { a1 => v1, ... }
91             # }
92             ###############################################################
93             #----------------------------------------------------------------------
94             # new( {root=>$r} )
95             #----------------------------------------------------------------------
96             sub new ($;$) {
97 22     22 1 1966 my $proto = shift;
98 22         52 my $args = shift;
99 22   33     648 my $self = bless {
100             indices => {},
101             types => [],
102             root => undef,
103             parents => [],
104             children => [],
105             attributes => [],
106             removed => [],
107             vectors =>
108             [
109             Bit::Vector->new($INITIAL_VECTOR_SIZE), # [0]: vector(0)
110             Bit::Vector->new($INITIAL_VECTOR_SIZE), # [1]: vector(1)
111             ],
112             # --- new ---
113             ancestors => [],
114             descendants => [],
115             compiled => 0,
116             hattributes => {}
117             }, ref($proto)||$proto;
118             # root node
119 22   100     178 $self->_root($args->{root}||'BOTTOM');
120 22         79 return $self;
121             }
122              
123              
124              
125             #--------------------------------------------------------------
126             sub compile ($) {
127 10     10 1 21 my $self = shift;
128              
129             # variables
130 10         44 my $size = $self->_size;
131 10         25 my $ancs = $self->{ancestors};
132 10         15 my $dscs = $self->{descendants};
133 10         13 my ($i);
134              
135 10         41 $self->_ensure_vector_sizes();
136 10         18 my ($psv, $csv) = @{$self->{vectors}}; # working vectors
  10         22  
137 10         16 my ($pse,$cse); # enums
138 0         0 my ($j,$jmin,$jmax); # interval-indices
139 10         60 my $q = Bit::Vector->new($psv->Size); # queue as a bit-vector
140 10         47 my $hv = Bit::Vector->new($psv->Size); # hierarchy-vector
141              
142             # tc-encoding masks: initialization
143 10         37 for ($i = 0; $i < $size; ++$i) {
144 66 50       140 next unless (exists($self->{types}[$i]));
145             # initialize ancestors
146 66 50       322 if (exists($ancs->[$i])) {
147 0         0 _bv_ensure_size($ancs->[$i], $psv->Size);
148 0         0 $ancs->[$i]->Empty;
149             } else {
150 66         274 $ancs->[$i] = $psv->Shadow; # new empty vector, same size
151             }
152             # intialize descendants
153 66 50       119 if (exists($dscs->[$i])) {
154 0         0 _bv_ensure_size($dscs->[$i], $psv->Size);
155 0         0 $dscs->[$i]->Empty;
156             } else {
157 66         293 $dscs->[$i] = $psv->Shadow
158             }
159             }
160              
161 10         44 $hv->Fill;
162 10         18 $hv->Index_List_Remove(@{$self->{removed}});
  10         49  
163              
164 10         48 $q->Bit_On($self->_indices->{$self->{root}});
165 10         65 while (!$q->is_empty) {
166 66         164 $i = $q->Min;
167 66         125 $q->Bit_Off($i);
168              
169 66         111 $pse = $self->{parents}[$i];
170 66         92 $cse = $self->{children}[$i];
171              
172 66   100     252 $psv->from_Enum($pse || '');
173 66   100     221 $csv->from_Enum($cse || '');
174              
175             # sanity-check
176 66 50 33     484 if (($ancs->[$i]->equal($hv) && $cse) || ($dscs->[$i]->equal($hv) && $pse))
      33        
      33        
177             {
178 0         0 carp("PartialOrder compilation error: circularity detected for type `$t'");
179 0         0 $self->decompile;
180 0         0 return 0;
181             }
182              
183 66 100       159 if ($cse) {
184 44         146 $ancs->[$i]->Union($ancs->[$i],$psv);
185 44         115 $dscs->[$i]->Union($dscs->[$i],$csv);
186              
187             # propagate all known ancestors to direct descendants
188 44         124 foreach ($csv->Index_List_Read) {
189 66         190 $ancs->[$_]->Union($ancs->[$_], $ancs->[$i]);
190 66         169 $ancs->[$_]->Bit_On($i);
191             }
192              
193             # propagate (direct) descendants to all known ancestors
194 44         65 $j = 0;
195 44   66     403 while ($j <= $size && (($jmin,$jmax) = $ancs->[$i]->Interval_Scan_inc($j)))
196             {
197 46         104 for ($j = $jmin; $j <= $jmax; ++$j) {
198 58         211 $dscs->[$j]->Union($dscs->[$j], $dscs->[$i]);
199             }
200 46         267 $j = $jmax + 2;
201             }
202             # ...and keep going
203 44         192 $q->Union($q,$csv);
204             }
205             }
206 10         60 return $self->_compiled(1);
207             }
208              
209             #--------------------------------------------------------------
210             sub decompile ($) {
211 0     0 1 0 @{$_[0]->{ancestors}} = qw();
  0         0  
212 0         0 @{$_[0]->{descendants}} = qw();
  0         0  
213 0         0 return $_[0]->{compiled} = 0; # and set the compiled-flag
214             }
215             *uncompile = \&decompile;
216              
217              
218             #--------------------------------------------------------------
219             # $bool = compiled(), compiled($bool)
220             sub compiled ($;$) {
221 136 100   136 1 314 return $_[0]->{compiled} unless (exists($_[1]));
222 132 100       912 if ($_[1]) {
223             # do compile
224 57 100       141 return $_[0]->compile unless ($_[0]->{compiled});
225 49         192 return 1; # we're already compiled...
226             }
227 75 50       214 return $_[0]->decompile if ($_[0]->{compiled});
228 75         141 return 0;
229             }
230              
231              
232              
233             ###############################################################
234             # Hierarchy Maintainance: Type Operations
235             ###############################################################
236              
237             #--------------------------------------------------------------
238             # @types = $h->types()
239 120     120 1 289 sub types ($) { return grep { defined($_) } @{$_[0]->{types}}; }
  892         1889  
  120         289  
240              
241             #--------------------------------------------------------------
242             # $h = $h->add($t,@ps)
243             sub add {
244 181     181 1 573 my $self = shift;
245 181         215 my $type = shift;
246              
247             # sanity checks
248 181 100       357 return $self->move($type, @_) if ($self->has_type($type));
249 152 50       393 unless (defined($type)) {
250 0         0 carp("Undefined type not supported in ".ref($self)."::add()");
251 0         0 return $self;
252             }
253 152         214 $self->{compiled} = 0;
254              
255             # add this type
256 152         297 my $i = $self->_next_index();
257 152         307 $self->{types}[$i] = $type;
258 152         344 $self->{indices}{$type} = $i;
259              
260             # ensure parents are well-defined & well-placed
261 152         648 @_ = $self->ensure_types(@_);
262              
263             # set parents-relation for new $type
264 152         453 $self->_ensure_vector_sizes();
265 152         375 $self->{parents}[$i] = $self->_types2enum(@_);
266              
267             # set children-relation for new $type
268 152         293 my $kids = $self->{children};
269 152         200 $kids->[$i] = '';
270 152         179 foreach (@{$self->{indices}}{@_}) {
  152         322  
271 174 100       293 if ($kids->[$_]) { $kids->[$_] .= ",$i"; }
  57         199  
272 117         251 else { $kids->[$_] = $i; }
273             }
274 152         524 return $self;
275             }
276              
277              
278              
279             #--------------------------------------------------------------
280             # $bool = $h->has_type($t)
281             sub has_type ($$) {
282             return
283 2611   66 2611 1 25297 defined($_[1]) &&
284             defined($_[0]->{indices}{$_[1]}) &&
285             defined($_[0]->{types}[$_[0]->{indices}{$_[1]}]);
286             }
287              
288              
289             #--------------------------------------------------------------
290             # $h = $h->add_parents($t,@ps)
291             sub add_parents ($$@) {
292 4     4 1 18 my $self = shift;
293 4         8 my $type = shift;
294              
295             # sanity check(s)
296 4 50       11 return $self->add($type,@_) unless ($self->has_type($type));
297 4 50       107 unless (defined($type)) {
298 0         0 carp("Undefined type not supported in ".ref($self)."::add_parents()");
299 0         0 return $self;
300             }
301 4         13 $self->compiled(0);
302              
303 4         12 my $i = $self->{indices}{$type};
304              
305             # ensure parents are well-defined & well-placed
306 4         15 @_ = $self->ensure_types(@_);
307              
308             # ensure that our vectors can handle this
309 4         13 $self->_ensure_vector_sizes();
310              
311             # set parents-relation for new $type
312 4         14 $self->{parents}[$i] =
313             _enum_union($self->{parents}[$i],
314 4         17 join(',',@{$self->{indices}}{@_}),
315 4         13 @{$self->{vectors}}[0..1]);
316              
317             # set children-relation for new $type
318 4         10 my $kids = $self->{children};
319 4         7 foreach (@{$self->{indices}}{@_}) {
  4         11  
320 4         17 $kids->[$_] = _enum_bit_on($kids->[$_], $i, $self->{vectors}[0]);
321             }
322 4         14 return $self;
323             }
324              
325              
326             #--------------------------------------------------------------
327             # $h = $h->replace($old,$new)
328             sub replace ($$$) {
329 12     12 1 34 my ($h, $old, $new) = @_;
330 12 50       37 unless (defined($old)) {
331 0         0 carp("Undefined type not supported in ".ref($self)."::replace()");
332 0         0 return $h;
333             }
334 12         32 my $i = $h->{indices}{$old};
335 12 50       33 return $h->add($new,$h->{root}) unless (defined($i));
336 12         27 $h->{indices}{$new} = $i;
337 12         26 $h->{types}[$i] = $new;
338 12 100       43 if ($old eq $h->{root}) { $h->{root} = $new; }
  10         21  
339 12         33 return $h;
340             }
341              
342             #--------------------------------------------------------------
343             # $h = $h->move($t,@ps)
344             sub move ($$@) {
345 45     45 1 65 my $self = shift;
346 45         63 my $type = shift;
347              
348             # sanity check(s)
349 45 50       102 if (!defined($type)) {
350 0         0 carp("Undefined type not supported in ".ref($self)."::move()");
351 0         0 return $h;
352             }
353 45 100       112 if ($type eq $self->{root}) {
354 8 50       17 if (@_) { croak("Cannot move hierarchy root in ".ref($self)." object"); }
  0         0  
355 8         21 else { return $self; }
356             }
357 37 50       69 return $self->add($type, @_) unless ($self->has_type($type));
358 37         85 $self->compiled(0);
359              
360             # ensure parents are well-defined & well-placed
361 37         135 @_ = $self->ensure_types(@_);
362              
363             # adjust old child-relations for moved $type
364 37         81 my $i = $self->{indices}{$type};
365 37         59 my $v = $self->{vectors}[0];
366 37         54 my $kids = $self->{children};
367 37         113 foreach (@$kids[$self->_parents_indices($type)])
368             {
369 39 50       78 next unless (defined($_));
370 39         90 $_ = _enum_bit_off($_,$i,$v);
371             }
372              
373             # add new child-relations for moved $type
374 37         57 my @pindices = @{$self->{indices}}{@_};
  37         103  
375 37         68 foreach (@$kids[@pindices]) {
376 39         131 $_ = _enum_bit_on($_, $i, $v);
377             }
378              
379             # adjust parent-relation for moved $type
380 37         94 $self->{parents}[$i] = join(',',@pindices);
381 37         183 return $self;
382             }
383              
384              
385             #--------------------------------------------------------------
386             # remove(???): inherited from CEnum
387             sub remove ($@) {
388 2     2 1 4 my $self = shift;
389              
390 2 50 0     6 @_ =
      33        
391             grep {
392             # sanity check
393 2         6 $self->has_type($_) &&
394             ($_ ne $self->root || (carp("attempt to remove hierarchy root!") &&
395             0))
396             } @_;
397 2 50       7 return $self unless (@_); # not really deleting anything
398              
399 2         6 $self->compiled(0);
400              
401 2         3 my ($kids,$parents,$type,$idx);
402 2         5 my ($v0,$v1) = @{$self->{vectors}}[0,1];
  2         5  
403 2         4 foreach $type (@_) {
404             # get type-information
405 2         7 $idx = $self->{indices}{$type};
406 2         3 $kids = $self->{children}[$idx];
407 2         5 $parents = $self->{parents}[$idx];
408              
409             # adopt orphans
410 2         6 foreach (@{$self->{parents}}[_enum2indices($kids,$v0)]) {
  2         6  
411             # $_ is the parents-enum of an orphaned child
412 2         5 $_ = _enum_bit_off(_enum_union($_, $parents, $v0, $v1), $idx, $v0);
413             }
414 2         7 foreach (@{$self->{children}}[_enum2indices($parents,$v0)]) {
  2         9  
415             # $_ is the kids-enum of an adopting grandparent
416 2         6 $_ = _enum_bit_off(_enum_union($_, $kids, $v0, $v1), $idx, $v0);
417             }
418              
419             # actually remove the type
420 2         7 delete($self->{indices}{$type});
421 2         13 delete($self->{types}[$idx]);
422 2         4 delete($self->{parents}[$idx]);
423 2         5 delete($self->{children}[$idx]);
424              
425             # ... and mark its index as re-usable
426 2         3 push(@{$self->{removed}}, $idx);
  2         9  
427             }
428             # ensure 'removed' is sorted...
429 2         3 @{$self->{removed}} = sort { $a <=> $b } @{$self->{removed}};
  2         8  
  0         0  
  2         7  
430 2         12 return $self;
431             }
432              
433             #--------------------------------------------------------------
434             # @prts = $h->parents($type)
435             sub parents ($$) {
436             return
437 834 50   834 1 1687 $_[0]->has_type($_[1])
438             ? $_[0]->_enum2types($_[0]->{parents}[$_[0]->{indices}{$_[1]}],
439             #$_[0]->_parents_enum($_[1]),
440             $_[0]->{vectors}[0])
441             : qw();
442             }
443              
444             #--------------------------------------------------------------
445             # @kids = $h->children($type)
446             sub children ($$) {
447 28 50   28 1 69 $_[0]->has_type($_[1])
448             ? $_[0]->_enum2types($_[0]->{children}[$_[0]->{indices}{$_[1]}],
449             #$_[0]->_children_enum($_[1]),
450             $_[0]->{vectors}[0])
451             : qw();
452             }
453              
454              
455             #--------------------------------------------------------------
456             sub ancestors ($$) {
457 1     1 1 1 my ($i);
458             return
459 1 50 33     9 defined($_[1]) && defined($i = $_[0]->{indices}{$_[1]}) &&
460             $_[0]->compiled(1)
461             ? $_[0]->mask2types($_[0]->{ancestors}[$i])
462             : qw();
463             }
464              
465             #--------------------------------------------------------------
466             sub descendants ($$) {
467 1     1 1 2 my ($i);
468             return
469 1 50 33     8 defined($i = $_[0]->{indices}{$_[1]}) &&
470             $_[0]->compiled(1)
471             ? $_[0]->mask2types($_[0]->{descendants}[$i])
472             : qw();
473             }
474              
475             #--------------------------------------------------------------
476             # $bool = $h->has_parent($typ,$prt)
477             sub has_parent ($$$) {
478             return
479 402   33 402 1 1090 $_[0]->has_types(@_[1,2]) &&
480             _enum_bit_test($_[0]->{parents}[$_[0]->{indices}{$_[1]}],
481             $_[0]->{indices}{$_[2]},
482             $_[0]->{vectors}[0]);
483             }
484              
485              
486             #--------------------------------------------------------------
487             # $bool = $h->has_child($typ,$kid)
488             sub has_child ($$$) {
489             return
490 2   33 2 1 11 $_[0]->has_types(@_[1,2]) &&
491             _enum_bit_test($_[0]->{children}[$_[0]->{indices}{$_[1]}],
492             $_[0]->{indices}{$_[2]},
493             $_[0]->{vectors}[0]);
494             }
495              
496              
497              
498             #--------------------------------------------------------------
499             # $bool = $h->has_ancestor($typ,$anc)
500             sub has_ancestor ($$$) {
501             return
502 6   66 6 1 27 $_[0]->has_types(@_[1,2])
503             && $_[0]->has_ancestor_index($_[0]->{indices}{$_[1]},
504             $_[0]->{indices}{$_[2]});
505              
506             }
507              
508              
509             #--------------------------------------------------------------
510             # $bool = $h->has_descendent($typ,$dsc)
511             sub has_descendant ($$$) {
512             return
513 2   33 2 1 9 $_[0]->has_types(@_[1,2])
514             && $_[0]->has_descendant_index($_[0]->{indices}{$_[1]},
515             $_[0]->{indices}{$_[2]});
516              
517             }
518              
519             #--------------------------------------------------------------
520             # @sorted = subsort(@types)
521             sub subsort ($@) {
522 0     0 1 0 my $h = shift;
523 0 0       0 return qw() unless (@_);
524 0         0 $h->compiled(1);
525 0 0       0 my @indices = map { defined($_) ? $h->{indices}{$_} : undef } @_;
  0         0  
526 0         0 my @other = qw();
527 0         0 my ($i,$j);
528 0         0 for ($i = 0; $i <= $#_; ++$i) {
529 0         0 for ($j = $i+1; $j <= $#_; ++$j) {
530 0 0 0     0 if (!defined($indices[$i])
      0        
531             ||
532             (defined($indices[$j]) &&
533             $h->{ancestors}[$indices[$i]]->bit_test($indices[$j])))
534             {
535 0         0 @indices[$i,$j] = @indices[$j,$i];
536 0         0 @_[$i,$j] = @_[$j,$i];
537             }
538             }
539             }
540 0         0 return @_, @other;
541             }
542              
543              
544              
545             #--------------------------------------------------------------
546             # \%strata = get_strata(@types)
547             sub get_strata ($@) {
548 0     0 1 0 my $h = shift;
549 0         0 $h->compiled(1);
550 0 0       0 my @indices = @{$h->{indices}}{grep { defined($_) && exists($h->{indices}{$_}) } @_};
  0         0  
  0         0  
551 0         0 my (@strata);
552 0         0 foreach (@indices) { $strata[$_] = 0; }
  0         0  
553 0         0 my ($cmp,$i,$j);
554 0         0 my $changed = 1;
555 0         0 my $step = 1;
556              
557 0         0 while ($changed) {
558 0 0       0 last if ($step > scalar(@_));
559 0         0 $changed = 0;
560              
561 0         0 for ($i = 0; $i < $#indices; ++$i) {
562 0         0 for ($j = $i+1; $j <= $#indices; ++$j) {
563              
564 0 0       0 if ($h->{ancestors}[$indices[$j]]->bit_test($indices[$i])) {
    0          
565 0 0       0 next if ($strata[$indices[$i]] < $strata[$indices[$j]]);
566 0         0 $changed = 1;
567 0         0 $strata[$indices[$j]] = $strata[$indices[$i]] + 1;
568             }
569             elsif ($h->{ancestors}[$indices[$i]]->bit_test($indices[$j])) {
570 0 0       0 next if ($strata[$indices[$i]] > $strata[$indices[$j]]);
571 0         0 $changed = 1;
572 0         0 $strata[$indices[$i]] = $strata[$indices[$j]] + 1;
573             }
574             }
575             }
576             }
577 0         0 my %strata =
578 0         0 (map { $h->{types}[$_] => $strata[$_] } @indices);
579 0         0 return \%strata;
580             }
581              
582              
583             #--------------------------------------------------------------
584             # $h->_compare_index($i1,$i2);
585             sub _compare_index ($$$) {
586 0 0 0 0   0 return 0 if (# object-equality is easy
      0        
      0        
      0        
587             (defined($_[1]) and defined($_[2]) and $_[1] == $_[2])
588             or
589             # so is undef
590             (!defined($_[1]) and !defined($_[2])));
591 0 0       0 return 1 if ($_[0]->has_ancestor_index($_[1],$_[2]));
592 0 0       0 return -1 if ($_[0]->has_ancestor_index($_[2],$_[1]));
593 0         0 return undef; # incomparable
594             }
595              
596              
597             #--------------------------------------------------------------
598             # @min = $h->min(@types)
599             sub min ($@) {
600             return
601 0     0 1 0 $_[0]->mask2types
602             ($_[0]->_minimize($_[0]->types2mask(@_[1..$#_])));
603             }
604              
605              
606             #--------------------------------------------------------------
607             # @max = $h->max(@types)
608             sub max ($@) {
609             return
610 0     0 1 0 $_[0]->mask2types
611             ($_[0]->_maximize($_[0]->types2mask(@_[1..$#_])));
612             }
613              
614              
615             #--------------------------------------------------------------
616             # $bv = $h->_minimize($bv,$tmp)
617             sub _minimize ($$) {
618 5     5   7 my $self = shift;
619 5         11 my $bv = shift;
620 5         10 $self->compiled(1);
621 5         7 my $vecary = $self->{descendants};
622 5         4 my ($bmin,$bmax);
623 5         6 my $i = 0;
624 5   100     10 while ($i < $self->_size && (($bmin,$bmax) = $bv->Interval_Scan_inc($i)))
625             {
626 2         9 for ($i = $bmin; $i <= $bmax; ++$i) {
627 3 50       11 last unless ($bv->bit_test($i)); # it might already have been removed
628 3         16 $bv->Difference($bv, $vecary->[$i]);
629             }
630 2 50       7 if ($i >= $bmax) { $i = $bmax + 2; }
  2         4  
631 0         0 else { ++$i; }
632             }
633 5         18 return $bv;
634             }
635              
636             #--------------------------------------------------------------
637             # $bv = $h->_maximize($bv,$tmp)
638             sub _maximize ($$) {
639 1     1   2 my $self = shift;
640 1         2 my $bv = shift;
641 1         3 $self->compiled(1);
642 1         15 my ($bmin,$bmax);
643 1         3 my $vecary = $self->{ancestors};
644 1         3 my $i = $self->_size;
645 1   66     29 while ($i >= 0 && (($bmin,$bmax) = $bv->Interval_Scan_dec($i)))
646             {
647 1         6 for ($i = $bmax; $i >= $bmin; --$i) {
648 1 50       5 last unless ($bv->bit_test($i)); # it might already have been removed
649 1         5 $bv->Difference($bv, $vecary->[$i]);
650             }
651 1 50       3 if ($i <= $bmin) { $i = $bmin - 2; }
  1         4  
652 0         0 else { --$i; }
653             }
654 1         5 return $bv;
655             }
656              
657              
658             #--------------------------------------------------------------
659             # get_attribute($t,$a) : inherited from Base
660              
661             #--------------------------------------------------------------
662             # set_attribute($t,$a,$v) : inherited from Base
663              
664             #--------------------------------------------------------------
665             # $h1 = $h1->assign($h2)
666             sub assign ($$) {
667 12     12 1 3195 my ($h1,$h2) = @_;
668 12 100       88 return $h1->SUPER::assign($h2) unless (ref($h1) eq ref($h2));
669             #$h1->clear();
670              
671 4         4 %{$h1->{indices}} = %{$h2->{indices}};
  4         46  
  4         19  
672 4         16 @{$h1->{types}} = @{$h2->{types}};
  4         19  
  4         11  
673 4         8 @{$h1->{removed}} = @{$h2->{removed}};
  4         9  
  4         9  
674 4         7 @{$h1->{attributes}} = @{$h2->{attributes}};
  4         8  
  4         10  
675              
676 4         6 @{$h1->{parents}} = @{$h2->{parents}};
  4         21  
  4         8  
677 4         7 @{$h1->{children}} = @{$h2->{children}};
  4         20  
  4         8  
678              
679 4 0       10 @{$h1->{ancestors}} =
  0         0  
680             map {
681 4         10 defined($_) ? $_->Clone : undef
682 4         6 } @{$h2->{ancestors}};
683 4 0       7 @{$h1->{descendants}} =
  0         0  
684             map {
685 4         9 defined($_) ? $_->Clone : undef
686 4         8 } @{$h2->{descendants}};
687              
688 4         13 @$h1{qw(root compiled)} = @$h2{qw(root compiled)};
689              
690 4         7 %{$h1->{hattributes}} = %{$h2->{hattributes}};
  4         7  
  4         10  
691              
692 4         135 $h1->_ensure_vector_sizes();
693 4         15 return $h1;
694             }
695              
696              
697             #--------------------------------------------------------------
698             # $h1 = $h1->merge($h2,...) : inherited from Base
699              
700              
701             #--------------------------------------------------------------
702             # $h = $h->clear();
703             sub clear ($) {
704 10     10 1 18 my $self = shift;
705 10         13 @{$self->{types}} = qw();
  10         38  
706 10         19 %{$self->{indices}} = ();
  10         39  
707 10         17 @{$self->{parents}} = qw();
  10         30  
708 10         22 @{$self->{children}} = qw();
  10         30  
709 10         44 @{$self->{attributes}} = qw();
  10         22  
710 10         13 @{$self->{removed}} = qw();
  10         19  
711 10         14 @{$self->{ancestors}} = qw();
  10         18  
712 10         12 @{$self->{descendants}} = qw();
  10         17  
713 10         23 $self->{compiled} = 0;
714 10         16 %{$self->{hattributes}} = ();
  10         17  
715              
716             # make sure we still have the root type!
717 10         82 $self->_root($self->{root});
718 10         25 return $self;
719             }
720              
721              
722             ###############################################################
723             # Additional Hierarchy Info/Maintainence Operations
724             ###############################################################
725              
726             #--------------------------------------------------------------
727             # $root = $h->ensure_types(@types): inherited from Base
728              
729             #--------------------------------------------------------------
730             # has_types: inherited from Base
731              
732             # $bool = $h->has_ancestor_index($typ_idx,$anc_idx);
733             sub has_ancestor_index ($$$) {
734             return
735 3   66 3 1 31 defined($_[0]) && defined($_[1]) && defined($_[2]) &&
736             $_[0]->compiled(1) &&
737             defined($_[0]->{ancestors}[$_[1]]) &&
738             $_[0]->{ancestors}[$_[1]]->bit_test($_[2]);
739             }
740              
741             # $bool = $h->has_descendant_index($typ_idx,$dsc_idx);
742             sub has_descendant_index ($$$) {
743             return
744 1   33 1 1 11 defined($_[0]) && defined($_[1]) && defined($_[2]) &&
745             $_[0]->compiled(1) &&
746             defined($_[0]->{descendants}[$_[1]]) &&
747             $_[0]->{descendants}[$_[1]]->bit_test($_[2]);
748             }
749              
750             # $bv = $h->ancestors_mask($typ_idx)
751             sub ancestors_mask ($$) {
752             return
753 0 0 0 0 1 0 (defined($_[0]->{types}[$_[1]]) && $_[0]->compiled(1)
754             ? $_[0]->{ancestors}[$_[1]]->Clone
755             : undef);
756             }
757              
758             # $bv = $h->descendants_mask($typ_idx)
759             sub descendants_mask ($$) {
760             return
761 0 0 0 0 1 0 (defined($_[0]->{types}[$_[1]]) && $_[0]->compiled(1)
762             ? $_[0]->{ancestors}[$_[1]]->Clone
763             : undef);
764             }
765              
766              
767             #--------------------------------------------------------------
768             # $rv = $h->iterate_i(\&next,\&callback,\%args)
769             sub iterate_i ($&&;$) {
770 0     0 1 0 my ($self,$next,$callback,$args) = @_;
771 0         0 my ($i,$r);
772 0         0 my @q = defined($args->{start})
773             ? ref($args->{start})
774 0 0       0 ? @{$args->{start}}
    0          
775             : ($args->{start})
776             : ($self->{indices}{$self->root});
777 0         0 while (@q) {
778 0         0 $i = shift(@q);
779 0         0 $r = &$callback($self, $i, $args);
780 0 0       0 return $r if (defined($r));
781 0         0 push(@q, &$next($self,$i,$args));
782             }
783 0         0 return $args->{return};
784             }
785              
786             #--------------------------------------------------------------
787             # $rv = $h->iterate_pc_i(\&callback,\%args)
788             sub iterate_pc_i ($&;$) {
789             return
790 0     0 1 0 $_[0]->iterate_i(\&_iterate_pc_i_next, $_[1], $_[2]);
791             }
792             sub _iterate_pc_i_next ($$) {
793             return
794 0 0   0   0 _enum2indices($_[0]->{children}[$_[1]],
795             $_[0]->{vectors}[0])
796             if (defined($_[0]->{children}[$_[1]]));
797             }
798              
799              
800             #--------------------------------------------------------------
801             # $rv = $h->iterate_cp_i(\&sub,\%args)
802             sub iterate_cp_i ($&;$) {
803             return
804 0     0 1 0 $_[0]->iterate_i(\&_iterate_cp_i_next, $_[1], $_[2]);
805             }
806             sub _iterate_cp_i_next ($$) {
807             return
808 0 0   0   0 _enum2indices($_[0]->{parents}[$_[1]],
809             $_[0]->{vectors}[0])
810             if (defined($_[0]->{parents}[$_[1]]));
811             }
812              
813              
814              
815              
816             ###############################################################
817             # Type Operations
818             ###############################################################
819              
820             #--------------------------------------------------------------
821             # _get_bounds_log($i1,$i2,\@vectors,$want_indices,$min_or_max)
822             sub _get_bounds_log ($$$$;$$) {
823 13     13   14 my $self = shift;
824 13         15 my $i1 = shift;
825 13         14 my $i2 = shift;
826 13         15 my $vecary = shift;
827              
828             # sanity checks
829             return undef unless
830 13 50 33     68 (defined($i1) && defined($i2) && $self->compiled(1));
      33        
831              
832             # set up solutions-vector
833 13         71 my $solns = $self->{vectors}[0]->Shadow;
834              
835 13 50       28 if (shift) { # $want_indices
836             # get the easy answers
837 13 100       62 if ($vecary->[$i1]->bit_test($i2)) {
    50          
838 7         16 $solns->Bit_On($i2);
839 7         22 return $solns;
840             }
841             elsif ($vecary->[$i2]->bit_test($i1)) {
842 0         0 $solns->Bit_On($i1);
843 0         0 return $solns;
844             }
845             }
846              
847             # the guts
848 6         22 $solns->Intersection($vecary->[$i1],$vecary->[$i2]);
849 6 100       14 if ($_[0] < 0) {
    50          
850 5         12 return $self->_minimize($solns);
851             } elsif ($_[0] > 0) {
852 1         5 return $self->_maximize($solns);
853             }
854             # well that's odd -- let's just return the intersection
855 0         0 return $solns;
856             }
857              
858              
859             #--------------------------------------------------------------
860             # @lubs = $h->_lub($t1,$t2)
861             sub _lub ($$$) {
862             return
863 24     24   103 @{$_[0]->{types}}[$_[0]->_get_bounds_log
  24         83  
864             ($_[0]->{indices}{$_[1]},
865             $_[0]->{indices}{$_[2]},
866             $_[0]->{descendants},
867             1, -1)->Index_List_Read];
868             }
869              
870             #--------------------------------------------------------------
871             # @mcds = $h->_mcd($i1,$i2)
872             sub _mcd ($$$) {
873             return
874 0     0   0 @{$_[0]->{types}}[$_[0]->_get_bounds_log
  0         0  
875             ($_[0]->{indices}{$_[1]},
876             $_[0]->{indices}{$_[2]},
877             $_[0]->{descendants},
878             0, -1)->Index_List_Read];
879             }
880              
881             #--------------------------------------------------------------
882             # @glbs = $h->_glb($t1,$t2)
883             sub _glb ($$$) {
884             return
885 2     2   14 @{$_[0]->{types}}[$_[0]->_get_bounds_log
  2         10  
886             ($_[0]->{indices}{$_[1]},
887             $_[0]->{indices}{$_[2]},
888             $_[0]->{ancestors},
889             1, 1)->Index_List_Read];
890             }
891              
892             #--------------------------------------------------------------
893             # @mcas = $h->_mca($i1,$i2)
894             sub _mca ($$$) {
895             return
896 0     0   0 @{$_[0]->{types}}[$_[0]->_get_bounds_log
  0         0  
897             ($_[0]->{indices}{$_[1]},
898             $_[0]->{indices}{$_[2]},
899             $_[0]->{ancestors},
900             0, 1)->Index_List_Read];
901             }
902              
903              
904              
905              
906             ###############################################################
907             # Low-level Accessors/manipulators
908             ###############################################################
909              
910             # $h->_ensure_vector_sizes(), $h->_ensure_vector_sizes($size)
911             sub _ensure_vector_sizes ($;$) {
912 172 50   172   342 my $size = exists($_[1]) ? $_[1] : scalar(@{$_[0]->{types}});
  172         314  
913 172         477 $size = int(1 + ($size / $VECTOR_GROW_STEP)) * $VECTOR_GROW_STEP;
914 172         178 foreach (@{$_[0]->{vectors}}) {
  172         344  
915 344 50       1888 $_->Resize($size) unless ($_->Size > $size);
916             }
917             }
918              
919             #--------------------------------------------------------------
920 10     10   51 sub _indices ($) { return $_[0]->{indices}; }
921 0     0   0 sub _types ($) { return $_[0]->{types}; }
922              
923             #--------------------------------------------------------------
924             sub _root ($;$) {
925 109     109   332 my $self = shift;
926 109 100       574 return $self->{root} unless (@_);
927 32         53 my $root = shift;
928              
929 32 50 33     116 unless ($self->has_type($root) && $self->{root} eq $root) {
930 32         118 $self->compiled(0);
931              
932 32         82 my $i = $self->{indices}{$root};
933              
934 32 50       81 unless (defined($i)) {
935 32         116 $i = $self->_next_index();
936 32         81 $self->{indices}{$root} = $i; # ... add index
937 32         81 $self->{types}[$i] = $root; # ... add element
938             }
939              
940             # ... add parents
941 32         67 $self->{parents}[$i] = '';
942              
943             # adopt parentless types
944 32         45 my $c = '';
945 32         43 my $j;
946 32         52 for ($j = 0; $j <= $#{$self->{parents}}; ++$j) {
  64         198  
947 32 50       114 next if ($i == $j);
948 0 0       0 $c = $c ? ",$j" : $j unless ($self->{parents}[$j]);
    0          
949             }
950             # ... add children
951 32         162 $self->{children}[$i] = $c;
952             }
953 32         79 return $self->{root} = $root;
954             }
955             *root = \&_root;
956              
957              
958             #--------------------------------------------------------------
959 0     0   0 sub _set_root ($$) { return $_[0]->{root} = $_[1]; }
960              
961             #--------------------------------------------------------------
962 0     0   0 sub _parents ($) { return $_[0]->{parents}; }
963              
964             #--------------------------------------------------------------
965 0     0   0 sub _children ($) { return $_[0]->{children}; }
966              
967              
968              
969             #--------------------------------------------------------------
970 0     0   0 sub _ancestors ($) { return $_[0]->{ancestors}; }
971              
972             #--------------------------------------------------------------
973 1     1   34 sub _descendants ($) { return $_[0]->{descendants}; }
974              
975             #--------------------------------------------------------------
976             # $bool = _compiled(), _compiled($bool)
977             sub _compiled ($;$) {
978 10 50   10   143 return exists($_[1]) ? $_[0]->{compiled} = $_[1] : $_[0]->{compiled};
979             }
980              
981             #--------------------------------------------------------------
982             # \@attrs = $h->_attributes
983             # \%type_attrs_or_undef = $h->_attributes($type)
984             # \%attrs = $h->_attributes($type,\%attrs)
985             sub _attributes ($;$$) {
986 178 50   178   428 return $_[0]->{attributes} if (scalar(@_) == 1);
987 178         164 my ($i);
988 178 50 33     896 return undef unless (defined($_[1]) && defined($i = $_[0]->{indices}{$_[1]}));
989 178 50       689 return $_[0]->{attributes}[$i] if (scalar(@_) == 2);
990 0         0 return $_[0]->{attributes}[$i] = $_[2];
991             }
992              
993              
994             #--------------------------------------------------------------
995             # $hashref = $h->_hattributes(), $h->_hattributes($hashref);
996             sub _hattributes ($;$) {
997 50 100   50   286 return $_[0]->{hattributes} if (!exists($_[1]));
998 2         6 return $_[0]->{hattributes} = $_[1];
999             }
1000              
1001             #--------------------------------------------------------------
1002             # $aryref = $h->_removed
1003 0     0   0 sub _removed ($) { return $_[0]->{removed}; }
1004              
1005             #--------------------------------------------------------------
1006             # $aryref = $h->_vectors()
1007             # @vecs = $h->_vectors(@indices)
1008             sub _vectors($;@) {
1009             return
1010 0         0 exists($_[1])
1011 1 50   1   7 ? @{$_[0]->{vectors}}[@_[1..$#_]]
1012             : $_[0]->{vectors};
1013             }
1014              
1015              
1016             #--------------------------------------------------------------
1017             # $free_idx = $h->_next_index
1018             sub _next_index ($) {
1019             return
1020 184         467 scalar(@{$_[0]->{removed}})
  0         0  
1021 184         390 ? shift(@{$_[0]->{removed}})
1022 184 50   184   194 : scalar(@{$_[0]->{types}});
1023             }
1024              
1025             #--------------------------------------------------------------
1026             # $size = $h->_size;
1027 18     18   33 sub _size ($) { return scalar(@{$_[0]->{types}}); }
  18         76  
1028              
1029             #--------------------------------------------------------------
1030             # $bv = $h->mask;
1031             sub mask ($) {
1032 0     0 0 0 my $bv = Bit::Vector->new(scalar(@{$_[0]->{types}}));
  0         0  
1033 0         0 $bv->Fill;
1034 0         0 $bv->Index_List_Remove(@{$_[0]->{removed}});
  0         0  
1035 0         0 return $bv;
1036             }
1037              
1038              
1039              
1040             ###############################################################
1041             # Misc
1042             ###############################################################
1043              
1044             #--------------------------------------------------------------
1045             sub dump ($;$$) {
1046 0     0 1 0 my $h = shift;
1047 0   0     0 my $name = shift || "$h";
1048 0         0 my $what = shift;
1049 0         0 my $dump = "\$$name = [\n";
1050 0         0 my ($i);
1051 0 0 0     0 if (!defined($what) || $what =~ /\btypes\b/) {
1052 0         0 $dump .= " TYPES: [";
1053 0         0 for ($i = 0; $i <= $#{$h->{types}}; ++$i) {
  0         0  
1054 0 0       0 $dump .=
1055             "\n $i: " .
1056             (defined($h->{types}->[$i]) ? "'" . $h->{types}->[$i] . "'" : 'undef');
1057             }
1058 0         0 $dump .= "\n ],\n";
1059             }
1060 0 0 0     0 if (!defined($what) || $what =~ /\bindices\b/) {
1061 0         0 $dump .= " INDICES: {";
1062 0         0 foreach $i (keys(%{$h->{indices}})) {
  0         0  
1063 0         0 $dump .= "\n '$i' => '" . $h->{indices}->{$i} . "'";
1064             }
1065 0         0 $dump .= "\n },\n";
1066             }
1067 0 0 0     0 if (!defined($what) || $what =~ /\broot\b/) {
1068 0         0 $dump .= " ROOT: '" . $h->{root} . "',\n";
1069             }
1070 0 0 0     0 if (!defined($what) || $what =~ /\bparents\b/) {
1071 0         0 $dump .= " PARENTS: [";
1072 0         0 for ($i = 0; $i <= $#{$h->{parents}}; ++$i) {
  0         0  
1073 0 0       0 $dump .= "\n $i: (" . (defined($h->{parents}->[$i]) ? $h->{parents}->[$i] : 'undef') . ")";
1074             }
1075 0         0 $dump .= "\n ],\n";
1076             }
1077 0 0 0     0 if (!defined($what) || $what =~ /\bchildren\b/) {
1078 0         0 $dump .= " CHILDREN: [";
1079 0         0 for ($i = 0; $i <= $#{$h->{children}}; ++$i) {
  0         0  
1080 0 0       0 $dump .= "\n $i: (" . (defined($h->{children}->[$i]) ? $h->{children}->[$i] : 'undef') . ")";
1081             }
1082 0         0 $dump .= "\n ],\n";
1083             }
1084 0 0 0     0 if (!defined($what) || $what =~ /\bremoved\b/) {
1085 0         0 $dump .= " REMOVED: [" . join(',', @{$h->{removed}}) . "],\n";
  0         0  
1086             }
1087 0 0 0     0 if (!defined($what) || $what =~ /\bancestors\b/) {
1088 0         0 $dump .= " ANCESTORS: [";
1089 0         0 for ($i = 0; $i <= $#{$h->{ancestors}}; ++$i) {
  0         0  
1090 0 0       0 $dump .= "\n $i: (" .
1091             (defined($h->{ancestors}->[$i])
1092             ? $h->{ancestors}->[$i]->to_Enum
1093             : 'undef') . ")";
1094             }
1095 0         0 $dump .= "\n ],\n";
1096             }
1097 0 0 0     0 if (!defined($what) || $what =~ /\bdescendants\b/) {
1098 0         0 $dump .= " DESCENDANTS: [";
1099 0         0 for ($i = 0; $i <= $#{$h->{descendants}}; ++$i) {
  0         0  
1100 0 0       0 $dump .= "\n $i: (" .
1101             (defined($h->{descendants}->[$i])
1102             ? $h->{descendants}->[$i]->to_Enum
1103             : 'undef') . ")";
1104              
1105             }
1106 0         0 $dump .= "\n ],\n";
1107             }
1108 0 0 0     0 if (!defined($what) || $what =~ /\bhattr/) {
1109 0         0 $dump .= " HATTRS: {";
1110 0         0 foreach $i (keys(%{$h->{hattributes}})) {
  0         0  
1111 0         0 $dump .= "\n '$i' => '" . $h->{hattributes}->{$i} . "'";
1112             }
1113 0         0 $dump .= "\n },\n";
1114             }
1115 0 0 0     0 if (!defined($what) || $what =~ /\bcompiled\b/) {
1116 0 0       0 $dump .= " COMPILED: " . ($h->compiled ? '1' : '0') . "\n";
1117             }
1118 0         0 return $dump . "];\n";
1119             }
1120              
1121              
1122              
1123             ###############################################################
1124             # Storage/retrieval
1125             ###############################################################
1126              
1127             #--------------------------------------------------------------
1128             # $hashref = $h->_get_bin_compat() : for binary compatibility
1129 2     2   22 sub _get_bin_compat { return \%BIN_COMPAT; }
1130              
1131              
1132             #--------------------------------------------------------------
1133             # $h->_store_before($retr)
1134             sub _store_before {
1135 1     1   3 my ($h,$retr) = @_;
1136 1         3 $retr->{RemovedIndices} = $h->{removed};
1137 1         3 $retr->{ParentsEnums} = $h->{parents};
1138 1         2 $retr->{ChildrenEnums} = $h->{children};
1139 1         6 $retr->{CompiledFlag} = $h->{compiled};
1140 1 50       4 if ($h->{compiled}) {
1141 8 50       48 $retr->{AncestorsEnums} =
1142 1         3 [ map { defined($_) ? $_->to_Enum : undef } @{$h->{ancestors}} ];
  1         3  
1143 8 50       97 $retr->{DescendantsEnums} =
1144 1         13 [ map { defined($_) ? $_->to_Enum : undef } @{$h->{descendants}} ];
  1         4  
1145             }
1146 1         5 return $retr;
1147             }
1148              
1149             #--------------------------------------------------------------
1150             # $h->_store_type($tr,$retr) : add index to type-record
1151             sub _store_type {
1152 16     16   60 $_[1]->[$_tr_index] = $_[0]->{indices}{$_[1]->[0]};
1153             }
1154              
1155              
1156             #--------------------------------------------------------------
1157             # $h->_retrieve_type($tr,$retr)
1158             sub _retrieve_type {
1159 16     16   19 my ($h,$tr,$retr) = @_;
1160 16         29 my $type = $retr->{Refs}{$tr->[$_tr_name]};
1161 16         34 $h->{types}[$tr->[$_tr_index]] = $type;
1162 16         29 $h->{indices}{$type} = $tr->[$_tr_index];
1163 16 50       55 $h->_attributes($type, $retr->{Refs}{$tr->[$_tr_attrs]})
1164             if (defined($tr->[$_tr_attrs]));
1165             }
1166              
1167             #--------------------------------------------------------------
1168             # $h->_retrieve_after($retr)
1169             sub _retrieve_after {
1170 1     1   2 my ($h,$retr) = @_;
1171 1         4 @{$h->{removed}} = @{$retr->{RemovedIndices}};
  1         3  
  1         2  
1172 1         2 @{$h->{parents}} = @{$retr->{ParentsEnums}};
  1         6  
  1         2  
1173 1         3 @{$h->{children}} = @{$retr->{ChildrenEnums}};
  1         4  
  1         2  
1174 1         12 $h->{compiled} = $retr->{CompiledFlag};
1175              
1176 1 50       4 if ($h->{compiled}) {
1177 1         3 $h->_ensure_vector_sizes();
1178 1         5 my $size = $h->{vectors}[0]->Size;
1179              
1180 1 50       4 @{$h->{ancestors}} =
  8         34  
1181             map {
1182 1         3 defined($_) ? Bit::Vector->new_Enum($size,$_) : undef
1183 1         2 } @{$retr->{AncestorsEnums}};
1184              
1185 1 50       4 @{$h->{descendants}} =
  8         28  
1186             map {
1187 1         3 defined($_) ? Bit::Vector->new_Enum($size,$_) : undef
1188 1         2 } @{$retr->{DescendantsEnums}};
1189              
1190             }
1191 1         3 return $h;
1192             }
1193              
1194             ###############################################################
1195             # Mask Utility Methods
1196             ###############################################################
1197              
1198             # $bv = $h->_types2mask(@types)
1199             sub _types2mask ($@) {
1200 0     0   0 my $self = shift;
1201 0         0 my $bv = Bit::Vector->new($self->_size+1);
1202 0         0 $bv->Index_List_Store(@{$self->{indices}}{@_});
  0         0  
1203 0         0 return $bv;
1204             }
1205              
1206             sub types2mask ($@) {
1207 0     0 1 0 my $self = shift;
1208 0         0 my $bv = Bit::Vector->new($self->_size+1);
1209 0         0 $bv->Index_List_Store(grep { defined($_) } @{$self->{indices}}{@_});
  0         0  
  0         0  
1210 0         0 return $bv;
1211             }
1212              
1213             #--------------------------------------------------------------
1214             # _mask2types($bv) -- @types list for bit-vector mask
1215             #--------------------------------------------------------------
1216             sub _mask2types ($$) {
1217 0     0   0 return @{$_[0]->{types}}[$_[1]->Index_List_Read];
  0         0  
1218             # $_[0]->types_at($_[1]->Index_List_Read);
1219             }
1220              
1221             sub mask2types ($$) {
1222 2     2 0 7 return grep { defined($_) } @{$_[0]->{types}}[$_[1]->Index_List_Read];
  8         20  
  2         5  
1223             #grep { defined($_) } $_[0]->_types_at($_[1]->Index_List_Read);
1224             }
1225              
1226              
1227             ###############################################################
1228             # Enum Utility Methods
1229             ###############################################################
1230              
1231             # $enum = $h->_types2enum(@types)
1232             sub _types2enum ($@) {
1233             return
1234 152         638 scalar(@_) > 1
1235 152 50   152   531 ? join(',',@{$_[0]->{indices}}{@_[1..$#_]})
1236             #join(',', $_[0]->_indices_of(@_[1..$#_]))
1237             : '';
1238             }
1239              
1240             # $enum = $h->types2enum(@types)
1241             sub types2enum ($@) {
1242             return
1243 0         0 scalar(@_) > 1
1244 0 0   0 1 0 ? join(',', grep { defined($_) } @{$_[0]->{indices}}{@_[1..$#_]})
  0         0  
1245             #join(',', grep { defined($_) } $_[0]->_indices_of(@_[1..$#_]))
1246             : '';
1247             }
1248              
1249             # @types = $h->_enum2types($enum,$bv)
1250             sub _enum2types ($$$) {
1251 864     864   2521 $_[2]->from_Enum($_[1]);
1252 864         2027 return @{$_[0]->{types}}[$_[2]->Index_List_Read];
  864         3348  
1253             #$_[0]->_mask2types($_[2]);
1254             }
1255              
1256             # @types = $h->enum2types($enum,$bv)
1257             sub enum2types ($$$) {
1258 0     0 1 0 $_[2]->from_Enum($_[1]);
1259 0         0 return grep { defined($_) } @{$_[0]->{types}}[$_[2]->Index_List_Read];
  0         0  
  0         0  
1260             #$_[0]->mask2types($_[2]);
1261             }
1262              
1263              
1264              
1265             # $enum = $h->_parents_enum($type)
1266             sub _parents_enum ($$) {
1267 0     0   0 return $_[0]->{parents}[$_[0]->{indices}{$_[1]}];
1268             }
1269             # $enum = $_[0]->_children_enum($type)
1270             sub _children_enum ($$) {
1271 0     0   0 return $_[0]->{children}[$_[0]->{indices}{$_[1]}];
1272             }
1273              
1274              
1275             # $bv = $h->_parents_mask($type)
1276             sub _parents_mask ($$) {
1277 0     0   0 $_[0]->{vectors}[0]->from_Enum($_[0]->{parents}[$_[0]->{indices}{$_[1]}]);
1278 0         0 return $_[0]->{vectors}[0];
1279             }
1280             # $bv = $h->_children_mask($type)
1281             sub _children_mask ($$) {
1282 0     0   0 $_[0]->{vectors}[0]->from_Enum($_[0]->{children}[$_[0]->{indices}{$_[1]}]);
1283 0         0 return $_[0]->{vectors}[0];
1284             }
1285              
1286              
1287             # @indices = $h->_parents_indices($type);
1288             sub _parents_indices ($$) {
1289 37     37   198 $_[0]->{vectors}[0]->from_Enum($_[0]->{parents}[$_[0]->{indices}{$_[1]}]);
1290 37         163 return $_[0]->{vectors}[0]->Index_List_Read;
1291             #return $_[0]->_parents_mask($_[1])->Index_List_Read;
1292             }
1293             # @indices = $h->_children_indices($type);
1294             sub _children_indices ($$) {
1295 0     0   0 $_[0]->{vectors}[0]->from_Enum($_[0]->{children}[$_[0]->{indices}{$_[1]}]);
1296 0         0 return $_[0]->{vectors}[0]->Index_List_Read;
1297             }
1298              
1299              
1300              
1301             ###############################################################
1302             # Non-method Utilities: Bit-vectors
1303             ###############################################################
1304              
1305             # _bv_ensure_size($bv,$size)
1306             sub _bv_ensure_size ($$) {
1307 16 50   16   58 return ($_[0]->Size < $_[1]) ? $_[0]->Resize($_[1]) : undef;
1308             }
1309              
1310             # $size = _bv_make_comparable($bv1,$bv2)
1311             sub _bv_make_comparable ($$) {
1312 8     8   230 _bv_ensure_size($_[0],$_[1]->Size);
1313 8         33 _bv_ensure_size($_[1],$_[0]->Size);
1314 8         28 return $_[0]->Size;
1315             }
1316              
1317             # $bool = _bv_bit_test($bv,$idx)
1318 0   0 0   0 sub _bv_bit_test ($$) { return $_[0]->Size > $_[1] && $_[0]->bit_test($_[1]); }
1319              
1320             # _bv_bit_on($bv,$idx)
1321             sub _bv_bit_on ($$) {
1322 43 50   43   153 $_[0]->Resize($_[1]+1) if ($_[0]->Size <= $_[1]);
1323 43         143 $_[0]->Bit_On($_[1]);
1324             }
1325              
1326             # _bv_bit_off($bv,$idx)
1327             sub _bv_bit_off ($$) {
1328 43 50   43   313 $_[0]->Bit_Off($_[1]) if ($_[0]->Size > $_[1]);
1329             }
1330              
1331             # _bv_union_d($bv1,$bv2);
1332             sub _bv_union_d ($$) {
1333 8     8   24 _bv_make_comparable($_[0],$_[1]);
1334 8         40 $_[0]->Union(@_[0,1]);
1335             }
1336              
1337             # _bv_intersection_d($bv1,$bv2)
1338             sub _bv_intersection_d ($$) {
1339 0     0   0 _bv_make_comparable($_[0],$_[1]);
1340 0         0 $_[0]->Intersection(@_[0,1]);
1341             }
1342              
1343             # _bv_difference_d($bv1,$bv2)
1344             sub _bv_difference_d ($$) {
1345 0     0   0 _bv_make_comparable($_[0],$_[1]);
1346 0         0 $_[0]->Difference($_[0],$_[1]);
1347             }
1348              
1349              
1350             ###############################################################
1351             # Non-method Utilities: Enums
1352             ###############################################################
1353              
1354             # @indices = _enum2indices($enum,$bv)
1355             sub _enum2indices ($$) {
1356 4 50   4   21 $_[1]->from_Enum(defined($_[0]) ? $_[0] : '');
1357 4         21 return $_[1]->Index_List_Read;
1358             }
1359              
1360             # $bool = _enum_bit_test($enum,$bit,$bv)
1361             sub _enum_bit_test ($$$) {
1362 408 50   408   1463 $_[2]->from_Enum(defined($_[0]) ? $_[0] : '');
1363 408         3023 return $_[2]->bit_test($_[1]);
1364             }
1365              
1366             # $enum2 = _enum_bit_on($enum1,$bit,$bv)
1367             sub _enum_bit_on ($$$) {
1368 43 50   43   199 $_[2]->from_Enum(defined($_[0]) ? $_[0] : '');
1369 43         102 _bv_bit_on($_[2],$_[1]);
1370 43         253 return $_[2]->to_Enum;
1371             }
1372              
1373             # $enum2 = _enum_bit_off($enum1,$bit,$bv)
1374             sub _enum_bit_off ($$$) {
1375 43 50   43   151 $_[2]->from_Enum(defined($_[0]) ? $_[0] : '');
1376 43         132 _bv_bit_off($_[2],$_[1]);
1377 43         239 return $_[2]->to_Enum;
1378             }
1379              
1380             # $enum3 = _enum_union($enum1,$enum2,$bv1,$bv2);
1381             sub _enum_union ($$$$) {
1382 8 50   8   50 $_[2]->from_Enum(defined($_[0]) ? $_[0] : '');
1383 8 50       29 $_[3]->from_Enum(defined($_[1]) ? $_[1] : '');
1384 8         21 _bv_union_d($_[2],$_[3]);
1385 8         45 return $_[2]->to_Enum;
1386             }
1387              
1388             # $enum3 = _enum_intersection($enum1,$enum2,$bv1,$bv2);
1389             sub _enum_intersection ($$$$) {
1390 0 0   0     $_[2]->from_Enum(defined($_[0]) ? $_[0] : '');
1391 0 0         $_[3]->from_Enum(defined($_[1]) ? $_[1] : '');
1392 0           _bv_intersection_d($_[2],$_[3]);
1393 0           return $_[2]->to_Enum;
1394             }
1395              
1396             # $enum3 =_enum_difference($enum1,$enum2,$bv1,$bv2);
1397             sub _enum_difference ($$$$) {
1398 0 0   0     $_[2]->from_Enum(defined($_[0]) ? $_[0] : '');
1399 0 0         $_[3]->from_Enum(defined($_[1]) ? $_[1] : '');
1400 0           _bv_difference_d($_[2],$_[3]);
1401 0           return $_[2]->to_Enum;
1402             }
1403              
1404              
1405              
1406              
1407             1;
1408             __END__