diff options
Diffstat (limited to 'regen')
-rw-r--r-- | regen/mk_invlists.pl | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/regen/mk_invlists.pl b/regen/mk_invlists.pl index a81c224fb5..1328f5850d 100644 --- a/regen/mk_invlists.pl +++ b/regen/mk_invlists.pl @@ -183,14 +183,29 @@ sub output_invmap ($$$$$$$) { my %enums; my $name_prefix; - if ($input_format eq 's') { + if ($input_format =~ / ^ s l? $ /x) { $prop_name = (prop_aliases($prop_name))[1] // $prop_name =~ s/^_Perl_//r; # Get full name my $short_name = (prop_aliases($prop_name))[0] // $prop_name; my @input_enums; # Find all the possible input values. These become the enum names - # that comprise the inversion map. + # that comprise the inversion map. For inputs that don't have sub + # lists, we can just get the unique values. Otherwise, we have to + # expand the sublists first. + if ($input_format ne 'sl') { @input_enums = sort(uniques(@$invmap)); + } + else { + foreach my $element (@$invmap) { + if (ref $element) { + push @input_enums, @$element; + } + else { + push @input_enums, $element; + } + } + @input_enums = sort(uniques(@input_enums)); + } # The internal enums come last, and in the order specified. my @enums = @input_enums; @@ -337,6 +352,14 @@ sub output_invmap ($$$$$$$) { my $enum_count = keys %enums; print $out_fh "\n#define ${name_prefix}ENUM_COUNT ", scalar keys %enums, "\n"; + if ($input_format eq 'sl') { + print $out_fh + "\n/* Negative enum values indicate the need to use an auxiliary" + . " table\n * consisting of the list of enums this one expands to." + . " The absolute\n * values of the negative enums are indices into" + . " a table of the auxiliary\n * tables' addresses */"; + } + # Start the enum definition for this map print $out_fh "\ntypedef enum {\n"; my @enum_list; @@ -344,16 +367,111 @@ sub output_invmap ($$$$$$$) { $enum_list[$enums{$enum}] = $enum; } foreach my $i (0 .. @enum_list - 1) { + print $out_fh ",\n" if $i > 0; + my $name = $enum_list[$i]; print $out_fh "\t${name_prefix}$name = $i"; - print $out_fh "," if $i < $enum_count - 1; - print $out_fh "\n"; } + + # For an 'sl' property, we need extra enums, because some of the + # elements are lists. Each such distinct list is placed in its own + # auxiliary map table. Here, we go through the inversion map, and for + # each distinct list found, create an enum value for it, numbered -1, + # -2, .... + my %multiples; + my $aux_table_prefix = "AUX_TABLE_"; + if ($input_format eq 'sl') { + foreach my $element (@$invmap) { + + # A regular scalar is not one of the lists we're looking for + # at this stage. + next unless ref $element; + + my $joined = join ",", sort @$element; + my $already_found = exists $multiples{$joined}; + + my $i; + if ($already_found) { # Use any existing one + $i = $multiples{$joined}; + } + else { # Otherwise increment to get a new table number + $i = keys(%multiples) + 1; + $multiples{$joined} = $i; + } + + # This changes the inversion map for this entry to not be the + # list + $element = "use_$aux_table_prefix$i"; + + # And add to the enum values + if (! $already_found) { + print $out_fh ",\n\t${name_prefix}$element = -$i"; + } + } + } + + print $out_fh "\n"; $declaration_type = "${name_prefix}enum"; print $out_fh "} $declaration_type;\n"; # Finished with the enum defintion. $output_format = "${name_prefix}%s"; + + # If there are auxiliary tables, output them. + if (%multiples) { + + print $out_fh "\n#define HAS_${name_prefix}AUX_TABLES\n"; + + # Invert keys and values + my %inverted_mults; + while (my ($key, $value) = each %multiples) { + $inverted_mults{$value} = $key; + } + + # Output them in sorted order + my @sorted_table_list = sort { $a <=> $b } keys %inverted_mults; + + # Keep track of how big each aux table is + my @aux_counts; + + # Output each aux table. + foreach my $table_number (@sorted_table_list) { + my $table = $inverted_mults{$table_number}; + print $out_fh "\nstatic const $declaration_type $name_prefix$aux_table_prefix$table_number\[] = {\n"; + + # Earlier, we joined the elements of this table together with a comma + my @elements = split ",", $table; + + $aux_counts[$table_number] = scalar @elements; + for my $i (0 .. @elements - 1) { + print $out_fh ",\n" if $i > 0; + print $out_fh "\t${name_prefix}$elements[$i]"; + } + print $out_fh "\n};\n"; + } + + # Output the table that is indexed by the absolute value of the + # aux table enum and contains pointers to the tables output just + # above + print $out_fh "\nstatic const $declaration_type * const ${name_prefix}${aux_table_prefix}ptrs\[] = {\n"; + print $out_fh "\tNULL,\t/* Placeholder */\n"; + for my $i (1 .. @sorted_table_list) { + print $out_fh ",\n" if $i > 1; + print $out_fh "\t$name_prefix$aux_table_prefix$i"; + } + print $out_fh "\n};\n"; + + print $out_fh + "\n/* Parallel table to the above, giving the number of elements" + . " in each table\n * pointed to */\n"; + print $out_fh "static const U8 ${name_prefix}${aux_table_prefix}lengths\[] = {\n"; + print $out_fh "\t0,\t/* Placeholder */\n"; + for my $i (1 .. @sorted_table_list) { + print $out_fh ",\n" if $i > 1; + print $out_fh "\t$aux_counts[$i]\t/* $name_prefix$aux_table_prefix$i */"; + } + print $out_fh "\n};\n"; + } # End of outputting the auxiliary and associated tables } else { die "'$input_format' invmap() format for '$prop_name' unimplemented"; |