Index

An 'index' lets you find records instantly by key and iterate over ranges of keys in order. It supports multi-part keys: you can sort by a primary key and break ties with a secondary key. Declare the key fields inside angle brackets: 'field' sorts ascending, '-field' descending. Note: each record can only belong to one index at a time.

struct Elm {
  nr: integer,
  key: text,
  value: integer
}
struct Db {
  map: index < Elm[nr, -key] >
}
fn main() {

Adding and Looking Up Records

Fill the index just like a vector. Elements are automatically kept in key order. This index is sorted first by 'nr' (ascending), then by 'key' (descending) for ties.

  db = Db {map: [
  Elm {nr: 101, key: "One", value: 1 },
  Elm {nr: 92, key: "Two", value: 2 },
  Elm {nr: 83, key: "Three", value: 3 },
  Elm {nr: 83, key: "Four", value: 4 },
  Elm {nr: 83, key: "Five", value: 5 },
  Elm {nr: 63, key: "Six", value: 6 }
  ] };

Provide all key fields together inside brackets to find a record. Supply fewer fields to match all records that share a prefix.

  assert(db.map[101, "One"].value == 1, "Key lookup");
  assert(!db.map[12, ""], "Missing key returns null");
  assert(!db.map[83, "One"], "Wrong secondary key returns null");

Iterating in Order

A 'for' loop visits all elements in key order.

  total = 0;
  for r in db.map {
    total += r.value;
  }
  assert(total == 21, "Sum of all values: {total}");

Range Queries

Provide a range in the first key position to visit only the matching slice. '[83..92, "Two"]' means: nr from 83 up to (not including) 92, and key from "Two" down (since the key is sorted descending, "Two" is the start of that descending segment).

  sum = 0;
  for v in db.map[83..92, "Two"] {
    sum = sum * 10 + v.value;
  }

Elements matched: (83, Three, 3), (83, Four, 4), (83, Five, 5)

  assert(sum == 345, "Range iteration result: {sum}");

Loop Helpers: #first and #count

'r#first' is true for the very first element visited. 'r#count' is a running counter starting at 0. Note: #index is not meaningful on index collections — use #count instead.

  first_nr = 0;
  count_total = 0;
  for r in db.map {
    if r#first {
      first_nr = r.nr
    }
    count_total = r#count
  }
  assert(first_nr == 63, "First element by key: {first_nr}");
  assert(count_total == 5, "Total elements: {count_total}");

Removing by Key

Assigning null to an index subscript removes the element with that exact key combination. Removing a key that is not present is a safe no-op.

  db.map[92, "Two"] = null;
  assert(!db.map[92, "Two"], "element (92, Two) was removed");
  assert(db.map[101, "One"].value == 1, "element (101, One) still present");
  db.map[999, "Z"] = null;

no-op; does not panic

  total2 = 0;
  for r in db.map {
    total2 += r.value
  }
  assert(total2 == 19, "Sum after key removal: {total2}");
}