blob: 6a24a73e4edff0a5a3dd284514ce3be2c71b4b57 [file] [log] [blame]
package Krawfish::Query::Exclusion;
use strict;
use warnings;
use Role::Tiny::With;
use Krawfish::Query::Base::Dual;
# Export constants and @next_a and @next_b
use Krawfish::Query::Constraint::Position;
use Krawfish::Util::Bits; # exports bitstring
use Krawfish::Log;
use bytes;
with 'Krawfish::Query::Base::Dual';
with 'Krawfish::Query';
# This query validates positional constraints
# that are exclusive returns a valid forwarding mechanism
# It checks for an operand X that there is no operand Y
# in the given positional relation
use constant DEBUG => 0;
# Constructor
sub new {
my $class = shift;
bless {
frames => shift,
first => shift,
second => shift,
buffer => Krawfish::Util::Buffer->new,
}, $class;
};
# Clone query
sub clone {
my $self = shift;
__PACKAGE__->new(
$self->{frames},
$self->{first}->clone,
$self->{second}->clone
);
};
# Check for configuration
sub check {
my $self = shift;
my ($first, $second) = @_;
# Create configuration debug message
if (DEBUG) {
my $str = "Configuration is $first";
if ($second) {
$str .= ' vs ' . $second;
}
else {
$str .= ' only';
};
print_log('excl', $str);
};
# Get the current configuration
my $case = Krawfish::Query::Constraint::Position::case($first, $second);
my $frames = $self->{frames};
# There is a match - so A does not exclude B
if ($case & $frames) {
if (DEBUG) {
print_log('excl', "Excluded span occurs - next with A");
print_log('excl', ' for frames '.bitstring($frames));
print_log('excl', ' with case '.bitstring($case));
};
return NEXTA;
};
my $ret_val = NEXTA;
# Span may forward with b
if ($next_b[$case] & $frames) {
$ret_val |= NEXTB;
}
# Span may forward with a
elsif ($next_a[$case] & $frames) {
print_log('excl', 'No next b valid - so match') if DEBUG;
# Set current
$self->{doc_id} = $first->doc_id;
$self->{start} = $first->start;
$self->{end} = $first->end;
$self->{flags} = $first->flags;
$self->{payload} = $first->payload->clone;
print_log('excl', 'Set match to ' . $self->current->to_string) if DEBUG;
# TODO:
# Forget all entries span_b in this frame, that have an spanb->end < spana->start
# by returning a value that triggers skip_pos()
return NEXTA | MATCH;
}
# No second span
elsif (!$second) {
print_log('excl', 'The case is null') if DEBUG;
# Set current
$self->{doc_id} = $first->doc_id;
$self->{start} = $first->start;
$self->{end} = $first->end;
$self->{flags} = $first->flags;
$self->{payload} = $first->payload->clone;
print_log('excl', 'Set match to ' . $self->current->to_string) if DEBUG;
return NEXTA | MATCH;
};
if (DEBUG) {
print_log('excl', "Next frames are ".bitstring($next_a[$case])." for A and ");
print_log('excl', ' '.bitstring($next_b[$case])." for B");
print_log('excl', ' for frames '.bitstring($frames));
print_log('excl', ' with case '.bitstring($case));
};
return $ret_val;
};
# Stringification
sub to_string {
my $self = shift;
my $string = 'excl(' . (0 + $self->{frames}) . ':';
$string .= $self->{first}->to_string . ',';
return $string . $self->{second}->to_string . ')';
};
# Get maximum frequency
sub max_freq {
$_[0]->{first}->max_freq;
};
# Filter query by a VC
sub filter_by {
my ($self, $corpus) = @_;
# Only the first operand is relevant
$self->{first} = $self->{first}->filter_by($corpus);
return $self;
};
# Requires filtering
sub requires_filter {
return $_[0]->{first}->requires_filter;
};
1;