package Queue; use strict; use warnings; use include; # Make a new blank Queue object. Entries must be hashes for now. sub new { return bless { IDs => {}, Queue => [], Active => 0, Hooks => [], Heap => {} }, shift; } # Turn an ID into an entry number and verify its existence. sub check { my ($self, $id) = @_; if ($id =~ m/\D/) { # \D = has non-digits, aka, isnt a number #debug("$id not there...") return unless exists $self->{IDs}{$id}; $id = $self->{IDs}{$id}; } #carp("no entry #$id..."), return unless $self->{Queue}[$id]; return unless $self->{Queue}[$id]; return $id; } # Sets an existing entry. sub set { my ($self, $id, %new) = @_; $id = $self->check($id) // croak "can't set to an undefined id"; %{ $self->{Queue}[$id] } = (%{ $self->{Queue}[$id] }, %new); $self->callback("set", $id); } # Returns an entry. sub get { my ($self, $id) = @_; $id = $self->check($id); return $self->{Queue}[$id] if defined $id; } # Returns the active ID. sub active { my $self = shift; croak "No active entry yet... queue is empty" unless @{ $self->{Queue} }; return $self->{Active}; } # Adds a new hook. sub hook { my ($self, $hook, $id, $ref) = @_; push @{ $self->{Hooks} }, $hook; $self->{Heap}{$id} = $ref; } sub callback { my $self = shift; foreach (@{ $self->{Hooks} }) { $_->($self, @_); } } # Adds a new entry to the end of the queue. sub add { my ($self, $id, %new) = @_; croak "the ID key is reserved for use by queue!" if $new{ID}; push @{ $self->{Queue} }, {%new, ID => $id}; $self->{IDs}{$id} = $#{ $self->{Queue} }; $id = $self->check($id); $self->callback("add", $id); } # Adds a new entry to the beginning of the queue. sub preadd { my ($self, $id, %new) = @_; my $queue = $self->{Queue}; croak "the ID key is reserved for use by queue!" if $new{ID}; unshift @$queue, {%new, ID => $id}; $self->{IDs}{$id} = 0; foreach (1 .. $#{ $queue }) { $self->{IDs}{ $queue->[$_]{ID} }++; } $id = $self->check($id); $self->callback("add", $id); } # Deletes an entry. sub del { my ($self, $id) = @_[0, 1]; my $aux = 1 if $_[2] and $_[2] eq "-aux"; $id = $self->check($id) // croak "can't delete an unknown id"; $self->{Active}-- if $id <= $self->active; $self->{Active} = 0 if $self->{Active} < 0; my $entry = splice @{ $self->{Queue} }, $id, 1; delete $self->{IDs}{ $entry->{ID} }; foreach ($id .. $#{ $self->{Queue} }) { $self->{IDs}{ $self->{Queue}[$_]{ID} }--; } $self->callback("del", $entry) unless $aux; return $entry; } # Returns all the entries. sub all { my $self = shift; return @{ $self->{Queue} }; } # Change the active entry. sub move_up { my $self = shift; return if $self->{Active} == 0; $self->{Active}--; $self->callback("move"); } sub move_down { my $self = shift; return if $self->{Active} == $#{ $self->{Queue} }; $self->{Active}++; $self->callback("move"); } sub move_first { my $self = shift; return if $self->{Active} == 0; $self->{Active} = 0; $self->callback("move"); } sub move_last { my $self = shift; return if $self->{Active} == $#{ $self->{Queue} }; $self->{Active} = $#{ $self->{Queue} }; $self->callback("move"); } # Actually move the active entry to another position. sub shift_up { my $self = shift; my ($active, $queue) = ($self->{Active}, $self->{Queue}); return if $active == 0; ($queue->[$active], $queue->[$active - 1]) = ($queue->[$active - 1], $queue->[$active]); $self->{Active}--; $self->{IDs}{ $queue->[$self->{Active}]{ID} }--; $self->{IDs}{ $queue->[$self->{Active} + 1]{ID} }++; $self->callback("shift", $self->{Active} + 1, $self->{Active}); } sub shift_down { my $self = shift; my ($active, $queue) = ($self->{Active}, $self->{Queue}); return if $self->{Active} == $#{ $self->{Queue} }; ($queue->[$active], $queue->[$active + 1]) = ($queue->[$active + 1], $queue->[$active]); $self->{Active}++; $self->{IDs}{ $queue->[$self->{Active}]{ID} }++; $self->{IDs}{ $queue->[$self->{Active} - 1]{ID} }--; $self->callback("shift", $self->{Active} - 1, $self->{Active}); } sub shift_first { my $self = shift; my ($active, $queue) = ($self->{Active}, $self->{Queue}); return if $active == 0; my $entry = $self->del($active, "-aux"); unshift @$queue, $entry; $self->{IDs}{ $entry->{ID} } = 0; $self->{Active} = 0; foreach (1 .. $#{ $queue }) { $self->{IDs}{ $queue->[$_]{ID} }++; } $self->callback("shift", $active, $self->{Active}); } sub shift_last { my $self = shift; my ($active, $queue) = ($self->{Active}, $self->{Queue}); return if $active == $#{ $queue }; my $entry = $self->del($active, "-aux"); push @$queue, $entry; $self->{IDs}{ $entry->{ID} } = $#{ $queue }; $self->{Active} = $#{ $queue }; $self->callback("shift", $active, $self->{Active}); } 42;