File Coverage

blib/lib/Set/Scalar/Base.pm
Criterion Covered Total %
statement 357 391 91.3
branch 118 160 73.7
condition 39 51 76.4
subroutine 72 78 92.3
pod 0 35 0.0
total 586 715 81.9


line stmt bran cond sub pod time code
1             package Set::Scalar::Base;
2              
3 22     22   158 use strict;
  22         37  
  22         987  
4             # local $^W = 1;
5              
6             require Exporter;
7              
8 22     22   108 use vars qw($VERSION @ISA @EXPORT_OK);
  22         36  
  22         7781  
9              
10             $VERSION = '1.29';
11             @ISA = qw(Exporter);
12              
13             BEGIN {
14 22     22   1393 eval 'require Scalar::Util';
15 22 50       131 unless ($@) {
16 22         9287 import Scalar::Util qw(blessed refaddr);
17             } else {
18             # Use the pure Perl emulations (directly snagged from Scalar::Util).
19 0         0 eval 'sub UNIVERSAL::a_sub_not_likely_to_be_here { ref($_[0]) }';
20             *blessed = sub ($) {
21 0         0 local($@, $SIG{__DIE__}, $SIG{__WARN__});
22             length(ref($_[0]))
23 0 0       0 ? eval { $_[0]->a_sub_not_likely_to_be_here }
  0         0  
24             : undef
25 0         0 };
26             *refaddr = sub ($) {
27 0 0       0 my $pkg = ref($_[0]) or return undef;
28 0 0       0 if (blessed($_[0])) {
29 0         0 bless $_[0], 'Scalar::Util::Fake';
30             }
31             else {
32 0         0 $pkg = undef;
33             }
34 0         0 "$_[0]" =~ /0x(\w+)/;
35 0         0 my $i = do { local $^W; hex $1 };
  0         0  
  0         0  
36 0 0       0 bless $_[0], $pkg if defined $pkg;
37 0         0 $i;
38 0         0 };
39             }
40             }
41              
42             @EXPORT_OK = qw(_make_elements
43             as_string
44             as_string_callback
45             _compare is_equal
46             _binary_underload
47             _unary_underload
48             _strval);
49              
50             use overload
51             '+' => \&_union_overload,
52             '*' => \&_intersection_overload,
53             '-' => \&_difference_overload,
54             'neg' => \&_complement_overload,
55             '%' => \&_symmetric_difference_overload,
56             '/' => \&_unique_overload,
57             'eq' => \&is_equal,
58             '==' => \&is_equal,
59             '!=' => \&is_disjoint,
60             '<=>' => \&compare,
61             '<' => \&is_proper_subset,
62             '>' => \&is_proper_superset,
63             '<=' => \&is_subset,
64             '>=' => \&is_superset,
65             'bool' => \&size,
66 8     8   113 '@{}' => sub { [ $_[0]->members ] },
67 1     1   19 '=' => sub { $_[0]->clone($_[1]) },
68 22     22   52380 'cmp' => sub { "$_[0]" cmp "$_[1]" };
  22     0   30405  
  22         521  
  0         0  
69              
70 22     22   5153 use constant OVERLOAD_BINARY_2ND_ARG => 1;
  22         54  
  22         2592  
71 22     22   115 use constant OVERLOAD_BINARY_REVERSED => 2;
  22         46  
  22         90730  
