mirror of
				https://github.com/pragma-/pbot.git
				synced 2025-11-04 00:27:23 +01:00 
			
		
		
		
	Storage-related packages have been moved to PBot/Storage/. MessageHistory_SQLite.pm has been moved to MessageHistory/Storage/SQLite.pm. Quotegrabs' storage packages have been moved to Plugin/Quotegrabs/Storage/. IRC handler-related packages have been moved to PBot/IRCHandlers/. Commands registered by core PBot packages have been moved to PBot/Commands/. Some non-core packages have been moved to PBot/Utils/. Several packages have been cleaned up. TODO: Move remaining core commands and IRC handlers. TODO: Split AntiFlood.pm into Plugin/AntiAbuse/ files.
		
			
				
	
	
		
			113 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
# File: PriorityQueue.pm
 | 
						|
#
 | 
						|
# Purpose: Bare-bones lightweight implementation of a priority queue.
 | 
						|
 | 
						|
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
 | 
						|
# SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package PBot::Utils::PriorityQueue;
 | 
						|
 | 
						|
use PBot::Imports;
 | 
						|
 | 
						|
sub new {
 | 
						|
    my ($class, %args) = @_;
 | 
						|
 | 
						|
    return bless {
 | 
						|
        # list of entries; each entry is expected to have a `priority` and an `id` field
 | 
						|
        queue => [],
 | 
						|
    }, $class;
 | 
						|
}
 | 
						|
 | 
						|
sub queue {
 | 
						|
    my ($self) = @_;
 | 
						|
    return $self->{queue};
 | 
						|
}
 | 
						|
 | 
						|
sub entries {
 | 
						|
    my ($self) = @_;
 | 
						|
    return @{$self->{queue}};
 | 
						|
}
 | 
						|
 | 
						|
sub count {
 | 
						|
    my ($self) = @_;
 | 
						|
    return scalar @{$self->{queue}};
 | 
						|
}
 | 
						|
 | 
						|
sub get {
 | 
						|
    my ($self, $position) = @_;
 | 
						|
    return $self->{queue}->[$position];
 | 
						|
}
 | 
						|
 | 
						|
sub get_priority {
 | 
						|
    my ($self, $position) = @_;
 | 
						|
    return $self->{queue}->[$position]->{priority};
 | 
						|
}
 | 
						|
 | 
						|
sub remove {
 | 
						|
    my ($self, $position) = @_;
 | 
						|
    return splice @{$self->{queue}}, $position, 1;
 | 
						|
}
 | 
						|
 | 
						|
# quickly and efficiently find the best position in the entry
 | 
						|
# queue array for a given priority value
 | 
						|
sub find_enqueue_position {
 | 
						|
    my ($self, $priority) = @_;
 | 
						|
 | 
						|
    $priority //= 0;
 | 
						|
 | 
						|
    # no entries in queue yet, early-return first position
 | 
						|
    return 0 if not @{$self->{queue}};
 | 
						|
 | 
						|
    # early-return first position if entry's priority is less
 | 
						|
    # than first position's
 | 
						|
    if ($priority < $self->{queue}->[0]->{priority}) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    # early-return last position if entry's priority is greater
 | 
						|
    if ($priority > $self->{queue}->[@{$self->{queue}} - 1]->{priority}) {
 | 
						|
        return scalar @{$self->{queue}};
 | 
						|
    }
 | 
						|
 | 
						|
    # binary search to find enqueue position
 | 
						|
 | 
						|
    my $lo = 0;
 | 
						|
    my $hi = scalar @{$self->{queue}} - 1;
 | 
						|
 | 
						|
    while ($lo <= $hi) {
 | 
						|
        my $mid = int (($hi + $lo) / 2);
 | 
						|
 | 
						|
        if ($priority < $self->{queue}->[$mid]->{priority}) {
 | 
						|
            $hi = $mid - 1;
 | 
						|
        } elsif ($priority > $self->{queue}->[$mid]->{priority}) {
 | 
						|
            $lo = $mid + 1;
 | 
						|
        } else {
 | 
						|
            # found a slot with the same priority. we "slide" down the array
 | 
						|
            # to append this entry to the end of this region of same-priorities
 | 
						|
            # and then return the final slot
 | 
						|
            while ($mid < @{$self->{queue}} and $self->{queue}->[$mid]->{priority} == $priority) {
 | 
						|
                $mid++;
 | 
						|
            }
 | 
						|
            return $mid;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return $lo;
 | 
						|
}
 | 
						|
 | 
						|
sub add {
 | 
						|
    my ($self, $entry) = @_;
 | 
						|
    my $position = $self->find_enqueue_position($entry->{priority});
 | 
						|
    splice @{$self->{queue}}, $position, 0, $entry;
 | 
						|
    return $position;
 | 
						|
}
 | 
						|
 | 
						|
sub update_priority {
 | 
						|
    my ($self, $id, $priority) = @_;
 | 
						|
    my @entries = grep { $_->{id} eq $id } @{$self->{queue}};
 | 
						|
    map { $_->{priority} = $priority } @entries;
 | 
						|
    $self->{queue} = [ sort { $a->{priority} <=> $b->{priority} } @{$self->{queue}} ];
 | 
						|
}
 | 
						|
 | 
						|
1;
 |