Acme-Urinal
view release on metacpan or search on metacpan
lib/Acme/Urinal.pm view on Meta::CPAN
package Acme::Urinal;
use strict;
use warnings;
use Carp;
our $VERSION = '1.0';
=head1 NAME
Acme::Urinal - assign resources using the same algorithm used by men choosing which urinal to use
=head1 SYNOPSIS
use Acme::Urinal;
my $urinals = Acme::Urinal->new(8);
say $urinal->pick_one; # prints 1
say $urinal->pick_one; # prints 3
say $urinal->pick_one; # prints 5
say $urinal->pick_one; # prints 7
say $urinal->pick_one; # prints 2
say $urinal->pick_one; # prints 4
say $urinal->pick_one; # prints 6
say $urinal->pick_one; # prints 0
say $urinal->pick_one; # prints nothing, triggers an uninit warning
$urinal->leave(3);
$urinal->leave(4);
say $urinal->pick_one; # prints 4
$urinal->leave(2);
$urinal->leave(1);
say $urinal->pick_one; # prints 1
=head1 DESCRIPTION
When men use a bathroom with multiple urinals. The way the urinal to use is
chosen is nearly deterministic. This module allocates resources in a way that
emulates this process.
Basically, a L<Acme::Urinal> object keeps track of a list of resources. You can
then request these resources be allocated and used by asking for one using the
L</pick_one> method. It will return the next resource according to the
algorithm. Once finished suing that resource, you may return it using the
L</leave> method.
Each resource is chosen according to the following rules:
=over
=item 1.
If possible, the lowest index resource that has a free resource on either side
is chosen.
=item 2.
Failing that, the lowest index resource with a lesser neighbor free is chosen.
=item 3.
Failing that, the lowest index resource with a greater neighbor free is chosen.
=item 4.
Failing that, the lowest index resource that is not at either end is chosen
(because those end ones usually tend to be the less preferable low urinal).
=item 5.
Finally, the lowest index resource that is available is chosen.
=back
=head1 METHODS
=head2 new
my $urinal = Acme::Urinal->new($count);
my $urinal = Acme::Urinal->new(\@resources);
Constructs a new Acme::Urinal object. If the argument is a positive integer, it
is the same as if an array reference were passed like this:
[ 0 .. $count ]
If an array reference is passed, the object will use that array as the list of
resources. The array will be copied, so changes to the original, won't change
the one used by Acme::Urinal.
Anything else should cause an error.
=cut
sub new {
my ($class, $resources) = @_;
if (ref $resources) {
return bless [ map { [ 0, $_ ] } @$resources ], $class;
( run in 1.500 second using v1.01-cache-2.11-cpan-5b529ec07f3 )