package Data::TagsAndRanges::RangeContainer;
use Moose;
use Moose::Util::TypeConstraints;
use MooseX::Types::Moose qw(Num Str Any Undef ArrayRef);
use MooseX::Types::Structured qw(Dict);
use Data::TagsAndRanges::Exceptions;
has _storage => (
is => 'rw',
isa => ArrayRef[
Dict[
from => Num|Undef,
to => Num|Undef,
value => Any,
],
],
init_arg => undef,
default => sub { [ ] },
);
sub get {
my ($self,$args) = @_;
my $at = $args->{at};
my ($range) = $self->_get_slot_at($at);
if (!$range) {
Data::TagsAndRanges::Exceptions::RangeNotFound->throw({
value => $at,
});
}
return $range;
}
sub _cmp_less {
return if !defined $_[0];
return 1 if !defined $_[1];
return $_[0] <= $_[1];
}
sub _cmp_more {
return if !defined $_[0];
return 1 if !defined $_[1];
return $_[0] > $_[1];
}
sub _cmp_eq {
return 1 if !defined($_[0]) && !defined($_[1]);
return if defined($_[0]) xor defined($_[1]);
return $_[0] == $_[1];
}
sub _get_slot_at {
my ($self,$at) = @_;
for my $slot (@{$self->_storage}) {
next if _cmp_less($slot->{to},$at);
last if _cmp_more($slot->{from},$at);
return $slot;
}
return;
}
sub set_or_create {
my ($self,$args) = @_;
my $from = $args->{from};
my $to = $args->{to};
my ($range) = $self->_get_slot_at($from);
if ($range && _cmp_eq($range->{from},$from) && _cmp_eq($range->{to},$to)) {
return $range;
}
$range = $self->_create_slot($from,$to);
return $range;
}
sub _create_slot {
my ($self,$from,$to) = @_;
push @{$self->_storage},{
from => $from,
to => $to,
value => undef,
};
return $self->_storage->[-1];
}
1;