=head1 NAME

Hustle::Table - Cached general purpose dispatch and routing table

=head1 SYNOPSIS

  use Hustle::Table;

Create a new table:

  my $table=Hustle::Table->new;

Add entry as hash ref:

  $table->add( { matcher => qr/regex (match)/, value=> "a value"});

Add entry as array ref (3 elements required):

   $table->add( [qr/another/, "another value", undef])

Add entry as flat key value pairs:

	$table->add(matcher=>"jones", value=> sub {"one more"}, type=>"begin");

Add entry as tuple
	
	$table->add(qr|magic matcher| => "to a value");
	

Set the default entry:

	$table->set_default("default value");

Prepare a dispatcher external cache:

	my %cache;
	my $dispatch = $table->prepare_dispatcher(cache=>\%cache);


Call dispatcher to return the matching entry and any regex captures

  my ($entry, $captures)=$dispatch->("thing to match");	


=head1 DESCRIPTION

This module provides a class to construct a routing table and build a high
performance dispatcher from it. 

A table can have any combination of regex, exact string, begin string end
string or numeric matching of entries. The order in which the entries are added
defines their precedence. First in, first tested.

In the case of no entries matching the input, a default/fallback entry always
matches.

Once all the entries have been added to the table, a dispatcher is
prepared/created. The dispatcher is an anonymous subroutine, which tests its
argument against the matcher in each entry in the table.

It returns a list containing the first entry that matched, and an anonymous
array of any captures from regex  matching.

If more entries are required to be added to the table, the dispatcher must be
prepared again.

A cache (hash) is used to drastically improve table lookup performance. Entries
are automatically added to the cache. However removal of cache entries is up to
the user to implement on a application basis.


=head1 CREATING A TABLE

Calling the class constructor returns a new table. There are no required
arguments:

	my $table=Hustle::Table->new;

In this case, a default catch all entry (an undef value) is added
automatically.

If an argument is provided, it is the value used in the default/catch all
entry:

	my $table=Hustle::Table->new($default);


=head1 ENTRIES

=head2 Structure

An entry is an anonymous array containing the following elements:
	
	[matcher, value, type, default]

=over 

=item matcher

C<matcher> can be a regex, a string or a numeric value.

When C<matcher> is a regex, any captures are returned as the second item when
calling the dispatcher

When  C<matcher> is string or numeric value, the last field C<type> specifies
how to perform the match. See C<type> below.

If no C<type> is specified or is C<undef>, the C<matcher> is always treated as
a regex

=item value

This is the data you want to retrieve from the table when the matches.

=item type

C<type> is used to adjust how the matcher is interpreted. The possible values
are:
	
	undef	=> 	matcher is always treated as a regex
	"begin"	=>	matches the begining of input string
	"end"	=>	matches the end of input string
	"exact"	=>	string equality
	"numeric" =>	numeric equality

If C<matcher> is a precompiled regex (i.e. C<qr{}>), C<type> is ignored. 

If C<matcher> is a string or number, it is treated as a regex unless C<type> is
as above.

=item default

This is a flag indicating if the entry was the default entry

=back

=head2 Adding

Entries are added in anonymous hash, anonymous array or flattened format, using
the C<add> method.

Anonymous array entries must contain six elements, in the order of:
	
	$table->add([$matcher, $value, $type]);

Anonymous hashes format only need to specify the matcher and value pairs

	$table->add({matcher=>$matcher, value=>$value, type=>$type});

Single flattened format takes a list directly. It must contain 4 elements

	$table->add(matcher=>$matcher, value=> $value);

Single simple format takes two elements

	$table->add(qr{some matcher}=>$value);

Or add multiple at once using mixed formats together

	$table->add(
		[$matcher, $value, $type],
		{matcher=> $matcher, value=>$value},
		matcher=>$matcher, value=>$value
	);

In any case,C<matcher> and C<value> are the only items which must be defined.


=head2 Default Matcher

Each list has a default matcher that will unconditionally match the input. This
entry is specified by using C<undef> as the matcher when adding an entry. When
set this way only the array format can be used.

To make it more explicit, the it can also be changed via the C<set_default>
method. 

The default value of the 'default' entry is undef

=head1 PREPARING A DISPATCHER

Once all the entries are added to the table, the dispatcher can be
constructed by calling C<prepare_dispatcher>:

	my $dispatcher=$table->prepare_dispatcher(%args);

Arguments to this method include:

=over 

=item cache

The hash ref to use as the dispatchers cache. Specifying a hash allows external
management. If no cache is specified an internal cache is used.

=back

=head1 USING A DISPATCHER

The dispatcher is simply a sub, which you call with the input to match against
the table entries:

	my ($entry, $captures)=$dispatcher->("input");
	my $value=$entry->[1];

The return from the dispatcher is a list of two elements.

The first is the array reference to the table entry that matched (or the
default entry if no match was found). The value associated with the table entry
is located in position 1

The second item returned is an anonymous array of any captures due to a
matching regex


=head1 COMPARISON TO OTHER MODULES

Solid performance compared to other perl routing/dispatch modules. Faster in
basic tests then other perl modules: 

L<Smart::Dispatch>
L<Router::Simple>
L<Router::Boom>


If you need even more performance then checkout L<URI::Router>

TODO: make proper benchmark and comparison

=head1 AUTHOR

Ruben Westerberg, E<lt>drclaw@mac.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2022 by Ruben Westerberg

Licensed under MIT

=head1 DISCLAIMER OF WARRANTIES

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE.

=cut
