This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Utf8.c: Generate and use inversion lists for binary swashes
authorKarl Williamson <public@khwilliamson.com>
Sun, 27 Nov 2011 01:24:46 +0000 (18:24 -0700)
committerKarl Williamson <public@khwilliamson.com>
Fri, 13 Jan 2012 16:58:34 +0000 (09:58 -0700)
commit36eb48b449474e547f4a223443d342155b738cee
treed72b01f062d79a382153558c06304e142f8578ee
parentb6a0ff336ac042af856687d8dad55d9515a4779b
Utf8.c: Generate and use inversion lists for binary swashes

Prior to this patch, every time a code point was matched against a swash,
and the result was not previously known, a linear search through the
swash was performed.  This patch changes that to generate an inversion
list whenever a swash for a binary property is created.  A binary search
is then performed for missing values.

This change does not have much effect on the speed of Perl's regression
test suite, but the speed-up in worst-case scenarios is huge.  The
program at the end of this commit is crafted to avoid the caching that
hides much of the current inefficiencies.  At character classes of 100
isolated code points, the new method is about an order of magnitude
faster; two orders of magnitude at 1000 code points.  The program at the
end of this commit message took 97s to execute on my box using blead,
and 1.5 seconds using this new scheme.  I was surprised to see that even
with classes containing fewer than 10 code points, the binary search
trumped, by a little, the linear search

Even after this patch, under the current scheme, one can easily run out
of memory due to the permanent storing of results of swash lookups in
hashes.  The new search mechanism might be fast enough to enable the
elimination of that memory usage.  Instead, a simple cache in each
inversion list that stored its previous result could be created, and
that checked to see if it's still valid before starting the search,
under the assumption, which the current scheme also makes, that probes
will tend to be clustered together, as nearby code points are often in
the same script.
===============================================
 # This program creates longer and longer character class lists while
 # testing code points matches against them.  By adding or subtracting
 # 65 from the previous member, caching of results is eliminated (as of
 # this writing), so this essentially tests for how long it takes to
 # search through swashes to see if a code point matches or not.

use Benchmark ':hireswallclock';

my $string = "";
my $class_cp = 2**30;   # Divide the code space in half, approx.
my $string_cp = $class_cp;
my $iterations = 10000;
for my $j (1..2048) {

    # Append the next character to the [class]
    my $hex_class_cp = sprintf("%X", $class_cp);
    $string .= "\\x{$hex_class_cp}";
    $class_cp -= 65;

    next if $j % 100 != 0;  # Only test certain ones

    print "$j: lowest is [$hex_class_cp]: ";

    timethis(1, "no warnings qw(portable non_unicode);my \$i = $string_cp; for (0 .. $iterations) { chr(\$i) =~ /[$string]/; \$i+= 65 }");
    $string_cp += ($iterations + 1) * 65;
}
utf8.c