Mod /
Tree Varying
Search:  


Table Of Contents (show)

  1. 1. Varying Tree
  2. 2. Initialized Data
    1. 2.1 Field
    2. 2.2 Tree
    3. 2.3 Array
  3. 3. Validation
  4. 4. Root

1.  Varying Tree

A varying tree is a *tree with data at many different levels. It uses + to indicate tree structure.

Here is an example:

namespace eval ::myapp {

    *tree new mt + {
        { + init "Record initializers" } {
            { + host  "Per host/ipaddress statistics"} {
                { badq          0   "Counter for bad queries" }
                { inchars       0   "Total chars received from clients" }
                { lasttime      {}  "Time of last query" }
                { outchars      0   "Total chars sent to clients" }
                { queries       0   "Counter for queries" }
            }
        }
        { + status  "Global statistics for THS server"} {
            { inchars       0   "Total chars received from clients" -type Int }
            { lastcode      {}  "Code from last query" -type Int }
            { lasttime      {}  "Time of last query" }
            { outchars      0   "Total chars sent to clients" }
            { queries       0   "Counter for queries" }
            { + tht  "Info for THT" } {
                { queries     0   "Counter of THT queries" -type Int }
                { resident    0   "Counter of Resident THT queries" }
            }
            { + bad  "Info for last field" } {
                { passwd     0   "Counter for bad password attempts" }
                { qlast      {}  "HTML from last bad query" }
                { qlasttime  {}  "Time of last bad query" }
                { queries    0   "Counter for bad queries" }
            }
        }
        { * hosts "Per host/ipaddress statistics array"} {}
    } -typecheck 1

    proc UpdCnt {ip cnt} {
        # Add some cnt chars for ip. If req create record.
        variable mt
        if {![$mt exists 0.hosts $ip]} {
            $mt set .hosts $ip [$mt get .init.host]
        }
        $mt incr .hosts ${ip}(inchars) $cnt
    }

    proc Main {args} {
        variable mt

        # Update some of the fixed fields
        $mt incr   .status       inchars  3
        $mt update .status       lasttime -1 queries 4
        $mt update .status.tht   resident -1 queries 4
        $mt update .status.bad   passwd   10

        # Create and update array fields.
        set ini [$mt get .init.host]
        $mt set   .hosts 192.168.1.101          $ini
        $mt set   .hosts 192.168.1.102          $ini
        $mt incr  .hosts 192.168.1.101(inchars)

        UpdCnt 192.168.1.104 10

        *tree view $mt

        *catch { $mt set    .status inchars xyz }
        *catch { $mt insert .hosts -label 192.168.1.104 }

    }

    eval Main $argv
}

2.  Initialized Data

The data that initializes a varying tree consist of a sequence of list element where the first element is one of:

  • + : indicates a tree element with sub-trees.
  • * : indicates an array element.
  • otherwise: indicates a field.

2.1  Field

The first 3 values in a field sequence are:

  • the field name
  • the field value
  • a description

Values may following in name/value pairs, including -type to provide type checking.

2.2  Tree

A tree sequence begins with a + and is followed by the node name. The third (optional) element is a description.

2.3  Array

We use a * to indicate an array sequence. This will add the tag _array to the node. This is used by *tree view to properly display and edit the data.

In a tree, each key in a node can contain either an ordinary value or an array. Thus in the above example we have a single node hosts to which we add a key for each IP address, and these each contain an array (somewhat like a dict).

One might wonder why not just insert nodes in host for each IP? That would certainly work, however, period is a delimiter in *tree so we could not then use the IP address as a label, ie. for lookups. (See Validation).

3.  Validation

In a non-flat *tree the period is a record delimiter, so using one in a label will generate an error.

When run with wize -Wall or when using the -typecheck option, tree will typecheck accesses to fields which define -type. If a type doesn't match, an error is raised and the value is restored. eg.

  *catch { $mt set .status inchars xyz }
  *catch { $mt insert .hosts -label 192.168.1.104 }

Warn: *catch(1): 'type mismatch: Int xyz: Int' in 'Main'
        Evaling: '$mt set .status inchars xyz'
Warn: *catch(1): 'label with dot: 192.168.1.104can't allocate new node' in 'Main'
        Evaling: '$mt insert .hosts -label 192.168.1.104'

4.  Root

The keys in the root node are used to store the description (in -cmt) and attributes such as -type for the fields. This is used for typechecking.

© 2008 Peter MacDonald

Page last modified on January 31, 2010, at 08:01 AM