72              
73             sub _binary_underload { # Handle overloaded binary operators.
74 4792     4792   5794 my (@args) = @{ $_[0] };
  4792         16682  
75              
76 4792 50       13324 if (@args == 3) {
77 4792 100       12021 $args[1] = (ref $args[0])->new( $args[1] ) unless ref $args[1];
78 4792 100       13051 @args[0, 1] = @args[1, 0] if $args[OVERLOAD_BINARY_REVERSED];
79 4792         7574 pop @args;
80             }
81              
82 4792         16777 return @args;
83             }
84              
85             sub _unary_underload { # Handle overloaded unary operators.
86 775 50   775   1218 if (@{ $_[0] } == 3) {
  775         5600  
87 775         915 pop @{ $_[0] };
  775         1327  
88 775         878 pop @{ $_[0] };
  775         1540  
89             }
90             }
91              
92 1     1   1 sub _new_hook {
93             # Just an empty stub.
94             }
95              
96             sub new {
97 7435     7435 0 12475 my $class = shift;
98              
99 7435         12696 my $self = { };
100              
101 7435   33     47546 bless $self, ref $class || $class;
102              
103 7435         32864 $self->_new_hook( \@_ );
104              
105 7435         26059 return $self;
106             }
107              
108             sub _strval {
109 66989     66989   95221 my $class = ref $_[0];
110 66989 100       283433 return $_[0] unless $class;
111 18291         112376 sprintf "%s(%s)", $class, refaddr $_[0];
112             }
113              
114             sub _make_elements {
115 20463 50   20463   48034 return map { (defined $_ ? _strval($_) : "") => $_ } @_;
  48485         132195  
116             }
117              
118             sub _invalidate_cached {
119 34531     34531   66787 my $self = shift;
120              
121 34531         42035 delete @{ $self }{ "as_string" };
  34531         131614  
122             }
123              
124 706     706   1611 sub _insert_hook {
125             # Just an empty stub.
126             }
127              
128             sub _insert {
129 13376     13376   19319 my $self = shift;
130 13376         16707 my $elements = shift;
131              
132 13376         34588 $self->_insert_hook( $elements );
133             }
134              
135             sub _insert_elements {
136 25364     25364   32490 my $self = shift;
137 25364         29297 my $elements = shift;
138              
139 25364         56421 @{ $self->{'elements'} }{ keys %$elements } = values %$elements;
  25364         83558  
140              
141 25364         63061 $self->_invalidate_cached;
142             }
143              
144             sub universe {
145 32955     32955 0 44719 my $self = shift;
146              
147 32955         106945 return $self->{'universe'};
148             }
149              
150             sub size {
151 34970     34970 0 45166 my $self = shift;
152              
153 34970         41194 return scalar keys %{ $self->{'elements'} };
  34970         157658  
154             }
155              
156             sub elements {
157 13167     13167 0 16066 my $self = shift;
158              
159 3         51 return @_ ?
160 3         20 @{ $self->{'elements'} }{ map { _strval($_) } @_ } :
  13164         62025  
161 13167 100       38572 values %{ $self->{'elements'} };
162             }
163              
164             *members = \&elements;
165              
166             sub element {
167 3     3 0 23 my $self = shift;
168              
169 3         12 $self->elements( shift );
170             }
171              
172             *member = \&element;
173              
174             sub has {
175 3     3 0 24 my $self = shift;
176              
177 3         16 my @has = map { exists $self->{'elements'}->{ $_ } } @_;
  3         16  
178              
179 3 50       17 return wantarray ? @has : @_ > 1 ? grep { $_ } @has : $has[0];
  0 50       0  
180             }
181              
182             *contains = \&has;
183              
184             sub each {
185 7     7 0 43 my $self = shift;
186              
187 7         8 my ($k, $e) = each %{ $self->{'elements'} };
  7         21  
188              
189 7         20 return $e;
190             }
191              
192             sub _empty_clone {
193 6016     6016   7526 my $self = shift;
194 6016         6907 my $original = shift;
195              
196 6016         10741 $self->{'universe'} = $original->{'universe'};
197 6016         13840 $self->{'null' } = $original->{'null' };
198             }
199              
200             sub _clone {
201 5990     5990   8369 my $self = shift;
202 5990         6820 my $original = shift;
203              
204 5990         10933 $self->_empty_clone($original);
205              
206 5990         18065 $self->_insert( $original->{'elements'} );
207             }
208              
209             sub clone {
210 5990     5990 0 7422 my $self = shift;
211 5990         38936 my $clone = (ref $self)->new;
212              
213 5990         14962 $clone->_clone( $self );
214              
215 5990         13293 return $clone;
216             }
217              
218             *copy = \&clone;
219              
220             sub empty_clone {
221 26     26 0 29 my $self = shift;
222 26         62 my $clone = (ref $self)->new;
223              
224 26         56 $clone->_empty_clone( $self );
225              
226 26         66 return $clone;
227             }
228              
229             sub clear {
230 4     4 0 3 my $self = shift;
231              
232 4         3 undef %{ $self };
  4         10  
233 4         5 undef @{ $self }{ "as_string" };
  4         13  
234             }
235              
236             sub _union ($$) {
237 2388     2388   3799 my ($this, $that) = @_;
238              
239 2388         5288 my $this_universe = $this->universe;
240              
241 2388 50       5904 return (undef, 1, undef)
242             unless $this_universe == $that->universe;
243              
244 2388 100       6551 return ($this->clone, 0, ref $this)
245             if $that->is_null;
246              
247 1768 100       6488 return ($that->clone, 0, ref $that)
248             if $this->is_null;
249              
250 1455 100       3451 return ($this, 1, ref $this)
251             if $this->is_universal;
252              
253 1106 100       2647 return ($that, 1, ref $that)
254             if $that->is_universal;
255              
256 833         2688 my $union = $this->clone;
257              
258 833         1809 $union->insert( $that->elements );
259              
260 833         1935 return ($union, $union->is_universal, ref $this);
261             }
262              
263             sub _union_overload {
264 2383     2383   7325 my ($this, $that) = _binary_underload( \@_ );
265              
266 2383         6258 my ($union, $is_universal, $class) = $this->_union( $that );
267              
268 2383         11288 return $union;
269             }
270              
271             sub union {
272 9     9 0 41 my $self = shift;
273              
274 9         35 my $union = $self->clone;
275              
276 9         13 my $is_universal;
277             my $class;
278              
279 9         23 foreach my $next ( @_ ) {
280 5 50       21 unless ($next->is_null) {
281 5         22 ($union, $is_universal, $class) = $union->_union( $next );
282              
283 5 100       26 last if $is_universal;
284             }
285             }
286              
287 9 100 100     33 $union = $self
288             if $is_universal && $union->size == $self->size;
289              
290 9         45 return $union;
291             }
292              
293             sub _intersection ($$) {
294 4152     4152   5778 my $this = shift;
295 4152         4768 my $that = shift;
296              
297 4152 50       9160 return (undef, 1)
298             unless $this->universe == $that->universe;
299              
300 4152 100 100     12308 return ($this->null, 1)
301             if $this->is_null || $that->is_null;
302              
303 2597 100       6797 return ($this->clone, 0)
304             if $that->is_universal;
305              
306 2134 100       5501 return ($that->clone, 0)
307             if $this->is_universal;
308              
309 1938         5112 my $intersection = $this->clone;
310              
311 1938         5555 my %intersection = _make_elements $intersection->elements;
312              
313 1938         3426 delete @intersection{ keys %{{ _make_elements $that->elements }} };
  1938         3909  
314              
315 1938         10279 $intersection->delete( values %intersection );
316              
317 1938         4998 return ($intersection, $intersection->is_null);
318             }
319              
320             sub _intersection_overload {
321 2381     2381   6164 my ($this, $that) = _binary_underload( \@_ );
322              
323 2381         7166 my ($intersection) = $this->_intersection( $that );
324              
325 2381         14786 return $intersection;
326             }
327              
328             sub intersection {
329 1962     1962 0 2596 my $self = shift;
330              
331 1962         8691 my $intersection = $self->clone;
332              
333 1962         2455 my $is_null;
334              
335 1962         3854 foreach my $next ( @_ ) {
336 1962 100       3902 unless ($next->is_universal) {
337 1771         4346 ($intersection, $is_null) = $intersection->_intersection( $next );
338              
339 1771 100       6370 last if $is_null;
340             }
341             }
342              
343 1962 100 100     6979 $intersection = $self
344             if $is_null && $intersection->size == $self->size;
345              
346 1962         4040 return $intersection;
347             }
348              
349             sub _difference ($$) {
350 12     12   15 my $this = shift;
351 12         14 my $that = shift;
352              
353 12 50       23 return undef unless $this->universe == $that->universe;
354              
355 12 100 100     33 return $this->null if $this->is_null || $that->is_universal;
356 10 50       27 return $this->clone if $that->is_null;
357              
358 10         24 my $difference = $this->clone;
359              
360 10         31 my %that = _make_elements $that->elements;
361              
362 10         59 $difference->delete( values %that );
363              
364 10         48 return $difference;
365             }
366              
367             sub _difference_overload {
368 8     8   31 my ($this, $that) = _binary_underload( \@_ );
369              
370 8         24 return $this->_difference( $that );
371             }
372              
373             sub difference {
374 4     4 0 25 my $this = shift;
375              
376 4 50       13 return $this->null if $this->is_null;
377              
378 4 50       23 return $this->clone unless @_;
379              
380 4         6 my $that = shift;
381              
382 4         16 $that = $that->union( @_ );
383              
384 4 50       13 return undef unless defined $that;
385              
386 4 50       13 return $this->null if $that->is_universal;
387              
388 4         23 my $difference = $this->_difference( $that );
389              
390 4 100       19 $difference = $this
391             if $difference->size == $this->size;
392              
393 4         15 return $difference;
394             }
395              
396             sub _symmetric_difference ($$) {
397 7     7   9 my $this = shift;
398 7         9 my $that = shift;
399              
400 7 50       14 return (undef, 1) unless $this->universe == $that->universe;
401              
402 7 50       25 return $that->clone if $this->is_null;
403 7 50       18 return $this->clone if $that->is_null;
404              
405 7 50       23 return $that->complement if $this->is_universal;
406 7 50       17 return $this->complement if $that->is_universal;
407              
408 7         18 my $symmetric_difference = $this->clone;
409              
410 7         17 $symmetric_difference->invert( $that->elements );
411              
412 7         36 return $symmetric_difference;
413             }
414              
415             sub _symmetric_difference_overload {
416 7     7   53 my ($this, $that ) = _binary_underload( \@_ );
417              
418 7         23 return $this->_symmetric_difference( $that );
419             }
420              
421             sub symmetric_difference {
422 2     2 0 18 my $this = shift;
423              
424 2         10 my $symmetric_difference = $this->clone;
425              
426 2         5 foreach my $next ( @_ ) {
427 2         10 $symmetric_difference->invert( $next->elements );
428             }
429              
430 2         6 return $symmetric_difference;
431             }
432              
433             *symmdiff = \&symmetric_difference;
434              
435             sub _complement {
436 775     775   972 my $self = shift;
437 775         1814 my $complement = (ref $self)->new( $self->universe->elements );
438              
439 775         2685 $complement->delete( $self->elements );
440              
441 775         4180 return $complement;
442             }
443              
444             sub _complement_overload {
445 775     775   2990 _unary_underload( \@_ );
446              
447 775         1147 my $self = shift;
448              
449 775         1943 return $self->_complement;
450             }
451              
452             sub complement {
453 0     0 0 0 my $self = shift;
454              
455 0         0 return $self->_complement;
456             }
457              
458             sub _unique {
459 4     4   14 my $universe = $_[0]->universe;
460 4         6 my %frequency;
461              
462 4         7 for my $set ( @_ ) {
463 8 50       83 if ($set->universe == $universe) {
464 8         10 foreach my $element ( keys %{ $set->{'elements'} } ) {
  8         24  
465 35         58 $frequency{ $element }++;
466             }
467             } else {
468 0         0 return (ref $_[0])->new();
469             }
470             }
471              
472 4         11 return (ref $_[0])->new(grep { $frequency{ $_ } == 1 } keys %frequency);
  24         41  
473             }
474              
475             sub _unique_overload {
476 0     0   0 my ($this, $that) = _binary_underload( \@_ );
477              
478 0         0 return $this->_unique( $that );
479             }
480              
481             sub unique {
482 4     4 0 26 my $this = shift;
483              
484 4         15 return $this->_unique( @_ );
485             }
486              
487             sub _make_cartesian_product_iterator {
488 6     6   6 my @iter;
489             my @value;
490 6         13 for my $set (@_) {
491 12 50       99 return unless $set->isa('Set::Scalar');
492 12         30 my @member = $set->members;
493 12         18 my %member;
494 12         51 @member{@member} = @member;
495 12         21 push @iter, \%member;
496 12         13 push @value, scalar CORE::each(%{ $iter[-1] });
  12         48  
497             }
498             return sub {
499 54 100   54   138 return unless @iter;
500 48         110 my @now = @value;
501 48         53 my $ix;
502 48         178 for ($ix = $#iter; $ix >= 0; $ix--) {
503 64         60 my $next = CORE::each(%{ $iter[$ix] });
  64         115  
504 64 100       124 if (defined $next) {
505 42         53 $value[$ix] = $next;
506 42         59 last;
507             } else {
508 22         22 keys %{ $iter[$ix] }; # Reset the iterator.
  22         32  
509 22         20 $value[$ix] = CORE::each(%{ $iter[$ix] });
  22         79  
510             }
511             }
512 48 100       98 if ($ix < 0) {
513 6         19 @iter = (); # All done.
514             }
515 48         187 return @now;
516 6         30 };
517             }
518              
519             sub cartesian_product_iterator {
520 6 100   6 0 16 shift unless ref $_[0];
521 6         25 return &_make_cartesian_product_iterator;
522             }
523              
524             sub cartesian_product {
525 6     6 0 33 my $iterator = &cartesian_product_iterator;
526 6 50       16 return unless defined $iterator;
527 6         23 my $product = $_[0]->empty_clone;
528 6         11 while (my @member = $iterator->()) {
529 48         149 $product->insert(\@member);
530             }
531 6         54 return $product;
532             }
533              
534             sub _make_power_set_iterator {
535 3 50   3   18 return unless $_[0]->isa('Set::Scalar');
536 3         18 my @member = $_[0]->members;
537 3         7 my @iter = (0) x @member;
538             return sub {
539 17 100   17   35 return unless @iter;
540 16         14 my $ix;
541 16         35 for ($ix = 0; $ix < @iter; $ix++) {
542 28 100       44 if ($iter[$ix]++ == 0) {
543 14         17 last;
544             } else {
545 14         29 $iter[$ix] = 0;
546             }
547             }
548 16 100       29 if ($ix == @iter) {
549 2         3 @iter = (); # All done.
550             }
551 16         27 return map { $member[$_] } grep { $iter[$_] } 0..$#iter;
  24         47  
  42         52  
552 3         13 };
553             }
554              
555             sub power_set_iterator {
556 3 100   3 0 7 shift unless ref $_[0];
557 3         10 return &_make_power_set_iterator;
558             }
559              
560             sub power_set {
561 3     3 0 18 my $iterator = &power_set_iterator;
562 3 50       8 return unless defined $iterator;
563 3         9 my $power = $_[0]->empty_clone;
564 3         3 my @member;
565 3         4 do {
566 17         25 @member = $iterator->();
567 17         36 $power->insert($_[0]->empty_clone->insert(@member));
568             } while (@member);
569 3         20 return $power;
570             }
571              
572             sub is_universal {
573 10131     10131 0 15197 my $self = shift;
574              
575 10131         19023 return $self->size == $self->universe->size;
576             }
577              
578             sub is_null {
579 13306     13306 0 19218 my $self = shift;
580              
581 13306         32678 return $self->size == 0;
582             }
583              
584             *is_empty = \&is_null;
585              
586             sub null {
587 1457     1457 0 1981 my $self = shift;
588              
589 1457         3771 return $self->universe->null;
590             }
591              
592             *empty = \&null;
593              
594             sub _compare {
595 9120     9120   13480 my $a = shift;
596 9120         10586 my $b = shift;
597              
598 9120 100       64993 return "$a" eq "$b" ? 'equal' : 'different';
599             }
600              
601             sub compare {
602 2081     2081 0 2937 my $a = shift;
603 2081         3443 my $b = shift;
604              
605 2081 100 33     29221 return _compare("$a", "$b")
      66        
      66        
606             unless ref $a && $a->isa(__PACKAGE__) &&
607             ref $b && $b->isa(__PACKAGE__);
608              
609 1957 50       5235 return 'disjoint universes' unless $a->universe == $b->universe;
610              
611 1957         6808 my $c = $a->intersection($b);
612              
613 1957         5153 my $na = $a->size;
614 1957         16584 my $nb = $b->size;
615 1957         4484 my $nc = $c->size;
616              
617 1957 100 100     17957 return 'proper superset' if $na && $nb == 0;
618 1954 100 100     6908 return 'proper subset' if $na == 0 && $nb;
619 1953 100 66     12529 return 'disjoint' if $na && $nb && $nc == 0;
      100        
620 1949 100 100     13182 return 'equal' if $na == $nc && $nb == $nc;
621 6 100       22 return 'proper superset' if $nb == $nc;
622 3 100       11 return 'proper subset' if $na == $nc;
623 1         4 return 'proper intersect';
624             }
625              
626             sub is_disjoint {
627 2     2 0 20 my $a = shift;
628 2         4 my $b = shift;
629              
630 2   33     6 return $a->compare($b) eq 'disjoint' ||
631             $a->compare($b) eq 'disjoint universes';
632             }
633              
634             sub is_equal {
635 2065     2065 0 292150 my $a = shift;
636 2065         2852 my $b = shift;
637              
638 2065         5550 return $a->compare($b) eq 'equal';
639             }
640              
641             sub is_proper_subset {
642 3     3 0 19 my $a = shift;
643 3         5 my $b = shift;
644              
645 3         6 return $a->compare($b) eq 'proper subset';
646             }
647              
648             sub is_proper_superset {
649 3     3 0 23 my $a = shift;
650 3         4 my $b = shift;
651              
652 3         16 return $a->compare($b) eq 'proper superset';
653             }
654              
655             sub is_properly_intersecting {
656 0     0 0 0 my $a = shift;
657 0         0 my $b = shift;
658              
659 0         0 return $a->compare($b) eq 'proper intersect';
660             }
661              
662             sub is_subset {
663 3     3 0 21 my $a = shift;
664 3         4 my $b = shift;
665              
666 3         10 my $c = $a->compare($b);
667              
668 3   66     18 return $c eq 'equal' || $c eq 'proper subset';
669             }
670              
671             sub is_superset {
672 3     3 0 19 my $a = shift;
673 3         5 my $b = shift;
674              
675 3         12 my $c = $a->compare($b);
676              
677 3   66     21 return $c eq 'equal' || $c eq 'proper superset';
678             }
679              
680             sub cmp {
681 0     0 0 0 return "$_[0]" cmp "$_[1]";
682             }
683              
684             sub have_same_universe {
685 0     0 0 0 my $self = shift;
686 0         0 my $universe = $self->universe;
687              
688 0         0 foreach my $set ( @_ ) {
689 0 0       0 return 0 unless $set->universe == $universe;
690             }
691              
692 0         0 return 1;
693             }
694              
695             sub _elements_have_reference {
696 147     147   170 my $self = shift;
697 147         151 my $elements = shift;
698              
699 147         247 foreach my $element (@$elements) {
700 380 100       793 return 1 if ref $element;
701             }
702              
703 122         233 return 0;
704             }
705              
706 22     22   229 use constant RECURSIVE_SELF => 1;
  22         310  
  22         1383  
