Algorithm-SlidingWindow

 view release on metacpan or  search on metacpan

lib/Algorithm/SlidingWindow.pm  view on Meta::CPAN

package Algorithm::SlidingWindow;

use strict;
use warnings;

use Carp 'croak';


our $VERSION = '1.002';

sub new {
    my ($class, %args) = @_;

    # --- die if extra arguments ---
    my %allowed = map { $_ => 1 } qw(capacity on_evict);
    for my $k (keys %args) {
        croak "unknown argument '$k'" unless $allowed{$k};
    }

    # --- required arguments ---
    my $capacity = $args{capacity};
    defined $capacity or croak "capacity is required";
    $capacity =~ /\A[0-9]+\z/ or croak "capacity must be a positive integer";
    $capacity > 0 or croak "capacity must be > 0";

    # --- optional arguments ---
    my $on_evict = $args{on_evict};
    if (defined $on_evict) {
        ref($on_evict) eq 'CODE' or croak "on_evict must be a CODE reference";
    }

    # --- initialize backing store ---
    my @buf;
    $#buf = $capacity - 1;   # preallocate fixed storage

    my $self = bless {
        _cap      => 0 + $capacity,
        _buf      => \@buf,
        _head     => 0,
        _size     => 0,
        _on_evict => $on_evict,
    }, $class;

    return $self;
}

sub add {
    my $self = $_[0];

    # Fast path: no items to add
    return $self if @_ == 1;

    my $cap  = $self->{_cap};
    my $buf  = $self->{_buf};
    my $head = $self->{_head};
    my $size = $self->{_size};
    my $cb   = $self->{_on_evict};

    for (my $ai = 1; $ai < @_; $ai++) {
        my $item = $_[$ai];

        if ($size == $cap) {
            my $old = $buf->[$head];
            $cb->($old) if $cb;

            # Drop references immediately
            $buf->[$head] = undef;

            $head++;
            $head = 0 if $head == $cap;
        }
        else {
            $size++;
        }

        my $tail = $head + $size - 1;
        $tail -= $cap if $tail >= $cap;

        $buf->[$tail] = $item;
    }

    $self->{_head} = $head;
    $self->{_size} = $size;

    return $self;
}

sub values {
    my $self = $_[0];

    my $size = $self->{_size};
    return () if $size == 0;

    my $cap  = $self->{_cap};
    my $buf  = $self->{_buf};
    my $i    = $self->{_head};



( run in 1.123 second using v1.01-cache-2.11-cpan-39bf76dae61 )