Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perlmod / Tie / IxHash.pm
CommitLineData
86530b38
AT
1# ========== Copyright Header Begin ==========================================
2#
3# OpenSPARC T2 Processor File: IxHash.pm
4# Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
5# 4150 Network Circle, Santa Clara, California 95054, U.S.A.
6#
7# * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; version 2 of the License.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21#
22# For the avoidance of doubt, and except that if any non-GPL license
23# choice is available it will apply instead, Sun elects to use only
24# the General Public License version 2 (GPLv2) at this time for any
25# software where a choice of GPL license versions is made
26# available with the language indicating that GPLv2 or any later version
27# may be used, or where a choice of which version of the GPL is applied is
28# otherwise unspecified.
29#
30# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
31# CA 95054 USA or visit www.sun.com if you need additional information or
32# have any questions.
33#
34# ========== Copyright Header End ============================================
35require 5.003;
36
37package Tie::IxHash;
38use integer;
39require Tie::Hash;
40@ISA = qw(Tie::Hash);
41
42$VERSION = $VERSION = '1.21';
43
44#
45# standard tie functions
46#
47
48sub TIEHASH {
49 my($c) = shift;
50 my($s) = [];
51 $s->[0] = {}; # hashkey index
52 $s->[1] = []; # array of keys
53 $s->[2] = []; # array of data
54 $s->[3] = 0; # iter count
55
56 bless $s, $c;
57
58 $s->Push(@_) if @_;
59
60 return $s;
61}
62
63#sub DESTROY {} # costly if there's nothing to do
64
65sub FETCH {
66 my($s, $k) = (shift, shift);
67 return exists( $s->[0]{$k} ) ? $s->[2][ $s->[0]{$k} ] : undef;
68}
69
70sub STORE {
71 my($s, $k, $v) = (shift, shift, shift);
72
73 if (exists $s->[0]{$k}) {
74 my($i) = $s->[0]{$k};
75 $s->[1][$i] = $k;
76 $s->[2][$i] = $v;
77 $s->[0]{$k} = $i;
78 }
79 else {
80 push(@{$s->[1]}, $k);
81 push(@{$s->[2]}, $v);
82 $s->[0]{$k} = $#{$s->[1]};
83 }
84}
85
86sub DELETE {
87 my($s, $k) = (shift, shift);
88
89 if (exists $s->[0]{$k}) {
90 my($i) = $s->[0]{$k};
91 for ($i+1..$#{$s->[1]}) { # reset higher elt indexes
92 $s->[0]{$s->[1][$_]}--; # timeconsuming, is there is better way?
93 }
94 delete $s->[0]{$k};
95 splice @{$s->[1]}, $i, 1;
96 return (splice(@{$s->[2]}, $i, 1))[0];
97 }
98 return undef;
99}
100
101sub EXISTS {
102 exists $_[0]->[0]{ $_[1] };
103}
104
105sub FIRSTKEY {
106 $_[0][3] = 0;
107 &NEXTKEY;
108}
109
110sub NEXTKEY {
111 return $_[0][1][$_[0][3]++] if ($_[0][3] <= $#{$_[0][1]});
112 return undef;
113}
114
115
116
117#
118#
119# class functions that provide additional capabilities
120#
121#
122
123sub new { TIEHASH(@_) }
124
125#
126# add pairs to end of indexed hash
127# note that if a supplied key exists, it will not be reordered
128#
129sub Push {
130 my($s) = shift;
131 while (@_) {
132 $s->STORE(shift, shift);
133 }
134 return scalar(@{$s->[1]});
135}
136
137sub Push2 {
138 my($s) = shift;
139 $s->Splice($#{$s->[1]}+1, 0, @_);
140 return scalar(@{$s->[1]});
141}
142
143#
144# pop last k-v pair
145#
146sub Pop {
147 my($s) = shift;
148 my($k, $v, $i);
149 $k = pop(@{$s->[1]});
150 $v = pop(@{$s->[2]});
151 if (defined $k) {
152 delete $s->[0]{$k};
153 return ($k, $v);
154 }
155 return undef;
156}
157
158sub Pop2 {
159 return $_[0]->Splice(-1);
160}
161
162#
163# shift
164#
165sub Shift {
166 my($s) = shift;
167 my($k, $v, $i);
168 $k = shift(@{$s->[1]});
169 $v = shift(@{$s->[2]});
170 if (defined $k) {
171 delete $s->[0]{$k};
172 for (keys %{$s->[0]}) {
173 $s->[0]{$_}--;
174 }
175 return ($k, $v);
176 }
177 return undef;
178}
179
180sub Shift2 {
181 return $_[0]->Splice(0, 1);
182}
183
184#
185# unshift
186# if a supplied key exists, it will not be reordered
187#
188sub Unshift {
189 my($s) = shift;
190 my($k, $v, @k, @v, $len, $i);
191
192 while (@_) {
193 ($k, $v) = (shift, shift);
194 if (exists $s->[0]{$k}) {
195 $i = $s->[0]{$k};
196 $s->[1][$i] = $k;
197 $s->[2][$i] = $v;
198 $s->[0]{$k} = $i;
199 }
200 else {
201 push(@k, $k);
202 push(@v, $v);
203 $len++;
204 }
205 }
206 if (defined $len) {
207 for (keys %{$s->[0]}) {
208 $s->[0]{$_} += $len;
209 }
210 $i = 0;
211 for (@k) {
212 $s->[0]{$_} = $i++;
213 }
214 unshift(@{$s->[1]}, @k);
215 return unshift(@{$s->[2]}, @v);
216 }
217 return scalar(@{$s->[1]});
218}
219
220sub Unshift2 {
221 my($s) = shift;
222 $s->Splice(0,0,@_);
223 return scalar(@{$s->[1]});
224}
225
226#
227# splice
228#
229# any existing hash key order is preserved. the value is replaced for
230# such keys, and the new keys are spliced in the regular fashion.
231#
232# supports -ve offsets but only +ve lengths
233#
234# always assumes a 0 start offset
235#
236sub Splice {
237 my($s, $start, $len) = (shift, shift, shift);
238 my($k, $v, @k, @v, @r, $i, $siz);
239 my($end); # inclusive
240
241 # XXX inline this
242 ($start, $end, $len) = $s->_lrange($start, $len);
243
244 if (defined $start) {
245 if ($len > 0) {
246 my(@k) = splice(@{$s->[1]}, $start, $len);
247 my(@v) = splice(@{$s->[2]}, $start, $len);
248 while (@k) {
249 $k = shift(@k);
250 delete $s->[0]{$k};
251 push(@r, $k, shift(@v));
252 }
253 for ($start..$#{$s->[1]}) {
254 $s->[0]{$s->[1][$_]} -= $len;
255 }
256 }
257 while (@_) {
258 ($k, $v) = (shift, shift);
259 if (exists $s->[0]{$k}) {
260 # $s->STORE($k, $v);
261 $i = $s->[0]{$k};
262 $s->[1][$i] = $k;
263 $s->[2][$i] = $v;
264 $s->[0]{$k} = $i;
265 }
266 else {
267 push(@k, $k);
268 push(@v, $v);
269 $siz++;
270 }
271 }
272 if (defined $siz) {
273 for ($start..$#{$s->[1]}) {
274 $s->[0]{$s->[1][$_]} += $siz;
275 }
276 $i = $start;
277 for (@k) {
278 $s->[0]{$_} = $i++;
279 }
280 splice(@{$s->[1]}, $start, 0, @k);
281 splice(@{$s->[2]}, $start, 0, @v);
282 }
283 }
284 return @r;
285}
286
287#
288# delete elements specified by key
289# other elements higher than the one deleted "slide" down
290#
291sub Delete {
292 my($s) = shift;
293
294 for (@_) {
295 #
296 # XXX potential optimization: could do $s->DELETE only if $#_ < 4.
297 # otherwise, should reset all the hash indices in one loop
298 #
299 $s->DELETE($_);
300 }
301}
302
303#
304# replace hash element at specified index
305#
306# if the optional key is not supplied the value at index will simply be
307# replaced without affecting the order.
308#
309# if an element with the supplied key already exists, it will be deleted first.
310#
311# returns the key of replaced value if it succeeds.
312#
313sub Replace {
314 my($s) = shift;
315 my($i, $v, $k) = (shift, shift, shift);
316 if (defined $i and $i <= $#{$s->[1]} and $i >= 0) {
317 if (defined $k) {
318 delete $s->[0]{ $s->[1][$i] };
319 $s->DELETE($k) ; #if exists $s->[0]{$k};
320 $s->[1][$i] = $k;
321 $s->[2][$i] = $v;
322 $s->[0]{$k} = $i;
323 return $k;
324 }
325 else {
326 $s->[2][$i] = $v;
327 return $s->[1][$i];
328 }
329 }
330 return undef;
331}
332
333#
334# Given an $start and $len, returns a legal start and end (where start <= end)
335# for the current hash.
336# Legal range is defined as 0 to $#s+1
337# $len defaults to number of elts upto end of list
338#
339# 0 1 2 ...
340# | X | X | X ... X | X | X |
341# -2 -1 (no -0 alas)
342# X's above are the elements
343#
344sub _lrange {
345 my($s) = shift;
346 my($offset, $len) = @_;
347 my($start, $end); # both inclusive
348 my($size) = $#{$s->[1]}+1;
349
350 return undef unless defined $offset;
351 if($offset < 0) {
352 $start = $offset + $size;
353 $start = 0 if $start < 0;
354 }
355 else {
356 ($offset > $size) ? ($start = $size) : ($start = $offset);
357 }
358
359 if (defined $len) {
360 $len = -$len if $len < 0;
361 $len = $size - $start if $len > $size - $start;
362 }
363 else {
364 $len = $size - $start;
365 }
366 $end = $start + $len - 1;
367
368 return ($start, $end, $len);
369}
370
371#
372# Return keys at supplied indices
373# Returns all keys if no args.
374#
375sub Keys {
376 my($s) = shift;
377 return ( @_ == 1
378 ? $s->[1][$_[0]]
379 : ( @_
380 ? @{$s->[1]}[@_]
381 : @{$s->[1]} ) );
382}
383
384#
385# Returns values at supplied indices
386# Returns all values if no args.
387#
388sub Values {
389 my($s) = shift;
390 return ( @_ == 1
391 ? $s->[2][$_[0]]
392 : ( @_
393 ? @{$s->[2]}[@_]
394 : @{$s->[2]} ) );
395}
396
397#
398# get indices of specified hash keys
399#
400sub Indices {
401 my($s) = shift;
402 return ( @_ == 1 ? $s->[0]{$_[0]} : @{$s->[0]}{@_} );
403}
404
405#
406# number of k-v pairs in the ixhash
407# note that this does not equal the highest index
408# owing to preextended arrays
409#
410sub Length {
411 return scalar @{$_[0]->[1]};
412}
413
414#
415# Reorder the hash in the supplied key order
416#
417# warning: any unsupplied keys will be lost from the hash
418# any supplied keys that dont exist in the hash will be ignored
419#
420sub Reorder {
421 my($s) = shift;
422 my(@k, @v, %x, $i);
423 return unless @_;
424
425 $i = 0;
426 for (@_) {
427 if (exists $s->[0]{$_}) {
428 push(@k, $_);
429 push(@v, $s->[2][ $s->[0]{$_} ] );
430 $x{$_} = $i++;
431 }
432 }
433 $s->[1] = \@k;
434 $s->[2] = \@v;
435 $s->[0] = \%x;
436 return $s;
437}
438
439sub SortByKey {
440 my($s) = shift;
441 $s->Reorder(sort $s->Keys);
442}
443
444sub SortByValue {
445 my($s) = shift;
446 $s->Reorder(sort { $s->FETCH($a) cmp $s->FETCH($b) } $s->Keys)
447}
448
4491;
450__END__
451
452=head1 NAME
453
454Tie::IxHash - ordered associative arrays for Perl
455
456
457=head1 SYNOPSIS
458
459 # simple usage
460 use Tie::IxHash;
461 tie HASHVARIABLE, Tie::IxHash [, LIST];
462
463 # OO interface with more powerful features
464 use Tie::IxHash;
465 TIEOBJECT = Tie::IxHash->new( [LIST] );
466 TIEOBJECT->Splice( OFFSET [, LENGTH [, LIST]] );
467 TIEOBJECT->Push( LIST );
468 TIEOBJECT->Pop;
469 TIEOBJECT->Shift;
470 TIEOBJECT->Unshift( LIST );
471 TIEOBJECT->Keys( [LIST] );
472 TIEOBJECT->Values( [LIST] );
473 TIEOBJECT->Indices( LIST );
474 TIEOBJECT->Delete( [LIST] );
475 TIEOBJECT->Replace( OFFSET, VALUE, [KEY] );
476 TIEOBJECT->Reorder( LIST );
477 TIEOBJECT->SortByKey;
478 TIEOBJECT->SortByValue;
479 TIEOBJECT->Length;
480
481
482=head1 DESCRIPTION
483
484This Perl module implements Perl hashes that preserve the order in which the
485hash elements were added. The order is not affected when values
486corresponding to existing keys in the IxHash are changed. The elements can
487also be set to any arbitrary supplied order. The familiar perl array
488operations can also be performed on the IxHash.
489
490
491=head2 Standard C<TIEHASH> Interface
492
493The standard C<TIEHASH> mechanism is available. This interface is
494recommended for simple uses, since the usage is exactly the same as
495regular Perl hashes after the C<tie> is declared.
496
497
498=head2 Object Interface
499
500This module also provides an extended object-oriented interface that can be
501used for more powerful operations with the IxHash. The following methods
502are available:
503
504=over 8
505
506=item FETCH, STORE, DELETE, EXISTS
507
508These standard C<TIEHASH> methods mandated by Perl can be used directly.
509See the C<tie> entry in perlfunc(1) for details.
510
511=item Push, Pop, Shift, Unshift, Splice
512
513These additional methods resembling Perl functions are available for
514operating on key-value pairs in the IxHash. The behavior is the same as the
515corresponding perl functions, except when a supplied hash key already exists
516in the hash. In that case, the existing value is updated but its order is
517not affected. To unconditionally alter the order of a supplied key-value
518pair, first C<DELETE> the IxHash element.
519
520=item Keys
521
522Returns an array of IxHash element keys corresponding to the list of supplied
523indices. Returns an array of all the keys if called without arguments.
524Note the return value is mostly only useful when used in a list context
525(since perl will convert it to the number of elements in the array when
526used in a scalar context, and that may not be very useful).
527
528If a single argument is given, returns the single key corresponding to
529the index. This is usable in either scalar or list context.
530
531=item Values
532
533Returns an array of IxHash element values corresponding to the list of supplied
534indices. Returns an array of all the values if called without arguments.
535Note the return value is mostly only useful when used in a list context
536(since perl will convert it to the number of elements in the array when
537used in a scalar context, and that may not be very useful).
538
539If a single argument is given, returns the single value corresponding to
540the index. This is usable in either scalar or list context.
541
542=item Indices
543
544Returns an array of indices corresponding to the supplied list of keys.
545Note the return value is mostly only useful when used in a list context
546(since perl will convert it to the number of elements in the array when
547used in a scalar context, and that may not be very useful).
548
549If a single argument is given, returns the single index corresponding to
550the key. This is usable in either scalar or list context.
551
552=item Delete
553
554Removes elements with the supplied keys from the IxHash.
555
556=item Replace
557
558Substitutes the IxHash element at the specified index with the supplied
559value-key pair. If a key is not supplied, simply substitutes the value at
560index with the supplied value. If an element with the supplied key already
561exists, it will be removed from the IxHash first.
562
563=item Reorder
564
565This method can be used to manipulate the internal order of the IxHash
566elements by supplying a list of keys in the desired order. Note however,
567that any IxHash elements whose keys are not in the list will be removed from
568the IxHash.
569
570=item Length
571
572Returns the number of IxHash elements.
573
574=item SortByKey
575
576Reorders the IxHash elements by textual comparison of the keys.
577
578=item SortByValue
579
580Reorders the IxHash elements by textual comparison of the values.
581
582=back
583
584
585=head1 EXAMPLE
586
587 use Tie::IxHash;
588
589 # simple interface
590 $t = tie(%myhash, Tie::IxHash, 'a' => 1, 'b' => 2);
591 %myhash = (first => 1, second => 2, third => 3);
592 $myhash{fourth} = 4;
593 @keys = keys %myhash;
594 @values = values %myhash;
595 print("y") if exists $myhash{third};
596
597 # OO interface
598 $t = Tie::IxHash->new(first => 1, second => 2, third => 3);
599 $t->Push(fourth => 4); # same as $myhash{'fourth'} = 4;
600 ($k, $v) = $t->Pop; # $k is 'fourth', $v is 4
601 $t->Unshift(neg => -1, zeroth => 0);
602 ($k, $v) = $t->Shift; # $k is 'neg', $v is -1
603 @oneandtwo = $t->Splice(1, 2, foo => 100, bar => 101);
604
605 @keys = $t->Keys;
606 @values = $t->Values;
607 @indices = $t->Indices('foo', 'zeroth');
608 @itemkeys = $t->Keys(@indices);
609 @itemvals = $t->Values(@indices);
610 $t->Replace(2, 0.3, 'other');
611 $t->Delete('second', 'zeroth');
612 $len = $t->Length; # number of key-value pairs
613
614 $t->Reorder(reverse @keys);
615 $t->SortByKey;
616 $t->SortByValue;
617
618
619=head1 BUGS
620
621You cannot specify a negative length to C<Splice>. Negative indexes are OK,
622though.
623
624Indexing always begins at 0 (despite the current C<$[> setting) for
625all the functions.
626
627
628=head1 TODO
629
630Addition of elements with keys that already exist to the end of the IxHash
631must be controlled by a switch.
632
633Provide C<TIEARRAY> interface when it stabilizes in Perl.
634
635Rewrite using XSUBs for efficiency.
636
637
638=head1 AUTHOR
639
640Gurusamy Sarathy gsar@umich.edu
641
642Copyright (c) 1995 Gurusamy Sarathy. All rights reserved.
643This program is free software; you can redistribute it and/or
644modify it under the same terms as Perl itself.
645
646
647=head1 VERSION
648
649Version 1.21 20 Nov 1997
650
651
652=head1 SEE ALSO
653
654perl(1)
655
656=cut