0
|
1 #-----------------------------------------------------------------------------
|
|
2 # PACKAGE : Bio::Root::Vector.pm
|
|
3 # AUTHOR : Steve Chervitz (sac@bioperl.org)
|
|
4 # CREATED : 15 April 1997
|
|
5 # REVISION: $Id: Vector.pm,v 1.10 2002/10/22 07:38:37 lapp Exp $
|
|
6 # STATUS : Alpha
|
|
7 #
|
|
8 # WARNING: This is considered an experimental module.
|
|
9 #
|
|
10 # For documentation, run this module through pod2html
|
|
11 # (preferably from Perl v5.004 or better).
|
|
12 #
|
|
13 # MODIFIED:
|
|
14 # sac --- Fri Nov 6 14:24:48 1998
|
|
15 # * Added destroy() method (experimental).
|
|
16 # 0.023, 20 Jul 1998, sac:
|
|
17 # * Improved memory management (_destroy_master()).
|
|
18 #
|
|
19 # Copyright (c) 1997 Steve Chervitz. All Rights Reserved.
|
|
20 # This module is free software; you can redistribute it and/or
|
|
21 # modify it under the same terms as Perl itself.
|
|
22 #-----------------------------------------------------------------------------
|
|
23
|
|
24 package Bio::Root::Vector;
|
|
25
|
|
26 use Bio::Root::Global qw(:devel);
|
|
27 use Bio::Root::Object ();
|
|
28
|
|
29 # @ISA = qw(Bio::Root::Object); # Eventually perhaps...
|
|
30
|
|
31 use vars qw($ID $VERSION);
|
|
32 $ID = 'Bio::Root::Vector';
|
|
33 $VERSION = 0.04;
|
|
34
|
|
35 use strict;
|
|
36 my @SORT_BY = ('rank','name');
|
|
37
|
|
38 ## POD Documentation:
|
|
39
|
|
40 =head1 NAME
|
|
41
|
|
42 Bio::Root::Vector - Interface for managing linked lists of Perl5 objects.
|
|
43
|
|
44 =head1 SYNOPSIS
|
|
45
|
|
46 =head2 Object Creation
|
|
47
|
|
48 B<At present, Vector objects cannot be instantiated.> This
|
|
49 package is currently designed to be inherited along with another class
|
|
50 that provides a constructor (e.g., B<Bio::Root::Object.pm>).
|
|
51 The Vector provides a set of methods that can then be used for managing
|
|
52 sets of objects.
|
|
53
|
|
54 See L<the USAGE section | USAGE>.
|
|
55
|
|
56 =head1 INSTALLATION
|
|
57
|
|
58 This module is included with the central Bioperl distribution:
|
|
59
|
|
60 http://bio.perl.org/Core/Latest
|
|
61 ftp://bio.perl.org/pub/DIST
|
|
62
|
|
63 Follow the installation instructions included in the README file.
|
|
64
|
|
65
|
|
66 =head1 DESCRIPTION
|
|
67
|
|
68 Bio::Root::Vector.pm provides an interface for creating and manipulating
|
|
69 dynamic sets (linked lists) of Perl5 objects. This is an abstract class (ie.,
|
|
70 there is no constructor) and as such is expected to be inherited along with
|
|
71 some other class (see note above).
|
|
72
|
|
73 Vectors are handy when, for example, an object may contain one or more
|
|
74 other objects of a certain class. The container object knows only
|
|
75 that is has at least one such object; the multiplex nature of the contained
|
|
76 object is managed by the contained object via its Vector interface.
|
|
77 The methods for adding, removing, counting, listing, and sorting all objects
|
|
78 are bundled together in Vector.pm.
|
|
79
|
|
80 Thus, the current Bio::Root::Vector class is somewhat of a cross between an
|
|
81 interator and a composite design pattern. At present, a number of classes
|
|
82 utilize Bio::Root::Vector's composite-like behavior to implement a composite
|
|
83 pattern (Bio::SeqManager.pm, for example).
|
|
84 This is not necessarily ideal and is expected to change.
|
|
85
|
|
86 =head1 USAGE
|
|
87
|
|
88 For a usage demo of Bio::Root::Vector.pm see the scripts in the
|
|
89 examples/root_object/vector directory.
|
|
90
|
|
91
|
|
92 =head1 DEPENDENCIES
|
|
93
|
|
94 Bio::Root::Vector.pm does not directly inherit from B<Bio::Root::Object.pm> but
|
|
95 creates an manager object which does.
|
|
96
|
|
97 =head1 BUGS/FEATURES
|
|
98
|
|
99 By default, all Vectors are doubly-linked lists. This relieves one from
|
|
100 the burden of worrying about whether a given Vector is single- or doubly-linked.
|
|
101 However, when generating lots of Vectors or extremely large vectors, memory
|
|
102 becomes an issue. In particular, signaling the GC to free the memory for
|
|
103 an object when you want to remove it. B<Until this memory issue is resolved,
|
|
104 the use of Vector.pm is not recommended for large projects.>
|
|
105
|
|
106 Although it is not required, all objects within a vector are expected
|
|
107 to derive from the same class (package). Support for heterogeneous
|
|
108 Vectors has not been explicitly added (but they should work fine, as long
|
|
109 as you know what you're doing).
|
|
110
|
|
111 =head1 FEEDBACK
|
|
112
|
|
113 =head2 Mailing Lists
|
|
114
|
|
115 User feedback is an integral part of the evolution of this and other Bioperl modules.
|
|
116 Send your comments and suggestions preferably to one of the Bioperl mailing lists.
|
|
117 Your participation is much appreciated.
|
|
118
|
|
119 bioperl-l@bioperl.org - General discussion
|
|
120 http://bioperl.org/MailList.shtml - About the mailing lists
|
|
121
|
|
122 =head2 Reporting Bugs
|
|
123
|
|
124 Report bugs to the Bioperl bug tracking system to help us keep track the bugs and
|
|
125 their resolution. Bug reports can be submitted via email or the web:
|
|
126
|
|
127 bioperl-bugs@bio.perl.org
|
|
128 http://bugzilla.bioperl.org/
|
|
129
|
|
130 =head1 AUTHOR
|
|
131
|
|
132 Steve Chervitz E<lt>sac@bioperl.orgE<gt>
|
|
133
|
|
134 See L<the FEEDBACK section | FEEDBACK> for where to send bug reports and comments.
|
|
135
|
|
136 =head1 VERSION
|
|
137
|
|
138 Bio::Root::Vector.pm, 0.04
|
|
139
|
|
140 =head1 TODO
|
|
141
|
|
142 =over 4
|
|
143
|
|
144 =item * (Maybe) create an container class version of this module
|
|
145
|
|
146 to permit Vectors to be instantiated. Thus, instead of inherited
|
|
147 from both Object.pm and Vector.pm, you could create a Vector.pm object.
|
|
148
|
|
149 =item * Improve documentation.
|
|
150
|
|
151 =back
|
|
152
|
|
153 =head1 SEE ALSO
|
|
154
|
|
155 Bio::Root::Object.pm - Core object
|
|
156 Bio::Root::Err.pm - Error/Exception object
|
|
157 Bio::Root::Global.pm - Manages global variables/constants
|
|
158
|
|
159 http://bio.perl.org/Projects/modules.html - Online module documentation
|
|
160 http://bio.perl.org/ - Bioperl Project Homepage
|
|
161
|
|
162 =head1 ACKNOWLEDGEMENTS
|
|
163
|
|
164 This module was developed under the auspices of the Saccharomyces Genome
|
|
165 Database:
|
|
166 http://genome-www.stanford.edu/Saccharomyces
|
|
167
|
|
168 =head1 COPYRIGHT
|
|
169
|
|
170 Copyright (c) 1996-98 Steve Chervitz. All Rights Reserved.
|
|
171 This module is free software; you can redistribute it and/or
|
|
172 modify it under the same terms as Perl itself.
|
|
173
|
|
174 =cut
|
|
175
|
|
176
|
|
177 #'
|
|
178 ##
|
|
179 ###
|
|
180 #### END of main POD documentation.
|
|
181 ###
|
|
182 ##
|
|
183 #
|
|
184
|
|
185 =head1 APPENDIX
|
|
186
|
|
187 Methods beginning with a leading underscore are considered private
|
|
188 and are intended for internal use by this module. They are
|
|
189 B<not> considered part of the public interface and are described here
|
|
190 for documentation purposes only.
|
|
191
|
|
192 =cut
|
|
193
|
|
194 ########################################################
|
|
195 # CONSTRUCTOR #
|
|
196 ########################################################
|
|
197
|
|
198 ## No constructor. See _set_master() for construction of {Master} data member.
|
|
199
|
|
200 ## Destructor: Use remove_all() or remove().
|
|
201
|
|
202 # New Idea for destructor
|
|
203 #-------------
|
|
204 sub destroy {
|
|
205 #-------------
|
|
206 my $self = shift;
|
|
207 local($^W) = 0;
|
|
208 undef $self->{'_prev'};
|
|
209 undef $self->{'_next'};
|
|
210 undef $self->{'_rank'};
|
|
211 undef $self->{'_master'};
|
|
212 }
|
|
213
|
|
214 #####################################################################################
|
|
215 ## ACCESSORS ##
|
|
216 #####################################################################################
|
|
217
|
|
218
|
|
219 =head2 set_rank
|
|
220
|
|
221 Purpose : To set an object's rank to an arbitrary numeric
|
|
222 : value to be used for sorting the objects of the Vector.
|
|
223 Usage : $self->set_rank(-RANK =>numeric_ranking_data,
|
|
224 : -RANK_BY =>ranking_criterion_string);
|
|
225 : or without the named parameters as (rank, rank_by).
|
|
226 Throws : warning (if rank is set without also setting RANK_BY)
|
|
227 Comments : It is redundant for every object to store RANK_BY data.
|
|
228 : For this reason, the RANK_BY data is stored with the master
|
|
229 : object associated with the vector.
|
|
230
|
|
231 See Also : L<rank>(), L<rank_by>()
|
|
232
|
|
233 =cut
|
|
234
|
|
235 #-------------'
|
|
236 sub set_rank {
|
|
237 #-------------
|
|
238 my( $self, %param) = @_;
|
|
239
|
|
240 $self->_set_master($self) unless $self->{'_master'}->{'_set'};
|
|
241
|
|
242 my($rank, $rank_by) = $self->master->_rearrange([qw(RANK RANK_BY)], %param);
|
|
243
|
|
244 $DEBUG==1 and do{ print STDERR "$ID:set_rank() = $rank; Criteria: $rank_by."; <STDIN>; };
|
|
245
|
|
246 $self->{'_rank'} = ($rank || undef);
|
|
247 $self->{'_master'}->{'_rankBy'} = ($rank_by || undef);
|
|
248 if( defined $self->{'_rank'} and not defined $self->{'_master'}->{'_rankBy'} ) {
|
|
249 return $self->master->warn('Rank defined without ranking criteria.');
|
|
250 }
|
|
251 1;
|
|
252 }
|
|
253
|
|
254 sub _set_rank_by {
|
|
255 my( $self, $arg) = @_;
|
|
256 $self->{'_master'}->{'_rankBy'} = $arg || 'unknown';
|
|
257 }
|
|
258
|
|
259 sub _set_master {
|
|
260 ## A vector does not need a master object unless it needs to grow.
|
|
261 my($self,$obj) = @_;
|
|
262
|
|
263 # print "$ID: _set_master() new Master object for ${\$obj->name}."; <STDIN>;
|
|
264
|
|
265 require Bio::Root::Object;
|
|
266 my $master = {};
|
|
267 bless $master, 'Bio::Root::Object';
|
|
268
|
|
269 $master->{'_set'} = 1; ## Special member indicating that this method has been called.
|
|
270 ## Necessary since perl will generate an anonymous {Master}
|
|
271 ## hash ref on the fly. This ref will not be blessed however.
|
|
272 $master->{'_first'} = $obj;
|
|
273 $master->{'_last'} = $obj;
|
|
274 $master->{'_size'} = 1;
|
|
275 $master->{'_index'}->{$obj->name()} = $obj;
|
|
276 $self->{'_master'} = $master;
|
|
277
|
|
278 $self->{'_rank'} = 1;
|
|
279 $self->{'_prev'} = undef;
|
|
280 $self->{'_next'} = undef;
|
|
281 # $self->{'_master'}->{'_rankBy'} = undef; # Default rank is the order of addition to Vector.
|
|
282 }
|
|
283
|
|
284 sub _destroy_master {
|
|
285 # This is called when the last object in the vector is being remove()d
|
|
286 my $self = shift;
|
|
287
|
|
288 return if !$self->master or !$self->master->{'_set'};
|
|
289
|
|
290 my $master = $self->master;
|
|
291
|
|
292 ## Get rid of the Vector master object.
|
|
293 ref $master->{'_first'} and (%{$master->{'_first'}} = (), undef $master->{'_first'});
|
|
294 ref $master->{'_last'} and (%{$master->{'_last'}} = (), undef $master->{'_last'});
|
|
295 ref $master->{'_index'} and (%{$master->{'_index'}} = (), undef $master->{'_index'});
|
|
296 %{$master} = ();
|
|
297 undef $master;
|
|
298 }
|
|
299
|
|
300
|
|
301 =head2 clone_vector
|
|
302
|
|
303 Purpose : Call this method to clone the whole vector.
|
|
304 : NOT calling this method will extract the vector element.
|
|
305 Usage : $self->clone_vector();
|
|
306 Throws : Exception if argument is not an object reference.
|
|
307 Comments : This method is usually called from within a module's
|
|
308 : _set_clone() method for modules that inherit from
|
|
309 : Bio::Root::Vector.pm.
|
|
310
|
|
311 =cut
|
|
312
|
|
313 #-----------------'
|
|
314 sub clone_vector {
|
|
315 #-----------------
|
|
316 my($self, $obj) = @_;
|
|
317
|
|
318 ref($obj) || throw($self, "Can't clone $ID object: Not an object ref ($obj)");
|
|
319
|
|
320 $self->{'_prev'} = $obj->{'_prev'};
|
|
321 $self->{'_next'} = $obj->{'_next'};
|
|
322 $self->{'_rank'} = $obj->{'_rank'};
|
|
323 $self->{'_master'} = $obj->{'_master'};
|
|
324 }
|
|
325
|
|
326
|
|
327 =head2 prev
|
|
328
|
|
329 Purpose : Returns the previous object in the Vector or undef
|
|
330 : if on first object.
|
|
331 Usage : $self->prev
|
|
332
|
|
333 =cut
|
|
334
|
|
335 #--------
|
|
336 sub prev { my $self = shift; $self->{'_prev'}; }
|
|
337 #--------
|
|
338
|
|
339
|
|
340
|
|
341 =head2 next
|
|
342
|
|
343 Purpose : Returns the next object in the Vector or undef
|
|
344 : if on last object.
|
|
345 Usage : $self->next
|
|
346
|
|
347 =cut
|
|
348
|
|
349 #--------
|
|
350 sub next { my $self = shift; $self->{'_next'}; }
|
|
351 #--------
|
|
352
|
|
353
|
|
354
|
|
355 =head2 first
|
|
356
|
|
357 Purpose : Returns the first object in the Vector or $self
|
|
358 : if Vector size = 1.
|
|
359 Usage : $self->first
|
|
360
|
|
361 =cut
|
|
362
|
|
363 #----------
|
|
364 sub first {
|
|
365 #----------
|
|
366 my $self = shift;
|
|
367 defined $self->{'_master'} ? $self->{'_master'}->{'_first'} : $self;
|
|
368 }
|
|
369
|
|
370
|
|
371 =head2 last
|
|
372
|
|
373 Purpose : Returns the last object in the Vector or
|
|
374 : $self if Vector size = 1.
|
|
375 Usage : $self->last
|
|
376
|
|
377 =cut
|
|
378
|
|
379 #-------
|
|
380 sub last {
|
|
381 #-------
|
|
382 my $self = shift;
|
|
383 defined $self->{'_master'} ? $self->{'_master'}->{'_last'} : $self;
|
|
384 }
|
|
385
|
|
386
|
|
387
|
|
388 =head2 rank
|
|
389
|
|
390 Purpose : Returns the rank of the current object or 1
|
|
391 : if rank is not defined.
|
|
392 Usage : $self->rank
|
|
393
|
|
394 See Also : L<set_rank>()
|
|
395
|
|
396 =cut
|
|
397
|
|
398 #---------
|
|
399 sub rank { my $self = shift; $self->{'_rank'} || 1; }
|
|
400 #---------
|
|
401
|
|
402
|
|
403
|
|
404 =head2 rank_by
|
|
405
|
|
406 Purpose : Returns the ranking criterion or the string 'order of addition'
|
|
407 : if rankBy has not been explicitly set.
|
|
408 Usage : $self->rank_by
|
|
409
|
|
410 See Also : L<set_rank>()
|
|
411
|
|
412 =cut
|
|
413
|
|
414 #-----------
|
|
415 sub rank_by {
|
|
416 #-----------
|
|
417 my $self = shift;
|
|
418 defined $self->{'_master'} ? ($self->{'_master'}->{'_rankBy'}||'order of addition')
|
|
419 : 'unranked';
|
|
420 }
|
|
421
|
|
422
|
|
423
|
|
424 =head2 size
|
|
425
|
|
426 Purpose : Returns the number of objects currently in the Vector.
|
|
427 Usage : $self->size
|
|
428
|
|
429 =cut
|
|
430
|
|
431 #---------
|
|
432 sub size {
|
|
433 #---------
|
|
434 my $self = shift;
|
|
435 defined $self->{'_master'} ? $self->{'_master'}->{'_size'} : 1;
|
|
436 }
|
|
437
|
|
438
|
|
439 =head2 master
|
|
440
|
|
441 Purpose : Returns the master object associated with the Vector.
|
|
442 : (should probably be a private method).
|
|
443 Usage : $self->master
|
|
444
|
|
445 =cut
|
|
446
|
|
447 #-----------
|
|
448 sub master { my $self = shift; $self->{'_master'}; }
|
|
449 #-----------
|
|
450
|
|
451
|
|
452 ## Not sure what these potentially dangerous methods are used for.
|
|
453 ## Should be unnecessary and probably can be removed.
|
|
454 sub set_prev { my($self,$obj) = @_; $self->{'_prev'} = $obj; }
|
|
455 sub set_next { my($self,$obj) = @_; $self->{'_next'} = $obj; }
|
|
456
|
|
457 #############################################################################
|
|
458 # INSTANCE METHODS ##
|
|
459 #############################################################################
|
|
460
|
|
461
|
|
462 =head2 is_first
|
|
463
|
|
464 Purpose : Test whether the current object is the first in the Vector.
|
|
465 Usage : $self->is_first
|
|
466
|
|
467 =cut
|
|
468
|
|
469 #------------
|
|
470 sub is_first { my($self) = shift; return not defined $self->{'_prev'}; }
|
|
471 #------------
|
|
472
|
|
473
|
|
474 =head2 is_last
|
|
475
|
|
476 Purpose : Test whether the current object is the last in the Vector.
|
|
477 Usage : $self->is_last
|
|
478
|
|
479 =cut
|
|
480
|
|
481 #------------
|
|
482 sub is_last { my($self) = shift; return not defined $self->{'_next'}; }
|
|
483 #------------
|
|
484
|
|
485
|
|
486
|
|
487
|
|
488 =head2 get
|
|
489
|
|
490 Purpose : Retrives an object from the Vector given its name.
|
|
491 : Returns undef if the object cannot be found.
|
|
492 Usage : $self->get(object_name)
|
|
493 Examples : $self->get($obj->name)
|
|
494
|
|
495 See Also : L<list>()
|
|
496
|
|
497 =cut
|
|
498
|
|
499 #--------
|
|
500 sub get {
|
|
501 #--------
|
|
502 my($self,$name) = @_;
|
|
503
|
|
504 my ($obj);
|
|
505 # print "$ID get(): getting $name\n";
|
|
506
|
|
507 if($self->{'_master'}->{'_set'}) {
|
|
508 # my @names = keys %{$self->{'_master'}->{'_index'}};
|
|
509 # print "$ID: names in hash:\n@names";<STDIN>;
|
|
510 # print " returning $self->{'_master'}->{'_index'}->{$name}\n";
|
|
511 local($^W) = 0;
|
|
512 $obj = $self->{'_master'}->{'_index'}->{$name};
|
|
513 }
|
|
514
|
|
515 elsif($self->name =~ /$name/i) {
|
|
516 # print " returning self\n";
|
|
517 $obj = $self;
|
|
518 }
|
|
519
|
|
520 if(not ref $obj) {
|
|
521 $self->throw("Can't get object named \"$name\": object not set or name undefined.");
|
|
522 }
|
|
523 $obj;
|
|
524 }
|
|
525
|
|
526 ## Former strategy: hunt through the list for the object.
|
|
527 ## No longer needed since master indexes all objects.
|
|
528 # do{
|
|
529 # if($obj->name eq $name) { return $obj; }
|
|
530 #
|
|
531 # } while($obj = $current->prev());
|
|
532
|
|
533
|
|
534
|
|
535
|
|
536 =head2 add
|
|
537
|
|
538 Purpose : Add an object to the end of a Vector.
|
|
539 Usage : $self->add(object_reference)
|
|
540
|
|
541 See also : L<insert>(), L<remove>()
|
|
542
|
|
543 =cut
|
|
544
|
|
545 #--------
|
|
546 sub add {
|
|
547 #--------
|
|
548 my($self,$new,$index) = @_;
|
|
549
|
|
550 $self->_set_master($self) unless $self->{'_master'}->{'_set'};
|
|
551
|
|
552 # print "\n\nADDING TO VECTOR ${\ref $self} ${\$self->name}\nFOR PARENT: ${\ref $self->parent} ${\$self->parent->name}\n\n";
|
|
553
|
|
554 $self->{'_next'} = $new;
|
|
555 $new->{'_prev'} = $self;
|
|
556 $self->{'_master'}->{'_last'} = $new;
|
|
557 $self->{'_master'}->{'_size'}++;
|
|
558 $new->{'_master'} = $self->{'_master'};
|
|
559 $new->_incrementRank();
|
|
560 $new->Bio::Root::Vector::_index();
|
|
561
|
|
562 # printf "NEW CONTENTS: (n=%s)\n", $self->size;
|
|
563 # my $obj = $self->first;
|
|
564 # my $count=0;
|
|
565 # do { print "\n","Object #",++$count,"\n";
|
|
566 # $obj->display;
|
|
567 # } while($obj=$obj->next);
|
|
568 # <STDIN>;
|
|
569 }
|
|
570
|
|
571
|
|
572 sub _index {
|
|
573 my($self) = @_;
|
|
574 my $name = $self->name;
|
|
575
|
|
576 # Generate unique name, if necessary, for indexing purposes.
|
|
577 if( not $name or $name =~ /anonymous/) {
|
|
578 $name ||= '';
|
|
579 $name .= $self->size();
|
|
580 }
|
|
581 # print "$ID: _index() called for $name\n";
|
|
582
|
|
583 $self->{'_master'}->{'_index'}->{$name} = $self;
|
|
584 }
|
|
585
|
|
586 sub _incrementRank {
|
|
587 my $self = shift;
|
|
588 return if not defined $self->{'_prev'};
|
|
589 $self->{'_rank'} = $self->{'_prev'}->rank() + 1;
|
|
590 }
|
|
591
|
|
592
|
|
593 =head2 remove
|
|
594
|
|
595 Purpose : Remove the current object from the Vector.
|
|
596 Usage : $self->remove([-RET=>'first'|'last'|'next'|'prev'], [-UPDATE => 0|1])
|
|
597 Returns : The first, last, next, or previous object in the Vector
|
|
598 : depending on the value of the -RET parameter.
|
|
599 : Default = next.
|
|
600 Argument : Named parameters: (TAGS CAN BE ALL UPPER OR ALL LOWER CASE)
|
|
601 : -RET => string: 'first', 'last', 'prev' 'next'
|
|
602 : THis indicates the object to be returned.
|
|
603 : -UPDATE => boolean, if non-zero all objects in the vector
|
|
604 : will be re-ranked.
|
|
605 Comments : The -UPDATE parameter should be set to true to force a re-updating
|
|
606 : of the rank data for each object. (default = 0, no update).
|
|
607
|
|
608 See Also : L<add>(), L<insert>(), L<shift>(), L<chop>()
|
|
609
|
|
610 =cut
|
|
611
|
|
612 #-----------
|
|
613 sub remove {
|
|
614 #-----------
|
|
615 my($self,%param) = @_;
|
|
616 my $updateRank = $param{-UPDATE} || $param{'-update'} || 0;
|
|
617 my $ret = $param{-RET} || $param{'-ret'} || 'next';
|
|
618
|
|
619 $DEBUG==2 && do{ print STDERR "$ID: removing ${\$self->name}; ret = $ret";<STDIN>; };
|
|
620
|
|
621 ## This set of conditionals involves primarily pointer shuffling.
|
|
622 ## The special case of destroying a vector of size 1 is handled.
|
|
623
|
|
624 if($self->is_first()) {
|
|
625 $DEBUG==2 && print STDERR "---> removing first object: ${\$self->name()}.\n";
|
|
626 if($self->is_last) {
|
|
627 # print "Removing only object in vector: ${\$self->name}.\n";
|
|
628 $self->_destroy_master();
|
|
629 return $self->destroy;
|
|
630 } else {
|
|
631 undef ($self->{'_next'}->{'_prev'});
|
|
632 $self->_update_first($self->{'_next'});
|
|
633 }
|
|
634
|
|
635 } elsif($self->is_last()) {
|
|
636 $DEBUG==2 && print STDERR "---> removing last object: ${\$self->name()}.\n";
|
|
637 undef ($self->{'_prev'}->{'_next'});
|
|
638 $self->_update_last($self->{'_prev'});
|
|
639
|
|
640 } else {
|
|
641 $DEBUG==2 && print STDERR "---> removing internal object.\n";
|
|
642 $self->{'_prev'}->{'_next'} = $self->{'_next'};
|
|
643 $self->{'_next'}->{'_prev'} = $self->{'_prev'};
|
|
644 }
|
|
645
|
|
646 $updateRank && $self->_update_rank();
|
|
647 $self->{'_master'}->{'_size'}--;
|
|
648
|
|
649 # print "new vector size = ",$self->size,"\n"; <STDIN>;
|
|
650
|
|
651 my($retObj);
|
|
652
|
|
653 if( $self->size) {
|
|
654 if($ret eq 'first') { $retObj = $self->first(); }
|
|
655 elsif($ret eq 'last') { $retObj = $self->last(); }
|
|
656 elsif($ret eq 'next') { $retObj = $self->next(); }
|
|
657 elsif($ret eq 'prev') { $retObj = $self->prev(); }
|
|
658 }
|
|
659
|
|
660 ## Destroy the object.
|
|
661 # $self->destroy;
|
|
662
|
|
663 $DEBUG && do{ print STDERR "$ID: returning ${\$retObj->name}";<STDIN>; };
|
|
664
|
|
665 $retObj;
|
|
666 }
|
|
667
|
|
668 sub _update_first {
|
|
669 my($self,$first) = @_;
|
|
670 $DEBUG && print STDERR "Updating first.\n";
|
|
671 undef ($first->{'_prev'});
|
|
672 $self->{'_master'}->{'_first'} = $first;
|
|
673 }
|
|
674
|
|
675 sub _update_last {
|
|
676 my($self,$last) = @_;
|
|
677 $DEBUG && print STDERR "Updating last.\n";
|
|
678 undef ($last->{'_next'});
|
|
679 $self->{'_master'}->{'_last'} = $last;
|
|
680 }
|
|
681
|
|
682
|
|
683 =head2 remove_all
|
|
684
|
|
685 Purpose : Remove all objects currently in the Vector.
|
|
686 Usage : $self->remove_all
|
|
687
|
|
688 See Also : L<remove>(), L<shift>(), L<chop>()
|
|
689
|
|
690 =cut
|
|
691
|
|
692 #---------------
|
|
693 sub remove_all {
|
|
694 #---------------
|
|
695 my($self,%param) = @_;
|
|
696
|
|
697 $DEBUG==2 && print STDERR "DESTROYING VECTOR $self ${\$self->name}";
|
|
698
|
|
699 # print "$ID Removing all.";
|
|
700
|
|
701 $self = $self->first();
|
|
702
|
|
703 while(ref $self) {
|
|
704 # print "$ID: removing ${\$self->name}\n";
|
|
705 $self = $self->remove(-RET=>'next');
|
|
706 }
|
|
707 }
|
|
708
|
|
709
|
|
710 =head2 shift
|
|
711
|
|
712 Purpose : Remove the first object from the Vector.
|
|
713 : This is a wrapper for remove().
|
|
714 Usage : $self->shift([-RET=>'first'|'last'|'next'|'prev'])
|
|
715 Returns : The object returned by remove().
|
|
716
|
|
717 See Also : L<remove>(), L<chop>()
|
|
718
|
|
719 =cut
|
|
720
|
|
721 #---------
|
|
722 sub shift {
|
|
723 #---------
|
|
724 my($self,%param) = @_;
|
|
725 $self = $self->first();
|
|
726 $self = $self->remove(%param);
|
|
727 }
|
|
728
|
|
729
|
|
730 =head2 chop
|
|
731
|
|
732 Purpose : Remove the last object from the Vector.
|
|
733 : This is a wrapper for remove().
|
|
734 Usage : $self->chop([-RET=>'first'|'last'|'next'|'prev'])
|
|
735 Returns : The object returned by remove().
|
|
736
|
|
737 See Also : L<remove>(), L<shift>()
|
|
738
|
|
739 =cut
|
|
740
|
|
741 #----------
|
|
742 sub chop {
|
|
743 #----------
|
|
744 my($self,%param) = @_;
|
|
745 $self = $self->last();
|
|
746 $self = $self->remove(%param);
|
|
747 }
|
|
748
|
|
749
|
|
750
|
|
751 =head2 insert
|
|
752
|
|
753 Purpose : Insert a new object into the vector relative to the current object.
|
|
754 Usage : $self->insert(object_ref, ['before'|'after'])
|
|
755 Examples : $self->insert($obj) # Default insert after $self
|
|
756 : $self->insert($obj,'before')
|
|
757 Returns : The new number of objects in the vector (int).
|
|
758 Throws : exception if the first argument is not a reference.
|
|
759
|
|
760 See Also : L<add>(), L<remove>()
|
|
761
|
|
762 =cut
|
|
763
|
|
764 #-----------
|
|
765 sub insert {
|
|
766 #-----------
|
|
767 my($self,$object,$where) = @_;
|
|
768 my($first);
|
|
769 $where ||= 'after';
|
|
770
|
|
771 $self->_set_master($self) unless $self->{'_master'}->{'_set'};
|
|
772
|
|
773 ref($object) || return $self->master->throw("Can't insert. Not an object: $object");
|
|
774
|
|
775 if($where eq 'before') {
|
|
776 $object->{'_next'} = $self;
|
|
777 $object->{'_prev'} = $self->{'_prev'};
|
|
778 $object->{'_master'} = $self->{'_master'};
|
|
779 $self->{'_prev'}->{'_next'} = $object;
|
|
780 $self->{'_prev'} = $object;
|
|
781 } else {
|
|
782 $object->{'_prev'} = $self;
|
|
783 $object->{'_next'} = $self->{'_next'};
|
|
784 $object->{'_master'} = $self->{'_master'};
|
|
785 $self->{'_next'}->{'_prev'} = $object;
|
|
786 $self->{'_next'} = $object;
|
|
787 }
|
|
788 $self->{'_master'}->{'_size'}++;
|
|
789 $object->Bio::Root::Vector::_index(); ##Fully qualified to disambiguate a potentially common method name.
|
|
790 $self->_update_rank();
|
|
791 }
|
|
792
|
|
793 sub _update_rank {
|
|
794 my($self) = @_;
|
|
795 my $current = $self->first();
|
|
796 my $count = 0;
|
|
797 $DEBUG && print STDERR "$ID: Updating rank.\n";
|
|
798 do{
|
|
799 $count++;
|
|
800 $current->{'_rank'} = $count;
|
|
801
|
|
802 } while($current = $current->next());
|
|
803 }
|
|
804
|
|
805
|
|
806 =head2 list
|
|
807
|
|
808 Purpose : Returns objects in the Vector as an array or array slice.
|
|
809 Usage : $self->list([starting_object|'first'] [,ending_object|'last'])
|
|
810 Examples : $self->list
|
|
811 : $self->list('first',$self->prev)
|
|
812
|
|
813 See Also : L<get>()
|
|
814
|
|
815 =cut
|
|
816
|
|
817 #----------
|
|
818 sub list {
|
|
819 #----------
|
|
820 my($self,$start,$stop) = @_;
|
|
821 my(@list);
|
|
822
|
|
823 $start ||= 1;
|
|
824 $stop ||= 'last';
|
|
825
|
|
826 if( $start =~ /first|beg|start/i or $start <= 1 ) {
|
|
827 $start = $self->first();
|
|
828 }
|
|
829
|
|
830 if( $stop =~ /last|end|stop/i ) {
|
|
831 $stop = $self->last();
|
|
832 }
|
|
833
|
|
834 ref($start) || ($start = $self->first());
|
|
835 ref($stop) || ($stop = $self->last());
|
|
836
|
|
837 my $obj = $start;
|
|
838 my $fini = 0;
|
|
839 do{
|
|
840 push @list, $obj;
|
|
841 if($obj eq $stop) { $fini = 1; }
|
|
842 } while( $obj = $obj->next() and !$fini);
|
|
843
|
|
844 @list;
|
|
845 }
|
|
846
|
|
847
|
|
848 =head2 sort
|
|
849
|
|
850 Purpose : Sort the objects in the Vector.
|
|
851 Usage : $self->sort(['rank'|'name'], [reverse])
|
|
852 Returns : The last object of the sorted Vector.
|
|
853 Argument : First argument can be 'name' or 'rank' to sort on
|
|
854 : the object's name or rank data member, respectively.
|
|
855 : If reverse is non-zero, sort will be in reverse order.
|
|
856 Example : $self->sort() # Default sort by rank, not reverse.
|
|
857 : $self->sort('name','reverse')
|
|
858
|
|
859 =cut
|
|
860
|
|
861 #---------'
|
|
862 sub sort {
|
|
863 #---------
|
|
864 my ($self,$sortBy,$reverse) = @_;
|
|
865 my (@unsortedList,@sortedList);
|
|
866
|
|
867 $sortBy ||= 'rank';
|
|
868 my $rankBy = $self->rank_by;
|
|
869
|
|
870 ### Build the initial unsorted list.
|
|
871 my $obj = $self->first();
|
|
872 do{
|
|
873 push @unsortedList, $obj;
|
|
874 } while( $obj = $obj->next());
|
|
875
|
|
876 # print "UNSORTED LIST:\n";
|
|
877 # foreach(@unsortedList) {print $_->name().' '};<STDIN>;
|
|
878
|
|
879 ### Sort it.
|
|
880 if( $sortBy =~ /rank/i) {
|
|
881 # print "sorting by rank";
|
|
882 if($reverse) {
|
|
883 # print " (reverse).\n";
|
|
884 @sortedList = reverse sort _sort_by_rank @unsortedList;
|
|
885 } else {
|
|
886 @sortedList = sort _sort_by_rank @unsortedList;
|
|
887 }
|
|
888 } elsif( $sortBy =~ /name/i) {
|
|
889 # print "sorting by name";
|
|
890 if($reverse) {
|
|
891 # print "(reverse).\n";
|
|
892 @sortedList = reverse sort _sort_by_name @unsortedList;
|
|
893 } else {
|
|
894 @sortedList = sort _sort_by_name @unsortedList;
|
|
895 }
|
|
896 } else {
|
|
897 # print "unknown sort criteria: $sortBy\n";
|
|
898 $self->warn("Invalid sorting criteria: $sortBy.",
|
|
899 "Sorting by rank.");
|
|
900 @sortedList = sort _sort_by_rank @unsortedList;
|
|
901 }
|
|
902
|
|
903
|
|
904 # if($reverse) { @sortedList = reverse sort @sortedList; }
|
|
905
|
|
906 # print "SORTED LIST:\n";
|
|
907 # foreach(@sortedList) {print $_->name().' '};<STDIN>;
|
|
908
|
|
909 ### Re-load the Vector with the sorted list.
|
|
910 my $count=0;
|
|
911
|
|
912 $self = $sortedList[0];
|
|
913 $self->_set_master($self);
|
|
914 $self->_set_rank_by($rankBy);
|
|
915
|
|
916 my($i);
|
|
917 my $current = $self;
|
|
918 for($i=1; $i<@sortedList; $current=$sortedList[$i], $i++) {
|
|
919 $current->add($sortedList[$i]);
|
|
920 if($i==$#sortedList) { $sortedList[$i]->{'_next'} = undef;}
|
|
921 }
|
|
922
|
|
923 $self->last();
|
|
924 }
|
|
925
|
|
926 sub _sort_by_rank { my $aRank = $a->rank(); my $bRank = $b->rank(); $aRank <=> $bRank; }
|
|
927
|
|
928 sub _sort_by_name { my $aName = $a->name(); my $bName = $b->name(); $aName cmp $bName; }
|
|
929
|
|
930
|
|
931
|
|
932 =head2 valid_any
|
|
933
|
|
934 Purpose : Determine if at least one object in the Vector is valid.
|
|
935 Usage : $self->valid_any
|
|
936 Status : Deprecated.
|
|
937 Comments : A non-valid object should throw an exception that must be
|
|
938 : be caught an dealt with on the spot.
|
|
939
|
|
940 See Also : B<Bio::Root::Object::valid()>
|
|
941
|
|
942 =cut
|
|
943
|
|
944 #-------------
|
|
945 sub valid_any {
|
|
946 #-------------
|
|
947 my $self = &shift(@_);
|
|
948
|
|
949 my $obj = $self->first();
|
|
950 do{
|
|
951 return 1 if $obj->valid();
|
|
952 } while( $obj = $obj->next());
|
|
953
|
|
954 return undef;
|
|
955 }
|
|
956
|
|
957
|
|
958 =head2 valid_all
|
|
959
|
|
960 Purpose : Determine if all objects in the Vector are valid.
|
|
961 Usage : $self->valid_all
|
|
962 Comments : A non-valid object should throw an exception that must be
|
|
963 : be caught an dealt with on the spot.
|
|
964
|
|
965 See Also : B<Bio::Root::Object::valid()>
|
|
966
|
|
967 =cut
|
|
968
|
|
969 #--------------
|
|
970 sub valid_all {
|
|
971 #--------------
|
|
972 my $self = &shift(@_);
|
|
973
|
|
974 my $obj = $self->first();
|
|
975 do{
|
|
976 return unless $obj->valid();
|
|
977 } while( $obj = $obj->next());
|
|
978
|
|
979 return 1;
|
|
980 }
|
|
981
|
|
982 sub _display_stats {
|
|
983 # This could be fleshed out a bit...
|
|
984
|
|
985 my( $self, $OUT ) = @_;
|
|
986
|
|
987 printf ( $OUT "%-11s %s\n","RANK:", $self->rank());
|
|
988 printf ( $OUT "%-11s %s\n","RANK BY:", $self->rank_by());
|
|
989 }
|
|
990
|
|
991 1;
|
|
992 __END__
|
|
993
|
|
994 #####################################################################################
|
|
995 # END OF CLASS #
|
|
996 #####################################################################################
|
|
997
|
|
998 =head1 FOR DEVELOPERS ONLY
|
|
999
|
|
1000 =head2 Data Members
|
|
1001
|
|
1002 Information about the various data members of this module is provided for those
|
|
1003 wishing to modify or understand the code. Two things to bear in mind:
|
|
1004
|
|
1005 =over 4
|
|
1006
|
|
1007 =item 1 Do NOT rely on these in any code outside of this module.
|
|
1008
|
|
1009 All data members are prefixed with an underscore to signify that they are private.
|
|
1010 Always use accessor methods. If the accessor doesn't exist or is inadequate,
|
|
1011 create or modify an accessor (and let me know, too!).
|
|
1012
|
|
1013 =item 2 This documentation may be incomplete and out of date.
|
|
1014
|
|
1015 It is easy for this documentation to become obsolete as this module is still evolving.
|
|
1016 Always double check this info and search for members not described here.
|
|
1017
|
|
1018 =back
|
|
1019
|
|
1020 Bio::Root::Vector.pm objects currently cannot be instantiated. Vector.pm must be inherited
|
|
1021 along with Bio::Root::Object.pm (or an object that provides a constructor).
|
|
1022 Vector.pm defines the following fields:
|
|
1023
|
|
1024 FIELD VALUE
|
|
1025 ------------------------------------------------------------------------
|
|
1026 _prev Reference to the previous object in the Vector.
|
|
1027
|
|
1028 _next Reference to the next object in the Vector.
|
|
1029
|
|
1030 _rank Rank relative to other objects in the Vector.
|
|
1031 Default rank = chronological order of addition to the Vector.
|
|
1032
|
|
1033 _master A reference to an Bio::Root::Object that acts as a manager for
|
|
1034 the given Vector. There is only one master per Vector.
|
|
1035 A master object is only needed when the Vector size is >1.
|
|
1036 The master object manages the following Vector data:
|
|
1037
|
|
1038 _first - Reference to the first object in the Vector.
|
|
1039 _last - Reference to the last object in the Vector.
|
|
1040 _size - Total number of objects in the Vector.
|
|
1041 _rankBy - Criteria used to rank the object.
|
|
1042 Default: chronological order of addition.
|
|
1043 _index - Hash reference for quick access to any object
|
|
1044 based on its name.
|
|
1045 Bio::Root::Object{'_err'} - Holds any errors affecting the
|
|
1046 Vector as a whole.
|
|
1047
|
|
1048 =cut
|
|
1049
|
|
1050 1;
|