Under development — the help is being filled in plugin by plugin.
Plugin reference

map

An ordered key/value map for script data.

18 functionsnamespace mapsource plugins/map/MapPlugin.c

Written from a line-by-line source review; every example output is from a real run.

Introduction

The map plugin is a named, in-memory key-value store (a hash map or dictionary). Several independent maps can exist at once, each identified by a unique name. The key is always a string; the value can be one of three kinds: text (string), integer (i64), or binary data (blob). The store is thread-safe: every operation is protected by a per-map mutex, so it is safe to use from multiple threads.

How it works inside

The implementation is a chained hash table (a bucket array with a linked list per bucket), using a 32-bit FNV-1a hash that is fast and distributes well for short string keys. When the load exceeds 75%, the table automatically doubles and rehashes. The store is ephemeral: it lives for the duration of the process and is never written to disk. It has no external dependencies (pthreads on Linux, CRITICAL_SECTION on Windows).

Loading the plugin

At the top of your script, load the plugin by a path to its file, relative to the script, without the extension. From the Examples folder this is of the form ../plugins/...:

plugin "../plugins/print/PrintPlugin";
plugin "../plugins/map/MapPlugin";

A typical lifecycle

Usage almost always follows the same arc: create (Create), populate (Put*), query (Get*/HasKey), and finally clear or destroy (Clear/Destroy). A key may not be empty and may not exceed the built-in length limit.

map.Create("config", 16);
map.PutString("config", "host", "localhost");
printf("%s\n", map.GetString("config", "host"));
map.Destroy("config");

What to know about every function (the basics)

  • The kind matters on lookup. Every entry has a kind (string, int, or blob). GetString returns only a string value, GetInt only an int, GetBlob only a blob — if the key has a different kind (or is missing), the function returns the "empty" result (empty string, 0, or empty blob), not an error.

  • A missing map is not an error. Most operations on a non-existent map simply return 0 (or an empty value) and the script keeps running. To be sure, call map.Exists first.

  • An error occurs only for a wrong argument count or type, an empty or too-long key, or out of memory — in those cases the script stops with a runtime error.

  • Put* overwrites. If the key already exists, Put* replaces its value (and its kind).

  • The key iteration order (Keys) follows the internal hash layout, NOT the insertion order — do not expect a sorted result.

  • The atomic operations (IncrInt, CompareAndSwapInt, AppendString, SetIfAbsentString) perform the whole read-modify-write in a single mutex-protected step, so no update is lost even with multiple threads.

How to read the signatures

name is always the map's name, key is the key. The type after the -> arrow is the return type. For example, map.PutInt(name, key, value) -> int means three arguments are required and the result is an integer (1 for success, 0 for failure).

Lifecycle

Creating, destroying, checking the existence of, and emptying a map.

map.Create

map.Create(name, initialCapacity) -> int

Creates a new, empty map with the given name. The initial capacity is only a performance hint (the table grows on its own when needed).

Parameters
Parameter Type Description
name string The unique name of the map. May not be empty, and has a built-in length limit.
initialCapacity int Initial bucket count (rounded up to the nearest power of two). 0 or negative is set to the minimum.
Return value

1 if it was created; 0 if a map with that name already exists. (Too many maps or out of memory causes a runtime error.)

Example
// a second Create with the same name does not create a new one
printf("%d\n", map.Create("m", 16));
printf("%d\n", map.Create("m", 16));
Output after running
1
0
When to use

Create the maps you need at the start of the program. The 0 return signals that a name is already taken — so several modules can share a map without clashing.

map.Destroy

map.Destroy(name) -> int

Destroys the map and frees all memory associated with it.

Parameters
Parameter Type Description
name string The name of the map to destroy.
Return value

1 if it was destroyed; 0 if there was no map with that name.

Example
map.Create("m", 8);
printf("%d\n", map.Destroy("m"));
printf("%d\n", map.Destroy("m"));
Output after running
1
0
When to use

Call it at the end of the program or when a task is done, so no leftover data stays in memory. Unlike Clear, it also frees the name.

map.Exists

map.Exists(name) -> int

Tells whether a map with the given name exists.