707 22     22   112 use constant RECURSIVE_DEEP => 2;
  22         36  
  22         27707  
708              
709             sub _elements_as_string {
710 147     147   213 my $self = shift;
711 147         5857 my $history = shift;
712              
713 147         319 my @elements = $self->elements;
714 147         304 my $self_id = _strval($self);
715 147         203 my %history;
716              
717 147 100       303 %history = %{ $history } if defined $history;
  19         69  
718              
719 147         420 my $have_reference = $self->_elements_have_reference(\@elements);
720              
721 147         176 my @simple_elements;
722             my @complex_elements;
723 0         0 my $recursive;
724              
725 147         204 foreach my $element (@elements) {
726 398         616 my $element_id = _strval($element);
727              
728 398 100 66     1589 if (exists $history{ $element_id }) {
    100          
729 12 100       30 if ($element_id eq $self_id) {
730 7         13 $recursive = RECURSIVE_SELF;
731             } else {
732 5         14 $recursive = RECURSIVE_DEEP;
733             }
734             } elsif (blessed $element && $element->isa(__PACKAGE__)) {
735 19         101 local $history{ $element_id } = 1;
736 19         51 push @complex_elements, $element->as_string( \%history );
737             } else {
738 367         699 push @simple_elements, $element;
739             }
740             }
741              
742 147         585 @elements = sort @simple_elements;
743 147         277 push @elements, sort @complex_elements;
744              
745 147         371 return (join($self->_element_separator, @elements),
746             $have_reference,
747             $recursive);
748             }
749              
750             my $AS_STRING_CALLBACK = sub {
751             my $self = shift;
752              
753             my $string = '';
754              
755             if (exists $self->{'as_string'}) {
756             $string = $self->{'as_string'};
757             } else {
758             ($string, my $have_reference, my $is_recursive) =
759             $self->_elements_as_string(@_ ? shift :
760             { _strval($self) => 1 });
761              
762             $string .= $self->_element_separator . "..." if $is_recursive;
763              
764             $string = sprintf $self->_set_format, $string;
765              
766             $self->{'as_string'} = $string unless $have_reference;
767             }
768              
769             return $string;
770             };
771              
772             my $as_string_callback = $AS_STRING_CALLBACK;
773              
774             sub as_string_callback {
775 5     5 0 28 my $arg = shift;
776              
777 5 100       11 if (ref $arg) {
778 2 50       5 if (@_) {
779 2         5 $arg->{'as_string_callback'} = shift;
780 2 100       30 delete $arg->{'as_string_callback'}
781             unless defined $arg->{'as_string_callback'};
782             } else {
783 0         0 return $arg->{'as_string_callback'};
784             }
785             } else {
786 3 100       6 if (@_) {
787 2         4 $as_string_callback = shift;
788 2 50       9 $as_string_callback = $AS_STRING_CALLBACK
789             unless defined $as_string_callback;
790             } else {
791 1         3 return $as_string_callback;
792             }
793             }
794             }
795              
796             sub as_string {
797 208     208 0 378 my $self = shift;
798              
799 208 100       477 if (exists $self->{'as_string_callback'}) {
800 4         11 return $self->{'as_string_callback'}->($self, @_);
801             } else {
802 204         427 return $as_string_callback->($self, @_);
803             }
804             }
805              
806             sub _element_separator {
807 159     159   191 my $self = shift;
808              
809 159 50       2794 return $self->{'display'}->{'element_separator'}
810             if exists $self->{'display'}->{'element_separator'};
811              
812 159         336 my $universe = $self->universe;
813              
814 159 50       419 return $universe->{'display'}->{'element_separator'}
815             if exists $universe->{'display'}->{'element_separator'};
816              
817 159         586 return (ref $self)->ELEMENT_SEPARATOR;
818             }
819              
820             sub _set_format {
821 147     147   174 my $self = shift;
822              
823 147 50       375 return $self->{'display'}->{'set_format'}
824             if exists $self->{'display'}->{'set_format'};
825              
826 147         276 my $universe = $self->universe;
827              
828 147 50       370 return $universe->{'display'}->{'set_format'}
829             if exists $universe->{'display'}->{'set_format'};
830              
831 147         606 return (ref $self)->SET_FORMAT;
832             }
833              
834             =pod
835              
836             =head1 NAME
837              
838             Set::Scalar::Base - base class for Set::Scalar
839              
840             =head1 SYNOPSIS
841              
842             B.
843              
844             =head1 DESCRIPTION
845              
846             B
847             See the L.
848              
849             =head1 AUTHOR
850              
851             Jarkko Hietaniemi
852              
853             =cut
854              
855             1;