@@ -109,6 +109,7 @@ sub new_intersection {
109109sub values { $_ [0]{values } }
110110sub unique_values { $_ [0]{unique_values } }
111111sub constraint { $_ [0]{constraint } ||= $_ [0]-> _build_constraint }
112+ sub use_eq { return $_ [0]{use_eq } if exists $_ [0]{use_eq }; $_ [0]{use_eq } = $_ [0]-> _build_use_eq }
112113
113114sub _is_null_constraint { 0 }
114115
@@ -117,6 +118,11 @@ sub _build_display_name {
117118 sprintf ( " Enum[%s ]" , join q[ ,] , @{ $self -> unique_values } );
118119}
119120
121+ sub _build_use_eq {
122+ my $self = shift ;
123+ !Type::Tiny::_USE_XS and @{ $self -> unique_values } <= 5;
124+ }
125+
120126sub is_word_safe {
121127 my $self = shift ;
122128 return not grep /\W/, @{ $self -> unique_values };
@@ -231,17 +237,30 @@ sub can_be_inlined {
231237sub inline_check {
232238 my $self = shift ;
233239
234- my $xsub ;
235240 if ( my $xs_encoding = _xs_encoding( $self -> unique_values ) ) {
236- $xsub = Type::Tiny::XS::get_subname_for( $xs_encoding );
241+ my $xsub = Type::Tiny::XS::get_subname_for( $xs_encoding );
237242 return " $xsub \( $_ [0]\) " if $xsub && !$Type::Tiny::AvoidCallbacks ;
238243 }
239244
240- my $regexp = $self -> _regexp;
241- my $code =
242- $_ [0] eq ' $_'
243- ? " (defined and !ref and m{\\ A(?:$regexp )\\ z})"
244- : " (defined($_ [0]) and !ref($_ [0]) and $_ [0] =~ m{\\ A(?:$regexp )\\ z})" ;
245+ my $code ;
246+ if ( $self -> use_eq ) {
247+ use B ();
248+ my %seen ;
249+ my @vals = grep { not $seen {$_ }++ } @{ $self -> values };
250+ if ( @vals == 1 ) {
251+ $code = sprintf ( ' (defined %s and !ref %s and %s eq %s)' , $_ [0], $_ [0], $_ [0], B::perlstring($vals [0]) );
252+ }
253+ else {
254+ $code = sprintf ( ' (defined %s and !ref %s and (%s))' , $_ [0], $_ [0], join q{ or } => map { sprintf ' (%s eq %s)' , $_ [0], B::perlstring($_ ) } @vals );
255+ }
256+ }
257+ else {
258+ my $regexp = $self -> _regexp;
259+ $code =
260+ $_ [0] eq ' $_'
261+ ? " (defined and !ref and m{\\ A(?:$regexp )\\ z})"
262+ : " (defined($_ [0]) and !ref($_ [0]) and $_ [0] =~ m{\\ A(?:$regexp )\\ z})" ;
263+ }
245264
246265 return " do { $Type::Tiny::SafePackage $code }"
247266 if $Type::Tiny::AvoidCallbacks ;
@@ -585,6 +604,46 @@ be passed to the constructor.
585604If C<< coercion => 1 >> is passed to the constructor, the type will have a
586605coercion using the C<closest_match > method.
587606
607+ =item C<use_eq >
608+
609+ When generating Perl type checking code, Type::Tiny::Enum will traditionally
610+ test incoming strings for being valid using a single regular expression,
611+ unless L<Type::Tiny::XS> is available and a faster XS check is possible.
612+
613+ From version 2.008006 onwards, if L<Type::Tiny::XS> is unavailable, and the
614+ enum is "small" (five possible values or less), Type::Tiny::Enum will instead
615+ generate code like:
616+
617+ ( $_ eq "foo" or $_ eq "bar" or $_ eq "baz" )
618+
619+ ... which benchmarks around 5% to 20% faster than C<< /(?:ba[rz]|foo)/ >>.
620+
621+ However, it is possible to manually indicate whether you prefer it to
622+ generate code using C<eq > or regexps by setting C<use_eq > to a boolean
623+ value in the constructor. (If C<use_eq > is not passed to the constructor
624+ at all, Type::Tiny::Enum will try to guess the most efficient technique.)
625+
626+ If you know that certain values in your enumeration are more common than
627+ others, you can "front load" your enumeration with the most common values
628+ so that C<eq > checks those I<first > . This may allow you to speed up certain
629+ checks.
630+
631+ has car_colour => (
632+ is => 'rw',
633+ isa => Type::Tiny::Enum->new( use_eq => 1, values => [qw/
634+ blue
635+ red
636+ grey
637+ white
638+ black
639+ green
640+ yellow
641+ orange
642+ purple
643+ pink
644+ /] );
645+ );
646+
588647=back
589648
590649=head2 Methods
0 commit comments