Set-Tiny-0.03/0000755000175000017500000000000012567410336010755 5ustar ststSet-Tiny-0.03/examples/0000755000175000017500000000000012567410336012573 5ustar ststSet-Tiny-0.03/examples/benchmark.pl0000755000175000017500000000724712410627234015071 0ustar stst#!/usr/bin/perl use strict; use lib 'lib'; # non-representative benchmark of different Set:: modules use Benchmark qw( cmpthese ); use Set::Tiny; use Set::Scalar; use Set::Object; my @a = 1 .. 100; my @b = 51 .. 150; my $s_t1 = Set::Tiny->new(@a); my $s_t2 = Set::Tiny->new(@b); my $s_s1 = Set::Scalar->new(@a); my $s_s2 = Set::Scalar->new(@b); my $s_o1 = Set::Object->new(@a); my $s_o2 = Set::Object->new(@b); my %tests = ( new => { t => sub { Set::Tiny->new(@a) }, s => sub { Set::Scalar->new(@a) }, o => sub { Set::Object->new(@a) }, }, # Set::Object doesn't have a clone() method #clone => { # t => sub { $s_t1->clone }, # s => sub { $s_s1->clone }, # o => sub { }, #}, insert => { t => sub { Set::Tiny->new->insert(@a) }, s => sub { Set::Scalar->new->insert(@a) }, o => sub { Set::Object->new->insert(@a) }, }, delete => { t => sub { Set::Tiny->new(@a)->delete(@b) }, s => sub { Set::Scalar->new(@a)->delete(@b) }, o => sub { Set::Object->new(@a)->delete(@b) }, }, invert => { t => sub { Set::Tiny->new(@a)->invert(@b) }, s => sub { Set::Scalar->new(@a)->invert(@b) }, o => sub { Set::Object->new(@a)->invert(@b) }, }, is_equal => { t => sub { $s_t1->is_equal($s_t2) }, s => sub { $s_s1->is_equal($s_s2) }, o => sub { $s_o1->equal($s_o2) }, }, is_subset => { t => sub { $s_t1->is_subset($s_t2) }, s => sub { $s_s1->is_subset($s_s2) }, o => sub { $s_o1->subset($s_o2) }, }, is_proper_subset => { t => sub { $s_t1->is_proper_subset($s_t2) }, s => sub { $s_s1->is_proper_subset($s_s2) }, o => sub { $s_o1->proper_subset($s_o2) }, }, is_superset => { t => sub { $s_t1->is_superset($s_t2) }, s => sub { $s_s1->is_superset($s_s2) }, o => sub { $s_o1->superset($s_o2) }, }, is_proper_superset => { t => sub { $s_t1->is_proper_superset($s_t2) }, s => sub { $s_s1->is_proper_superset($s_s2) }, o => sub { $s_o1->proper_superset($s_o2) }, }, is_disjoint => { t => sub { $s_t1->is_disjoint($s_t2) }, s => sub { $s_s1->is_disjoint($s_s2) }, o => sub { $s_o1->is_disjoint($s_o2) }, }, # The $set->contains(@elemets) methods are not identical: # Set::Tiny's and Set::Object's contains() returns true if $set contains # *all* of @elements # Set::Scalar's contains() returns true if $set contains *any* of @elements #contains => { # t => sub { $s_t1->contains(@b) }, # s => sub { $s_s1->contains(@b) }, # o => sub { $s_o1->contains(@b) }, #}, difference => { t => sub { $s_t1->difference($s_t2) }, s => sub { $s_s1->difference($s_s2) }, o => sub { $s_o1->difference($s_o2) }, }, union => { t => sub { $s_t1->union($s_t2) }, s => sub { $s_s1->union($s_s2) }, o => sub { $s_o1->union($s_o2) }, }, intersection => { t => sub { $s_t1->intersection($s_t2) }, s => sub { $s_s1->intersection($s_s2) }, o => sub { $s_o1->intersection($s_o2) }, }, symmetric_difference => { t => sub { $s_t1->symmetric_difference($s_t2) }, s => sub { $s_s1->symmetric_difference($s_s2) }, o => sub { $s_o1->symmetric_difference($s_o2) }, }, ); print "running benchmarks with sets of size ", scalar @a, " and ", scalar @b, "\n"; for my $test (sort keys %tests) { print "\n$test:\n"; cmpthese( -1, { 'Set::Tiny' => $tests{$test}{t}, 'Set::Scalar' => $tests{$test}{s}, 'Set::Object' => $tests{$test}{o}, }); } Set-Tiny-0.03/README0000644000175000017500000000173012410627234011630 0ustar ststSet-Tiny Set::Tiny is a thin wrapper around regular Perl hashes to perform often needed set operations, such as testing two sets of strings for equality, or checking whether one is contained within the other. INSTALLATION To install this module, run the following commands: perl Makefile.PL make make test make install SUPPORT AND DOCUMENTATION After installing, you can find documentation for this module with the perldoc command. perldoc Set::Tiny You can also look for information at: RT, CPAN's request tracker http://rt.cpan.org/NoAuth/Bugs.html?Dist=Set-Tiny AnnoCPAN, Annotated CPAN documentation http://annocpan.org/dist/Set-Tiny CPAN Ratings http://cpanratings.perl.org/d/Set-Tiny Search CPAN http://search.cpan.org/dist/Set-Tiny/ COPYRIGHT AND LICENCE Copyright (C) 2009 Stanis Trendelenburg This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Set-Tiny-0.03/lib/0000755000175000017500000000000012567410336011523 5ustar ststSet-Tiny-0.03/lib/Set/0000755000175000017500000000000012567410336012256 5ustar ststSet-Tiny-0.03/lib/Set/Tiny.pm0000644000175000017500000001756412567410205013547 0ustar ststpackage Set::Tiny; use 5.004; use strict; require Exporter; @Set::Tiny::ISA = qw(Exporter); @Set::Tiny::EXPORT_OK = qw(set); $Set::Tiny::VERSION = '0.03'; sub new { my $class = shift; my %self; @self{@_} = (); return bless \%self, $class; } sub set { if ( ref( $_[ 0 ] ) ne '' ) { return Set::Tiny->new( @{ $_[ 0 ] } ); } else { return Set::Tiny->new(@_); } } sub as_string { "(" . join(" ", sort keys %{$_[0]}) . ")" } sub size { scalar keys %{$_[0]} } sub element { exists $_[0]->{$_[1]} ? $_[1] : () } sub elements { keys %{$_[0]} } sub contains { my $self = shift; exists $self->{$_} or return for @_; return 1; } sub clone { my $class = ref $_[0]; return $class->new( keys %{$_[0]} ); } sub clear { %{$_[0]} = (); return $_[0]; } sub insert { my $self = shift; @{$self}{@_} = (); return $self; } sub remove { my $self = shift; delete @{$self}{@_}; return $self; } sub invert { my $self = shift; exists $self->{$_} ? delete $self->{$_} : ($self->{$_} = undef) for @_; return $self; } sub is_null { ! %{$_[0]} } sub is_subset { $_[1]->contains( keys %{$_[0]} ) } sub is_proper_subset { $_[0]->size < $_[1]->size && $_[0]->is_subset($_[1]) } sub is_superset { $_[1]->is_subset($_[0]) } sub is_proper_superset { $_[0]->size > $_[1]->size && $_[1]->is_subset($_[0]) } sub is_equal { $_[1]->is_subset($_[0]) && $_[0]->is_subset($_[1]) } sub is_disjoint { ! $_[0]->intersection($_[1])->size } sub is_properly_intersecting { ! $_[0]->is_disjoint($_[1]) && $_[0]->difference($_[1])->size && $_[1]->difference($_[0])->size } sub difference { $_[0]->clone->remove(keys %{$_[1]}) } sub union { my $class = ref $_[0]; return $class->new( keys %{$_[0]}, keys %{$_[1]} ); } sub intersection { my $class = ref $_[0]; return $class->new( grep { exists($_[0]->{$_}) } keys %{$_[1]} ); } sub intersection2 { my $class = ref $_[0]; my ($a, $b) = $_[0]->size > $_[1]->size ? ($_[0], $_[1]) : ($_[1], $_[0]); return $class->new( grep { exists($a->{$_}) } keys %{$b} ); } sub symmetric_difference { $_[0]->clone->invert(keys %{$_[1]}) } { *copy = \&clone; *has = \&contains; *member = \&element; *members = \&elements; *delete = \&remove; *is_empty = \&is_null; *unique = \&symmetric_difference; } 1; __END__ =head1 NAME Set::Tiny - Simple sets of strings =head1 VERSION Version 0.03 =head1 SYNOPSIS use Set::Tiny; my $s1 = Set::Tiny->new(qw( a b c )); my $s2 = Set::Tiny->new(qw( b c d )); my $u = $s1->union($s2); my $i = $s1->intersection($s2); my $s = $s1->symmetric_difference($s2); print $u->as_string; # (a b c d) print $i->as_string; # (b c) print $s->as_string; # (a d) print "i is a subset of s1" if $i->is_subset($s1); print "u is a superset of s1" if $u->is_superset($s1); # or using the shorter initializer: use Set::Tiny qw( set ); my $s1 = set(qw( a b c )); my $s2 = set([1, 2, 3]); =head1 DESCRIPTION Set::Tiny is a thin wrapper around regular Perl hashes to perform often needed set operations, such as testing two sets of strings for equality, or checking whether one is contained within the other. For a more complete implementation of mathematical set theory, see L. For sets of arbitrary objects, see L. =head2 Why Set::Tiny? =over =item Convenience Set::Tiny aims to provide a convenient interface to commonly used set operations, which you would usually implement using regular hashes and a couple of C loops (in fact, that's exactly what Set::Tiny does). =item Speed The price in performance you pay for this convenience when using a full-featured set implementation like L is way too high if you don't actually need the advanced functionality it offers. Run F for a (non-representative) comparison between different C modules. =item Ease of use L offers better performance than L, but needs a C compiler to install. Set::Tiny has no dependencies and contains no C code. =back =head1 EXPORTABLE FUNCTIONS =head2 set( [I] ) If you request it, Set::Tiny can export a function C, which lets you create a Set::Tiny instance in a more compact form. Unlike the constructor, this function also accepts the set elements as an array reference. =head1 METHODS Note that all methods that expect a I of set elements stringify their arguments before inserting them into the set. =head2 new( [I] ) Class method. Returns a new Set::Tiny object, initialized with the strings in I, or the empty set if I is empty. =head2 clone =head2 copy Returns a new set with the same elements as this one. =head2 insert( [I] ) Inserts the elements in I into the set. =head2 delete( [I] ) =head2 remove( [I] ) Removes the elements in I from the set. Elements that are not members of the set are ignored. =head2 invert( [I] ) For each element in I, if it is already a member of the set, deletes it from the set, else insert it into the set. =head2 clear Removes all elements from the set. =head2 as_string Returns a string representation of the set. =head2 elements =head2 members Returns the (unordered) list of elements. =head2 size Returns the number of elements. =head2 has( [I] ) =head2 contains( [I] ) Returns true if B of the elements in I are members of the set. If I is empty, returns true. =head2 element( [I] ) =head2 member( [I] ) Returns the string if it is contained in the set. =head2 is_null =head2 is_empty Returns true if the set is the empty set. =head2 union( I ) Returns a new set containing both the elements of this set and I. =head2 intersection( I ) Returns a new set containing the elements that are present in both this set and I. =head2 intersection2( I ) Like C, but orders the sets by size before comparing their elements. This results in a small overhead for small, evenly sized sets, but a large speedup when comparing bigger (~ 100 elements) and very unevenly sized sets. =head2 difference( I ) Returns a new set containing the elements of this set with the elements of I removed. =head2 unique( I ) =head2 symmetric_difference( I ) Returns a new set containing the elements that are present in either this set or I, but not in both. =head2 is_equal( I ) Returns true if this set contains the same elements as I. =head2 is_disjoint( I ) Returns true if this set has no elements in common with I. Note that the empty set is disjoint to any other set. =head2 is_properly_intersecting( I ) Returns true if this set has elements in common with I, but both also contain elements that they have not in common with each other. =head2 is_proper_subset( I ) Returns true if this set is a proper subset of I. =head2 is_proper_superset( I ) Returns true if this set is a proper superset of I. =head2 is_subset( I ) Returns true if this set is a subset of I. =head2 is_superset( I ) Returns true if this set is a superset of I. =head1 AUTHOR Stanis Trendelenburg, C<< >> =head1 CREDITS Thanks to Adam Kennedy for advice on how to make this module C. =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE Copyright 2009 Stanis Trendelenburg, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L Set-Tiny-0.03/t/0000755000175000017500000000000012567410336011220 5ustar ststSet-Tiny-0.03/t/set_init.t0000644000175000017500000000071412410627730013220 0ustar stst#!/usr/bin/perl use strict; use Test::More tests => 6; # test to make sure that the short initializer (`set()`) works use_ok 'Set::Tiny', qw(set); my $a = set(); my $b = set(qw( a b c )); isa_ok $a, 'Set::Tiny'; isa_ok $b, 'Set::Tiny'; is $a->as_string, '()', "empty set stringification"; is $b->as_string, '(a b c)', "non-empty set stringification"; my $c = set(['a', 'b', 'c']); is $c->as_string, '(a b c)', "initializer can be called with arrayref"; Set-Tiny-0.03/t/set.t0000644000175000017500000001037312567410205012177 0ustar stst#!/usr/bin/perl use strict; use Test::More tests => 60; use_ok 'Set::Tiny'; my $a = Set::Tiny->new; my $b = Set::Tiny->new(qw( a b c )); isa_ok $a, 'Set::Tiny'; sub to_s { join '', map { ref $_ eq 'Set::Tiny' ? $_->as_string : $_ } @_ } is $a->as_string, '()', "empty set stringification"; is $b->as_string, '(a b c)', "non-empty set stringification"; is $a->size, 0, to_s("size of ", $a, " is 0"); is $b->size, 3, to_s("size of ", $b, " is 3"); is $b->element('a'), 'a', "element()"; is $b->element('z'), undef, "element() on non-existing element"; is $b->member('a'), 'a', "member() is an alias for element()"; is_deeply [$a->elements], [], "elements() of emtpy set"; is_deeply [sort $b->elements], [qw( a b c )], "elements()"; is_deeply [sort $b->members], [qw( a b c )], "members() is an alias for elements()"; ok $b->contains(qw( a c )), to_s($b, " contains 'a' and 'c'"); ok $b->has(qw( a c )), "has() is an alias for contains()"; ok ! $a->contains('b'), to_s($a, " does not contain 'b'"); ok $a->contains(), to_s($a, " contains the empty list"); ok $a->is_null, to_s($a, " is empty"); ok ! $b->is_null, to_s($b, " is not empty"); ok $a->is_empty, "is_empty() is an alias for is_null"; ok $a->is_equal($a), to_s($a, " is equal to ", $a); ok $b->is_equal($b), to_s($b, " is equal to ", $b); ok ! $a->is_equal($b), to_s($a, " is not equal to ", $b); ok $a->is_subset($a), to_s($a, " is a subset of ", $a); ok $a->is_subset($b), to_s($a, " is a subset of ", $b); ok $b->is_subset($b), to_s($b, " is a subset of ", $b); ok ! $b->is_subset($a), to_s($b, " is not a subset of ", $a); ok $a->is_proper_subset($b), to_s($a, " is a proper subset of ", $b); ok ! $a->is_proper_subset($a), to_s($a, " is not a proper subset of ", $a); ok ! $b->is_proper_subset($b), to_s($b, " is not a proper subset of ", $b); ok ! $b->is_proper_subset($a), to_s($b, " is not a proper subset of ", $a); ok $b->is_superset($b), to_s($b, " is a superset of ", $b); ok $b->is_superset($a), to_s($b, " is a superset of ", $a); ok $a->is_superset($a), to_s($a, " is a superset of ", $a); ok ! $a->is_superset($b), to_s($a, " is not a superset of ", $b); ok $b->is_proper_superset($a), to_s($b, " is a proper superset of ", $a); ok ! $b->is_proper_superset($b), to_s($b, " is not a proper superset of ", $b); ok ! $a->is_proper_superset($a), to_s($a, " is not a proper superset of ", $a); ok ! $a->is_proper_superset($b), to_s($a, " is not a proper superset of ", $b); ok $a->is_disjoint($a), to_s($a, " and ", $a, " are disjoint"); ok $a->is_disjoint($b), to_s($a, " and ", $b, " are disjoint"); ok ! $b->is_disjoint($b), to_s($b, " and ", $b, " are not disjoint"); ok ! $a->is_properly_intersecting($b), to_s($a, " is not properly intersecting ", $b); ok ! $a->is_properly_intersecting($a), to_s($a, " is not properly intersecting ", $a); ok ! $b->is_properly_intersecting($b), to_s($b, " is not properly intersecting ", $b); my $c = Set::Tiny->new(qw( c d e )); ok $b->is_properly_intersecting($c), to_s($b, " is properly intersecting ", $c); my $d1 = $b->difference($c); my $d2 = $c->difference($b); is $d1->as_string, '(a b)', to_s("difference of ", $b, " and ", $c, " is ", $d1); is $d2->as_string, '(d e)', to_s("difference of ", $c, " and ", $b, " is ", $d2); my $u = $b->union($c); my $i = $b->intersection($c); my $i2 = $b->intersection2($c); my $s = $b->symmetric_difference($c); is $u->as_string, '(a b c d e)', to_s("union of ", $b, " and ", $c, " is ", $u); is $i->as_string, '(c)', to_s("intersection of ", $b, " and ", $c, " is ", $i); is $i2->as_string, '(c)', to_s("intersection2 of ", $b, " and ", $c, " is ", $i2); is $s->as_string, '(a b d e)', to_s("symmetric difference of ", $b, " and ", $c, " is ", $s); $s = $b->unique($c); is $s->as_string, '(a b d e)', "unique() is an alias for symmetric_difference()"; $b->clear; is $b->as_string, "()", "clear()"; $b->insert(qw( a b c d )); is $b->as_string, "(a b c d)", "insert()"; $b->remove(qw( a b )); is $b->as_string, "(c d)", "remove()"; $b->delete('c'); is $b->as_string, "(d)", "delete() is an alias for remove()"; $b->invert(qw( c d )); is $b->as_string, "(c)", "invert()"; my $x = $b->clone; is $x->as_string, "(c)", "clone()"; my $y = $b->copy; is $y->as_string, "(c)", "clone() is an alias for copy()"; $x->clear; is $b->as_string, "(c)", "clone is unchanged()"; Set-Tiny-0.03/t/meta.t0000644000175000017500000000116412410627234012327 0ustar stst#!/usr/bin/perl # Test that our META.yml file matches the specification use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Test::CPAN::Meta 0.12', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } meta_yaml_ok(); 1; Set-Tiny-0.03/t/pod.t0000644000175000017500000000120712410627234012161 0ustar stst#!/usr/bin/perl # Test that the syntax of our POD documentation is valid use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Pod::Simple 3.07', 'Test::Pod 1.26', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_pod_files_ok(); 1; Set-Tiny-0.03/t/minimumversion.t0000644000175000017500000000126712410627234014466 0ustar stst#!/usr/bin/perl # Test that our declared minimum Perl version matches our syntax use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Perl::MinimumVersion 1.20', 'Test::MinimumVersion 0.008', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_minimum_version_from_metayml_ok(); 1; Set-Tiny-0.03/Changes0000644000175000017500000000042012567410205012237 0ustar ststRevision history for Set-Tiny 0.03 2015-08-26 Faster intersection. Thanks to Alberto Simões. 0.02 2014-09-24 Added convenience initializer `set`. Thanks to Ricky Morse. 0.01 2009-03-18 First version, released on an unsuspecting world. Set-Tiny-0.03/MANIFEST0000644000175000017500000000034712567410336012112 0ustar ststChanges examples/benchmark.pl lib/Set/Tiny.pm Makefile.PL MANIFEST This list of files README t/meta.t t/minimumversion.t t/pod.t t/set.t t/set_init.t META.yml Module meta-data (added by MakeMaker) Set-Tiny-0.03/META.yml0000664000175000017500000000104112567410336012224 0ustar stst--- #YAML:1.0 name: Set-Tiny version: 0.03 abstract: Simple sets of strings author: - Stanis Trendelenburg license: perl distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: Test::More: 0 no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.57_05 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 Set-Tiny-0.03/Makefile.PL0000644000175000017500000000046712410627234012730 0ustar stst#!/usr/bin/perl use strict; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Set::Tiny', ABSTRACT_FROM => 'lib/Set/Tiny.pm', VERSION_FROM => 'lib/Set/Tiny.pm', AUTHOR => 'Stanis Trendelenburg ', LICENSE => 'perl', PREREQ_PM => { 'Test::More' => 0, }, );