Parameters
Parameter Type Description
name string The name of the map to check.
Return value

1 if it exists; 0 if not.

Example
map.Create("m", 8);
printf("%d\n", map.Exists("m"));
printf("%d\n", map.Exists("nope"));
Output after running
1
0
When to use

For conditional initialization: create the map only if it does not yet exist (though Create's 0 return can serve the same purpose).

map.Clear

map.Clear(name) -> int

Removes all entries from the map but keeps the map itself (and its name).

Parameters
Parameter Type Description
name string The name of the map to empty.
Return value

1 if it was emptied; 0 if there was no map with that name.

Example
map.Create("m", 8);
map.PutInt("m", "a", 1);
printf("%d\n", map.Clear("m"));
printf("%d\n", map.Size("m"));
Output after running
1
0
When to use

For emptying a reusable map between runs when you do not want to pay the cost of Create/Destroy again.

Inserting

Storing a value under a key. All three functions overwrite if the key already exists.

map.PutString

map.PutString(name, key, value) -> int

Stores a text value under the key.

Parameters
Parameter Type Description
name string The name of the map.
key string The key (may not be empty).
value string The text to store.
Return value

1 on success; 0 if there is no map with that name.

Example
map.Create("m", 8);
printf("%d\n", map.PutString("m", "name", "Ada"));
Output after running
1
When to use

For storing configuration values, names, messages. GetString reads back the same value.

map.PutInt

map.PutInt(name, key, value) -> int

Stores an integer value (i64) under the key.

Parameters
Parameter Type Description
name string The name of the map.
key string The key.
value int The integer to store.
Return value

1 on success; 0 if there is no map with that name.

Example
map.Create("m", 8);
printf("%d\n", map.PutInt("m", "age", 36));
Output after running
1
When to use

For storing counters, identifiers, settings. If you would increment a counter, the atomic IncrInt is safer than a Get+Put pair.

map.PutBlob

map.PutBlob(name, key, value) -> int

Stores binary data (a blob) under the key. The whole blob content is copied, including any 0 bytes.

Parameters
Parameter Type Description
name string The name of the map.
key string The key.
value blob The binary data to store.
Return value

1 on success; 0 if there is no map with that name.

Example
blob $B[4];
map.Create("m", 8);
$B[0] = 1; $B[1] = 2; $B[2] = 3;
$B.Length = 3;
printf("%d\n", map.PutBlob("m", "raw", $B));
Output after running
1
When to use

For storing raw bytes (a hash, an image, a network packet) where a 0 byte inside the data must be preserved. GetBlob reads it back.

Lookups

Reading a value or checking whether a key exists. Both a kind mismatch and a missing key produce the "empty" result.

map.HasKey

map.HasKey(name, key) -> int

Tells whether the key exists in the map (regardless of its kind).

Parameters
Parameter Type Description
name string The name of the map.
key string The key to look for.
Return value

1 if the key exists; 0 if not (or if the map does not exist).

Example
map.Create("m", 8);
map.PutString("m", "name", "Ada");
printf("%d\n", map.HasKey("m", "name"));
printf("%d\n", map.HasKey("m", "xxx"));
Output after running
1
0
When to use

For an existence check when the content does not matter. It distinguishes "no key" from "key present but value is empty/0", which Get* cannot.

map.GetString

map.GetString(name, key) -> string

Returns the text stored under the key.

Parameters
Parameter Type Description
name string The name of the map.
key string The key to look for.
Return value

The stored text; an empty string if the key is missing OR is not a string kind.

Example
map.Create("m", 8);
map.PutString("m", "name", "Ada");
map.PutInt("m", "age", 36);
printf("%s\n", map.GetString("m", "name"));
// 'age' is an int, so as a string it is empty
printf("[%s]\n", map.GetString("m", "age"));
Output after running
Ada
[]
When to use

For reading text values. If you must tell an empty string apart from a missing key, call HasKey first.

map.GetInt

map.GetInt(name, key) -> int

Returns the integer value stored under the key.

Parameters
Parameter Type Description
name string The name of the map.
key string The key to look for.
Return value

The stored integer; 0 if the key is missing OR is not an int kind.

Example
map.Create("m", 8);
map.PutInt("m", "age", 36);
map.PutString("m", "name", "Ada");
printf("%d\n", map.GetInt("m", "age"));
// 'name' is a string, so as an int it is 0
printf("%d\n", map.GetInt("m", "name"));
Output after running
36
0
When to use

For reading numeric values. To tell a real 0 from "missing", use HasKey, or store values so that 0 is never a valid one.

map.GetBlob

map.GetBlob(name, key) -> blob

Returns the binary data stored under the key.

Parameters
Parameter Type Description
name string The name of the map.
key string The key to look for.
Return value

A copy of the stored blob; an empty blob if the key is missing OR is not a blob kind.

Example
blob $B[4];
blob $Out[16];
map.Create("m", 8);
$B[0] = 1; $B[1] = 2; $B[2] = 3; $B.Length = 3;
map.PutBlob("m", "raw", $B);
$Out = map.GetBlob("m", "raw");
printf("%d\n", $Out.Length);
Output after running
3
When to use

For reading binary data back. The returned blob is an independent copy, so later changes to the map do not affect it.

Modifying

Removing an entry.

map.Remove

map.Remove(name, key) -> int

Removes the key and its associated value.

Parameters
Parameter Type Description
name string The name of the map.
key string The key to remove.
Return value

1 if it was removed; 0 if the key did not exist (or the map does not exist).

Example
map.Create("m", 8);
map.PutInt("m", "age", 36);
printf("%d\n", map.Remove("m", "age"));
printf("%d\n", map.Remove("m", "age"));
Output after running
1
0
When to use

For deleting a single entry. To empty the whole map, Clear is faster than removing keys one by one.

Atomic operations

These functions perform the read-modify-write in a single mutex-protected step. With multiple threads, no update can be lost — unlike a manual Get+Put pair.

map.IncrInt

map.IncrInt(name, key, delta) -> int

Atomically adds delta to the key's integer value and returns the NEW value. A missing key starts at 0; a non-int key is overwritten as an int (0 + delta).

Parameters
Parameter Type Description
name string The name of the map.
key string The counter's key.
delta int The value to add (may be negative).
Return value

The new integer value after the operation. (If the map does not exist, it returns delta itself but stores nothing.)

Example
map.Create("m", 8);
printf("%d\n", map.IncrInt("m", "hits", 1));
printf("%d\n", map.IncrInt("m", "hits", 5));
Output after running
1
6
When to use

For counters, accumulators, identifier generation. It replaces the dangerous "read, increment, write back" pattern, which can lose updates with multiple threads.

map.CompareAndSwapInt

map.CompareAndSwapInt(name, key, expected, new) -> int

Replaces the key's value with new only if it is currently exactly expected (and of int kind). An optimistic locking primitive.

Parameters
Parameter Type Description
name string The name of the map.
key string The key.
expected int The expected current value.
new int The new value if the check succeeds.
Return value

1 if it was swapped; 0 if not (key missing and expected is not 0, wrong kind, or value is not expected). Special case: if the key is missing and expected=0, it creates it with new.

Example
map.Create("m", 8);
map.IncrInt("m", "hits", 6);
// 6 -> 100 succeeds; the second (expects 6 again) does not
printf("%d\n", map.CompareAndSwapInt("m", "hits", 6, 100));
printf("%d\n", map.CompareAndSwapInt("m", "hits", 6, 200));
Output after running
1
0
When to use

For optimistic locking: read a value, compute with it, then write it back with CAS; if someone changed it meanwhile, CAS returns 0 and you can retry. expected=0 is good for the "initialize exactly once" pattern.

map.AppendString

map.AppendString(name, key, suffix) -> int

Atomically appends suffix to the key's existing text. If the key is missing, suffix becomes the new value.

Parameters
Parameter Type Description
name string The name of the map.
key string The key.
suffix string The text to append.
Return value

1 on success; 0 if the key is a non-string kind (int/blob) — in which case it does NOT overwrite — or if the map does not exist.

Example
map.Create("m", 8);
printf("%d\n", map.AppendString("m", "log", "a"));
printf("%d\n", map.AppendString("m", "log", "b"));
printf("%s\n", map.GetString("m", "log"));
Output after running
1
1
ab
When to use

For building logs, comma-separated lists, or append-only events, where several threads may append to the same key.

map.SetIfAbsentString

map.SetIfAbsentString(name, key, value) -> int

Writes the (key, value) pair only if the key does not already exist.

Parameters
Parameter Type Description
name string The name of the map.
key string The key.
value string The value to write if the key is missing.
Return value

1 if it was written; 0 if the key already existed (with any kind), or if the map does not exist.

Example
map.Create("m", 8);
printf("%d\n", map.SetIfAbsentString("m", "mode", "x"));
// already exists, the second does not overwrite
printf("%d\n", map.SetIfAbsentString("m", "mode", "y"));
printf("%s\n", map.GetString("m", "mode"));
Output after running
1
0
x
When to use

For one-shot initialization ("init once"): several threads may race to set the same default, but only one wins (gets 1), the others get 0.

Inspection

Querying the size and the keys of a map.

map.Size

map.Size(name) -> int

Returns the number of entries stored in the map.

Parameters
Parameter Type Description
name string The name of the map.
Return value

The number of entries; 0 if the map is empty or does not exist.

Example
map.Create("m", 8);
map.PutInt("m", "a", 1);
map.PutInt("m", "b", 2);
printf("%d\n", map.Size("m"));
Output after running
2
When to use

For a size check, an emptiness test, or estimating the number of items a Keys walk will yield.

map.Keys

map.Keys(name) -> blob

Returns all keys in a single blob, separated by NUL (0) bytes. The language has no array type, so this is how you iterate the keys.

Parameters
Parameter Type Description
name string The name of the map.
Return value

A blob in which the keys are laid out separated by 0 bytes. An empty blob for an empty or non-existent map. The order follows the internal hash layout, not the insertion order.

Example
blob $K[256];
string $Key[64];
i32 $Pos;
i32 $End;
i32 $j;
map.Create("m", 8);
map.PutString("m", "name", "Ada");
map.PutInt("m", "age", 36);
$K = map.Keys("m");
$Pos = 0;
while ($Pos < $K.Length)
{
$End = $Pos;
while (($End < $K.Length) && ($K[$End] != 0)) { $End =
$End + 1; }
$j = $Pos;
while ($j < $End) { $Key[$j - $Pos] = $K[$j]; $j = $j + 1; }
$Key.Length = $End - $Pos;
printf("%s\n", $Key);
$Pos = $End + 1;
}
Output after running
age
name
When to use

For iterating over all entries (since the language has no foreach). The walk pattern: find the next 0 byte, copy the stretch before it as a key, then jump past the 0. Do not expect a sorted order.

Practical notes

What the map is good for

  • Storing configuration, settings, values reachable by name (a "config" map).

  • Collecting counters and statistics (IncrInt), especially with multiple threads.

  • Cache-like data that needs fast access by key.

  • Shared state across threads, since every operation is thread-safe.

Thread safety done right

Individual calls are atomic on their own, but another thread can slip in between two separate calls (for example a Get followed by a Put). If you read-modify-write the same key, do not use a Get+Put pair; use the atomic operation that fits the purpose: IncrInt for a counter, CompareAndSwapInt for a conditional swap, AppendString for appending text, SetIfAbsentString for one-shot initialization.

Common pitfalls

  • Kind mismatch: if you stored a key as an int, GetString returns an empty string for it (and vice versa). Keep the kind consistent per key, or check with HasKey.

  • 0 and the empty string are not errors: Get* returns these for a missing key too. Where the distinction matters, use HasKey.

  • Keys does not sort: the key order reflects the hash table layout. If you need sorted output, sort the keys in the script.

  • Ephemeral store: the map disappears when the process stops. For persistence, save the data elsewhere (a file or a database).

Error handling

A wrong argument count or type, an empty/too-long key, and out of memory are reported by the runtime as a runtime error, and the script stops. Content-level cases (no such map, no such key, kind mismatch), however, are handled by the plugin not as errors but with a neutral return value, so in the usual cases you do not need extra guard checks.

The csv table plugin

Reading and writing CSV/TSV — complete function reference