App-Greple

 view release on metacpan or  search on metacpan

lib/App/Greple/Grep.pm  view on Meta::CPAN

	if ($self->{stretch}) {
	    my $b = $bp->[$bi];
	    my $m = $matched[0];
	    my $i = min map { $_->[2] // 0 } @matched;
	    @matched = [ $b->min, $b->max, $i, $m->[3] ];
	}
	if ($self->{only}) {
	    push @list, map({ [ $_, $_ ] } @matched);
	} elsif ($self->{all}) {
	    push @list, [ [ 0, length ] ] if @list == 0;
	    push @{$list[0]}, @matched;
	} else {
	    push @list, [ $bp->[$bi], @matched ];
	}
    }
    for my $r (@list) {
	bless $r, 'App::Greple::Grep::Result';
	bless $r->block, 'App::Greple::Grep::Block';
	for my $m ($r->matched) {
	    bless $m, 'App::Greple::Grep::Match';
	}
    }

    ##
    ## --join-blocks
    ##
    if ($self->{join_blocks} and @list > 1) {
	reduce {
	    if ($a->[-1][0]->max == $b->[0]->min) {
		$a->[-1][0]->max  = $b->[0]->max;
		push @{$a->[-1]}, splice @$b, 1;
	    } else {
		push @$a, $b;
	    }
	    $a;
	} \@list, splice @list, 1;
    }

    ##
    ## ( [ [blockstart, blockend, number ], [start, end], [start, end], ... ],
    ##   [ [blockstart, blockend, number ], [start, end], [start, end], ... ], ... )
    ##
    $self->{RESULT} = \@list;

    $self;
}

sub borders {
    my $self = shift;
    local $SIG{ALRM};
    my $alarm_start;
    if ($self->{alert_size} and length >= $self->{alert_size}) {
	$alarm_start = time;
	$SIG{ALRM} = sub {
	    $SIG{ALRM} = undef;
	    STDERR->printflush(
		$self->{filename} .
		": Counting lines, and it may take longer...\n");
	};
	alarm $self->{alert_time};
        warn "alert timer start ($alarm_start)\n" if $debug{a};
    }
    my @borders = do {
	if ($self->{BORDERS_CHILD}) {
	    my @b = $self->read_borders;
	    @b ? @b : match_borders $self->{border};
	} else {
	    match_borders $self->{border};
	}
    };
    if (defined $alarm_start) {
	if ($SIG{ALRM}) {
	    alarm 0;
	    warn "reset alert timer\n" if $debug{a};
	} else {
	    STDERR->printflush(sprintf("Count %d lines in %d seconds.\n",
				       @borders - 1,
				       time - $alarm_start));
	}
    }
    @borders;
}

sub result_ref {
    my $obj = shift;
    $obj->{RESULT};
}

sub result {
    my $obj = shift;
    @{ $obj->{RESULT} };
}

sub matched {
    my $obj = shift;
    sum(map { $_->@* - 1 } $obj->result) // 0;
}

sub blocks {
    my $obj = shift;
    $obj->{BLOCKS}->@*;
}

##
## Cut all result blocks (and gaps between them) from the text in a
## single pass.  Returns ( gap0, block0, gap1, block1, ..., rest ),
## or an empty list when not applicable.  Character based substr on
## a large utf8 string requires linear scan for every call to convert
## character offset to byte offset, so cutting each block separately
## makes the output routine quadratic.
##
sub slice_blocks {
    my $self = shift;
    my @blocks = map { $_->block } $self->result;
    return () if @blocks < 2;
    my $pos = 0;
    for (@blocks) {
	return () if $_->[0] < $pos;	# not in order
	$pos = $_->[1];
    }
    my $template = unpack_template(\@blocks, 0);
    unpack $template, ${ $self->{text} };
}

sub slice_result {
    my $obj = shift;
    my $result = shift;
    my($block, @list) = @$result;
    my $text = @_ ? shift : $obj->cut(@$block);
    my $template = unpack_template(\@list, $block->min);
    unpack($template, $text);
}

sub slice_index {



( run in 1.265 second using v1.01-cache-2.11-cpan-0b5f733616e )