-if (keys %OP_IS_SOCKET) {
- print ON "\n#define OP_IS_SOCKET(op) \\\n\t(";
- print ON join(" || \\\n\t ",
- map { "(op) == OP_" . uc() } sort keys %OP_IS_SOCKET);
- print ON ")\n\n";
-}
-
-if (keys %OP_IS_FILETEST) {
- print ON "\n#define OP_IS_FILETEST(op) \\\n\t(";
- print ON join(" || \\\n\t ",
- map { "(op) == OP_" . uc() } sort keys %OP_IS_FILETEST);
- print ON ")\n\n";
+# Emit OP_IS_* macros
+
+print $on <<EO_OP_IS_COMMENT;
+
+/* the OP_IS_(SOCKET|FILETEST) macros are optimized to a simple range
+ check because all the member OPs are contiguous in opcode.pl
+ <DATA> table. opcode.pl verifies the range contiguity. */
+
+EO_OP_IS_COMMENT
+
+gen_op_is_macro( \%OP_IS_SOCKET, 'OP_IS_SOCKET');
+gen_op_is_macro( \%OP_IS_FILETEST, 'OP_IS_FILETEST');
+gen_op_is_macro( \%OP_IS_FT_ACCESS, 'OP_IS_FILETEST_ACCESS');
+
+sub gen_op_is_macro {
+ my ($op_is, $macname) = @_;
+ if (keys %$op_is) {
+
+ # get opnames whose numbers are lowest and highest
+ my ($first, @rest) = sort {
+ $op_is->{$a} <=> $op_is->{$b}
+ } keys %$op_is;
+
+ my $last = pop @rest; # @rest slurped, get its last
+ die "Invalid range of ops: $first .. $last\n" unless $last;
+
+ print $on "#define $macname(op) \\\n\t(";
+
+ # verify that op-ct matches 1st..last range (and fencepost)
+ # (we know there are no dups)
+ if ( $op_is->{$last} - $op_is->{$first} == scalar @rest + 1) {
+
+ # contiguous ops -> optimized version
+ print $on "(op) >= OP_" . uc($first) . " && (op) <= OP_" . uc($last);
+ print $on ")\n\n";
+ }
+ else {
+ print $on join(" || \\\n\t ",
+ map { "(op) == OP_" . uc() } sort keys %$op_is);
+ print $on ")\n\n";
+ }
+ }