4 - An Example Speed Table Definition

This chapter provides an example speed table definition, explains it, and shows some basic usage of a speed table.
package require speedtable

speedtables Animinfo 1.1 { table animation_characters { varstring name indexed 1 unique 0 varstring home varstring show indexed 1 unique 0 varstring dad boolean alive default 1 varstring gender default male int age int coolness } }

Speed tables are defined inside the code block of the speedtables package.

Executing this will generate table-specific a Tcl extension package named Animinfo, compile it and link it it into a shared library. This package is implemented by application-specific C language code generated from the table definitions in the package.

Multiple speed tables can be defined in one speedtables package.

The package name must start with an uppercase letter, and can not contain any digits... this is a limitation of the Tcl package and shared library model.

The name of the package follows the "speedtables" keyword, followed by a version number, and then a code body containing table definitions.

Loading Your Speed Table Package

After sourcing in the above definition, you can do a package require Animinfo or package require Animinfo 1.1 and Tcl will load the extension and make it available.

For efficiency's sake, we detect whether or not the package has been altered since the last time it was generated as a shared library, and avoid the compilation and linking phase when it isn't necessary.

Sourcing the above code body and doing a package require Animinfo will create one new command, animation_characters, corresponding to the defined table. We call this command a Speed tables Class because it behaves similarly to iTcl classes, Tk widgets, and other object-oriented extensions to Tcl. It's also referred to as a meta table or a creator table.

animation_characters create t creates a new object, t, that is a Tcl command that will manage and manipulate zero or more rows of the animation_characters table.

One meta table can create many speed tables

You can create additional instances of the table using the meta table's create method. All tables created from the same meta table operate independently of each other, although they share the meta table data structure that speed table implementation code uses to understand and operate on the tables.

You can also say...

 set obj [animation_characters create #auto]

...to create a new instance of the table (containing, at first, zero rows), without having to generate a unique name for it.

Speed Table Basic Usage Examples

t set shake name "Master Shake" \
 show "Aqua Teen Hunger Force"

This creates a new row in the speed table named t. Currently all rows in a speed table must have unique key value, which resides outside of the table definition itself. The key for this row is "shake" [1]. The name and show fields in the row are set to the passed-in values.

We can set other fields in the same row:

t set shake age 4 coolness -5

And increment them in one operation:

% t incr shake age 1 coolness -1
5 -6

I can fetch a single value pretty naturally...

if {[t get $key age] > 18} {...}

Or I can get all the fields in definition order:

puts [t get shake]
{} {} {} {} {} 1 male 5 -6

Forgot what fields are available?

% t fields
id name home show dad alive gender age coolness

You can get a list of fields in array get format:

array set data [t array_get shake]
puts "$data(name) $data(coolness)"

In the above example, if a field's value is null then the field name and value will not be returned by array_get. So if a field can be null, you'll want to check for its existence using array_get_with_nulls, which will always provide all the fields' values, substituting a settable null value (typically the empty string) when the value is null.

Want to see if something exists?

t exists frylock

Let's load up our table from a file tab-separated data:

set fp [open animation_characters.tsv]
t read_tabsep $fp
close $fp


Search is one of the most useful capabilities of speed tables. Let's use search to write all of the rows in the table to a save file:

set fp [open save.tsv]
t search -write_tabsep $fp
close $fp

Want to restrict the results to a certain set of fields? Use the -fields option followed by a list of the names of the fields you want.

t search -write_tabsep $fp \
-fields {name show coolness}

Sometimes you might want to include the names of the fields as the first line...

t search -write_tabsep $fp \
-fields {name show coolness} \
-with_field_names 1

Let's find everyone who's on the Venture Brothers show who's over 20 years old, and execute code for each result:

t search -compare {{= show "Venture Brothers} {> age 20}} \ -array_get data -code {
 puts $data

Additional meta table methods

animation_characters info - which currently does nothing (boring)

animation_characters null_value \\N - which sets the default null value for all tables of this table type to, in this case, \N

Bug: This should be settable on a per-table basis.

animation_characters method foo bar - this will register a new method named foo and then invoke the proc bar with the arguments being the name of the object followed by whatever arguments were passed.

For example, if after executing animation_characters method foo bar and creating an instance of the animation_characters table named t, if you executed

   t foo a b c d

...then proc bar would be called with the arguments "x a b c d".

Implementation note: the generated C source code, some copied .c and .h files, the compiled .o object file, and shared library (the "Speed Tables Objects") are written in a directory called stobj underneath the directory that's current at the time the Speed Tables Package is sourced, unless a build path is specified. For example, after the "package require speedtable" and outside of and prior to the package definition, if you invoke

CTableBuildPath /tmp

...then those files will be generated in the /tmp directory. (It's a bad idea to use /tmp on a multiuser machine, of course, but could be OK for a dedicated appliance or something like that.)

Note that the specified build path is appended to the Tcl library search path variable, auto_path, if it isn't already in there.

[1] It feels a bit clumsy to have an external key like this, and we are working on making the key a part of the row itself, which seems better. Currently the "key" data type is used, and if no "key" is defined then the pseudo-field "_key" is created.