home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / struct / tree.tcl < prev   
Encoding:
Text File  |  2001-08-17  |  30.1 KB  |  1,179 lines

  1. # tree.tcl --
  2. #
  3. #    Implementation of a tree data structure for Tcl.
  4. #
  5. # Copyright (c) 1998-2000 by Ajuba Solutions.
  6. #
  7. # See the file "license.terms" for information on usage and redistribution
  8. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  9. # RCS: @(#) $Id: tree.tcl,v 1.14 2001/06/22 15:29:18 andreas_kupries Exp $
  10.  
  11. namespace eval ::struct {}
  12.  
  13. namespace eval ::struct::tree {
  14.     # Data storage in the tree module
  15.     # -------------------------------
  16.     #
  17.     # There's a lot of bits to keep track of for each tree:
  18.     #    nodes
  19.     #    node values
  20.     #    node relationships
  21.     #
  22.     # It would quickly become unwieldy to try to keep these in arrays or lists
  23.     # within the tree namespace itself.  Instead, each tree structure will get
  24.     # its own namespace.  Each namespace contains:
  25.     #    children    array mapping nodes to their children list
  26.     #    parent        array mapping nodes to their parent node
  27.     #    node:$node    array mapping keys to values for the node $node
  28.     
  29.     # counter is used to give a unique name for unnamed trees
  30.     variable counter 0
  31.  
  32.     # commands is the list of subcommands recognized by the tree
  33.     variable commands [list \
  34.         "children"        \
  35.         "cut"        \
  36.         "destroy"        \
  37.         "delete"        \
  38.         "depth"        \
  39.         "exists"        \
  40.         "get"        \
  41.         "index"        \
  42.         "insert"        \
  43.         "isleaf"        \
  44.         "move"        \
  45.         "next"        \
  46.         "numchildren"    \
  47.         "parent"        \
  48.         "previous"        \
  49.         "set"        \
  50.         "size"        \
  51.         "splice"        \
  52.         "swap"        \
  53.         "unset"        \
  54.         "walk"        \
  55.         ]
  56.  
  57.     # Only export one command, the one used to instantiate a new tree
  58.     namespace export tree
  59. }
  60.  
  61. # ::struct::tree::tree --
  62. #
  63. #    Create a new tree with a given name; if no name is given, use
  64. #    treeX, where X is a number.
  65. #
  66. # Arguments:
  67. #    name    Optional name of the tree; if null or not given, generate one.
  68. #
  69. # Results:
  70. #    name    Name of the tree created
  71.  
  72. proc ::struct::tree::tree {{name ""}} {
  73.     variable counter
  74.     
  75.     if { [llength [info level 0]] == 1 } {
  76.     incr counter
  77.     set name "tree${counter}"
  78.     }
  79.  
  80.     if { [llength [info commands ::$name]] } {
  81.     error "command \"$name\" already exists, unable to create tree"
  82.     }
  83.  
  84.     # Set up the namespace
  85.     namespace eval ::struct::tree::tree$name {
  86.     # Set up root node's child list
  87.     variable children
  88.     set children(root) [list ]
  89.  
  90.     # Set root node's parent
  91.     variable parent
  92.     set parent(root) [list ]
  93.  
  94.     # Set up the root node's data
  95.     variable noderoot
  96.     set noderoot(data) ""
  97.  
  98.     # Set up a value for use in creating unique node names
  99.     variable nextUnusedNode
  100.     set nextUnusedNode 1
  101.     }
  102.  
  103.     # Create the command to manipulate the tree
  104.     interp alias {} ::$name {} ::struct::tree::TreeProc $name
  105.  
  106.     return $name
  107. }
  108.  
  109. ##########################
  110. # Private functions follow
  111.  
  112. # ::struct::tree::TreeProc --
  113. #
  114. #    Command that processes all tree object commands.
  115. #
  116. # Arguments:
  117. #    name    Name of the tree object to manipulate.
  118. #    cmd    Subcommand to invoke.
  119. #    args    Arguments for subcommand.
  120. #
  121. # Results:
  122. #    Varies based on command to perform
  123.  
  124. proc ::struct::tree::TreeProc {name {cmd ""} args} {
  125.     # Do minimal args checks here
  126.     if { [llength [info level 0]] == 2 } {
  127.     error "wrong # args: should be \"$name option ?arg arg ...?\""
  128.     }
  129.     
  130.     # Split the args into command and args components
  131.     if { [llength [info commands ::struct::tree::_$cmd]] == 0 } {
  132.     variable commands
  133.     set optlist [join $commands ", "]
  134.     set optlist [linsert $optlist "end-1" "or"]
  135.     error "bad option \"$cmd\": must be $optlist"
  136.     }
  137.     eval [list ::struct::tree::_$cmd $name] $args
  138. }
  139.  
  140. # ::struct::tree::_children --
  141. #
  142. #    Return the child list for a given node of a tree.
  143. #
  144. # Arguments:
  145. #    name    Name of the tree object.
  146. #    node    Node to look up.
  147. #
  148. # Results:
  149. #    children    List of children for the node.
  150.  
  151. proc ::struct::tree::_children {name node} {
  152.     if { ![_exists $name $node] } {
  153.     error "node \"$node\" does not exist in tree \"$name\""
  154.     }
  155.     
  156.     upvar ::struct::tree::tree${name}::children children
  157.     return $children($node)
  158. }
  159.  
  160. # ::struct::tree::_cut --
  161. #
  162. #    Destroys the specified node of a tree, but not its children.
  163. #    These children are made into children of the parent of the
  164. #    destroyed node at the index of the destroyed node.
  165. #
  166. # Arguments:
  167. #    name    Name of the tree object.
  168. #    node    Node to look up and cut.
  169. #
  170. # Results:
  171. #    None.
  172.  
  173. proc ::struct::tree::_cut {name node} {
  174.     if { [string equal $node "root"] } {
  175.     # Can't delete the special root node
  176.     error "cannot cut root node"
  177.     }
  178.     
  179.     if { ![_exists $name $node] } {
  180.     error "node \"$node\" does not exist in tree \"$name\""
  181.     }
  182.     
  183.     upvar ::struct::tree::tree${name}::parent   parent
  184.     upvar ::struct::tree::tree${name}::children children
  185.     
  186.     # Locate our parent, children and our location in the parent
  187.     set parentNode $parent($node)
  188.     set childNodes $children($node)
  189.     
  190.     set index [lsearch -exact $children($parentNode) $node]
  191.     
  192.     # Excise this node from the parent list, 
  193.     set newChildren [lreplace $children($parentNode) $index $index]
  194.  
  195.     # Put each of the children of $node into the parent's children list,
  196.     # in the place of $node, and update the parent pointer of those nodes.
  197.     foreach child $childNodes {
  198.     set newChildren [linsert $newChildren $index $child]
  199.     set parent($child) $parentNode
  200.     incr index
  201.     }
  202.     set children($parentNode) $newChildren
  203.  
  204.     # Remove all record of $node
  205.     unset parent($node)
  206.     unset children($node)
  207.     # FRINK: nocheck
  208.     unset ::struct::tree::tree${name}::node$node
  209.  
  210.     return
  211. }
  212.  
  213. # ::struct::tree::_delete --
  214. #
  215. #    Remove a node from a tree, including all of its values.  Recursively
  216. #    removes the node's children.
  217. #
  218. # Arguments:
  219. #    name    Name of the tree.
  220. #    node    Node to delete.
  221. #
  222. # Results:
  223. #    None.
  224.  
  225. proc ::struct::tree::_delete {name node} {
  226.     if { [string equal $node "root"] } {
  227.     # Can't delete the special root node
  228.     error "cannot delete root node"
  229.     }
  230.     
  231.     if { ![_exists $name $node] } {
  232.     error "node \"$node\" does not exist in tree \"$name\""
  233.     }
  234.  
  235.     upvar ::struct::tree::tree${name}::children children
  236.     upvar ::struct::tree::tree${name}::parent parent
  237.  
  238.     # Remove this node from its parent's children list
  239.     set parentNode $parent($node)
  240.     set index [lsearch -exact $children($parentNode) $node]
  241.     set children($parentNode) [lreplace $children($parentNode) $index $index]
  242.  
  243.     # Yes, we could use the stack structure implemented in ::struct::stack,
  244.     # but it's slower than inlining it.  Since we don't need a sophisticated
  245.     # stack, don't bother.
  246.     set st [list ]
  247.     foreach child $children($node) {
  248.     lappend st $child
  249.     }
  250.  
  251.     unset children($node)
  252.     unset parent($node)
  253.     # FRINK: nocheck
  254.     unset ::struct::tree::tree${name}::node$node
  255.  
  256.     while { [llength $st] > 0 } {
  257.     set node [lindex $st end]
  258.     set st [lreplace $st end end]
  259.     foreach child $children($node) {
  260.         lappend st $child
  261.     }
  262.     unset children($node)
  263.     unset parent($node)
  264.     # FRINK: nocheck
  265.     unset ::struct::tree::tree${name}::node$node
  266.     }
  267.     return
  268. }
  269.  
  270. # ::struct::tree::_depth --
  271. #
  272. #    Return the depth (distance from the root node) of a given node.
  273. #
  274. # Arguments:
  275. #    name    Name of the tree.
  276. #    node    Node to find.
  277. #
  278. # Results:
  279. #    depth    Number of steps from node to the root node.
  280.  
  281. proc ::struct::tree::_depth {name node} {
  282.     if { ![_exists $name $node] } {
  283.     error "node \"$node\" does not exist in tree \"$name\""
  284.     }
  285.     upvar ::struct::tree::tree${name}::parent parent
  286.     set depth 0
  287.     while { ![string equal $node "root"] } {
  288.     incr depth
  289.     set node $parent($node)
  290.     }
  291.     return $depth
  292. }
  293.  
  294. # ::struct::tree::_destroy --
  295. #
  296. #    Destroy a tree, including its associated command and data storage.
  297. #
  298. # Arguments:
  299. #    name    Name of the tree to destroy.
  300. #
  301. # Results:
  302. #    None.
  303.  
  304. proc ::struct::tree::_destroy {name} {
  305.     namespace delete ::struct::tree::tree$name
  306.     interp alias {} ::$name {}
  307. }
  308.  
  309. # ::struct::tree::_exists --
  310. #
  311. #    Test for existance of a given node in a tree.
  312. #
  313. # Arguments:
  314. #    name    Name of the tree to query.
  315. #    node    Node to look for.
  316. #
  317. # Results:
  318. #    1 if the node exists, 0 else.
  319.  
  320. proc ::struct::tree::_exists {name node} {
  321.     return [info exists ::struct::tree::tree${name}::parent($node)]
  322. }
  323.  
  324. # ::struct::tree::__generateUniqueNodeName --
  325. #
  326. #    Generate a unique node name for the given tree.
  327. #
  328. # Arguments:
  329. #    name    Name of the tree to generate a unique node name for.
  330. #
  331. # Results:
  332. #    node    Name of a node guaranteed to not exist in the tree.
  333.  
  334. proc ::struct::tree::__generateUniqueNodeName {name} {
  335.     upvar ::struct::tree::tree${name}::nextUnusedNode nextUnusedNode
  336.     while {[_exists $name "node${nextUnusedNode}"]} {
  337.     incr nextUnusedNode
  338.     }
  339.     return "node${nextUnusedNode}"
  340. }
  341.  
  342. # ::struct::tree::_get --
  343. #
  344. #    Get a keyed value from a node in a tree.
  345. #
  346. # Arguments:
  347. #    name    Name of the tree.
  348. #    node    Node to query.
  349. #    flag    Optional flag specifier; if present, must be "-key".
  350. #    key    Optional key to lookup; defaults to data.
  351. #
  352. # Results:
  353. #    value    Value associated with the key given.
  354.  
  355. proc ::struct::tree::_get {name node {flag -key} {key data}} {
  356.     if { ![_exists $name $node] } {
  357.     error "node \"$node\" does not exist in tree \"$name\""
  358.     }
  359.     
  360.     upvar ::struct::tree::tree${name}::node${node} data
  361.     if { ![info exists data($key)] } {
  362.     error "invalid key \"$key\" for node \"$node\""
  363.     }
  364.     return $data($key)
  365. }
  366.  
  367. # ::struct::tree::_index --
  368. #
  369. #    Determine the index of node with in its parent's list of children.
  370. #
  371. # Arguments:
  372. #    name    Name of the tree.
  373. #    node    Node to look up.
  374. #
  375. # Results:
  376. #    index    The index of the node in its parent
  377.  
  378. proc ::struct::tree::_index {name node} {
  379.     if { [string equal $node "root"] } {
  380.     # The special root node has no parent, thus no index in it either.
  381.     error "cannot determine index of root node"
  382.     }
  383.     
  384.     if { ![_exists $name $node] } {
  385.     error "node \"$node\" does not exist in tree \"$name\""
  386.     }
  387.  
  388.     upvar ::struct::tree::tree${name}::children children
  389.     upvar ::struct::tree::tree${name}::parent   parent
  390.  
  391.     # Locate the parent and ourself in its list of children
  392.     set parentNode $parent($node)
  393.  
  394.     return [lsearch -exact $children($parentNode) $node]
  395. }
  396.  
  397. # ::struct::tree::_insert --
  398. #
  399. #    Add a node to a tree; if the node(s) specified already exist, they
  400. #    will be moved to the given location.
  401. #
  402. # Arguments:
  403. #    name        Name of the tree.
  404. #    parentNode    Parent to add the node to.
  405. #    index        Index at which to insert.
  406. #    args        Node(s) to insert.  If none is given, the routine
  407. #            will insert a single node with a unique name.
  408. #
  409. # Results:
  410. #    nodes        List of nodes inserted.
  411.  
  412. proc ::struct::tree::_insert {name parentNode index args} {
  413.     if { [llength $args] == 0 } {
  414.     # No node name was given; generate a unique one
  415.     set args [list [__generateUniqueNodeName $name]]
  416.     }
  417.  
  418.     if { ![_exists $name $parentNode] } {
  419.     error "parent node \"$parentNode\" does not exist in tree \"$name\""
  420.     }
  421.  
  422.     upvar ::struct::tree::tree${name}::parent parent
  423.     upvar ::struct::tree::tree${name}::children children
  424.     
  425.     # Make sure the index is numeric
  426.     if { ![string is integer $index] } {
  427.     # If the index is not numeric, make it numeric by lsearch'ing for
  428.     # the value at index, then incrementing index (because "end" means
  429.     # just past the end for inserts)
  430.     set val [lindex $children($parentNode) $index]
  431.     set index [expr {[lsearch -exact $children($parentNode) $val] + 1}]
  432.     }
  433.  
  434.     foreach node $args {
  435.     if { [_exists $name $node] } {
  436.         # Move the node to its new home
  437.         if { [string equal $node "root"] } {
  438.         error "cannot move root node"
  439.         }
  440.         
  441.         # Cannot make a node its own descendant (I'm my own grandpaw...)
  442.         set ancestor $parentNode
  443.         while { ![string equal $ancestor "root"] } {
  444.         if { [string equal $ancestor $node] } {
  445.             error "node \"$node\" cannot be its own descendant"
  446.         }
  447.         set ancestor $parent($ancestor)
  448.         }
  449.         # Remove this node from its parent's children list
  450.         set oldParent $parent($node)
  451.         set ind [lsearch -exact $children($oldParent) $node]
  452.         set children($oldParent) [lreplace $children($oldParent) $ind $ind]
  453.         
  454.         # If the node is moving within its parent, and its old location
  455.         # was before the new location, decrement the new location, so that
  456.         # it gets put in the right spot
  457.         if { [string equal $oldParent $parentNode] && $ind < $index } {
  458.         incr index -1
  459.         }
  460.     } else {
  461.         # Set up the new node
  462.         upvar ::struct::tree::tree${name}::node${node} data
  463.         set children($node) [list ]
  464.         set data(data) ""
  465.     }
  466.  
  467.     # Add this node to its parent's children list
  468.     set children($parentNode) [linsert $children($parentNode) $index $node]
  469.  
  470.     # Update the parent pointer for this node
  471.     set parent($node) $parentNode
  472.     incr index
  473.     }
  474.  
  475.     return $args
  476. }
  477.  
  478. # ::struct::tree::_isleaf --
  479. #
  480. #    Return whether the given node of a tree is a leaf or not.
  481. #
  482. # Arguments:
  483. #    name    Name of the tree object.
  484. #    node    Node to look up.
  485. #
  486. # Results:
  487. #    isleaf    True if the node is a leaf; false otherwise.
  488.  
  489. proc ::struct::tree::_isleaf {name node} {
  490.     if { ![_exists $name $node] } {
  491.     error "node \"$node\" does not exist in tree \"$name\""
  492.     }
  493.     
  494.     upvar ::struct::tree::tree${name}::children children
  495.     return [expr {[llength $children($node)] == 0}]
  496. }
  497.  
  498. # ::struct::tree::_move --
  499. #
  500. #    Move a node (and all its subnodes) from where ever it is to a new
  501. #    location in the tree.
  502. #
  503. # Arguments:
  504. #    name        Name of the tree
  505. #    parentNode    Parent to add the node to.
  506. #    index        Index at which to insert.
  507. #    node        Node to move; the node must exist in the tree.
  508. #    args        Additional nodes to move; these nodes must exist
  509. #            in the tree.
  510. #
  511. # Results:
  512. #    None.
  513.  
  514. proc ::struct::tree::_move {name parentNode index node args} {
  515.     set args [linsert $args 0 $node]
  516.  
  517.     # Can only move a node to a real location in the tree
  518.     if { ![_exists $name $parentNode] } {
  519.     error "parent node \"$parentNode\" does not exist in tree \"$name\""
  520.     }
  521.  
  522.     upvar ::struct::tree::tree${name}::parent parent
  523.     upvar ::struct::tree::tree${name}::children children
  524.     
  525.     # Make sure the index is numeric
  526.     if { ![string is integer $index] } {
  527.     # If the index is not numeric, make it numeric by lsearch'ing for
  528.     # the value at index, then incrementing index (because "end" means
  529.     # just past the end for inserts)
  530.     set val [lindex $children($parentNode) $index]
  531.     set index [expr {[lsearch -exact $children($parentNode) $val] + 1}]
  532.     }
  533.  
  534.     foreach node $args {
  535.     if { [string equal $node "root"] } {
  536.         error "cannot move root node"
  537.     }
  538.  
  539.     # Can only move real nodes
  540.     if { ![_exists $name $node] } {
  541.         error "node \"$node\" does not exist in tree \"$name\""
  542.     }
  543.  
  544.     # Cannot move a node to be a descendant of itself
  545.     set ancestor $parentNode
  546.     while { ![string equal $ancestor "root"] } {
  547.         if { [string equal $ancestor $node] } {
  548.         error "node \"$node\" cannot be its own descendant"
  549.         }
  550.         set ancestor $parent($ancestor)
  551.     }
  552.     
  553.     # Remove this node from its parent's children list
  554.     set oldParent $parent($node)
  555.     set ind [lsearch -exact $children($oldParent) $node]
  556.     set children($oldParent) [lreplace $children($oldParent) $ind $ind]
  557.  
  558.     # Update the nodes parent value
  559.     set parent($node) $parentNode
  560.  
  561.     # If the node is moving within its parent, and its old location
  562.     # was before the new location, decrement the new location, so that
  563.     # it gets put in the right spot
  564.     if { [string equal $oldParent $parentNode] && $ind < $index } {
  565.         incr index -1
  566.     }
  567.  
  568.     # Add this node to its parent's children list
  569.     set children($parentNode) [linsert $children($parentNode) $index $node]
  570.     
  571.     incr index
  572.     }
  573.  
  574.     return
  575. }
  576.  
  577. # ::struct::tree::_next --
  578. #
  579. #    Return the right sibling for a given node of a tree.
  580. #
  581. # Arguments:
  582. #    name        Name of the tree object.
  583. #    node        Node to retrieve right sibling for.
  584. #
  585. # Results:
  586. #    sibling        The right sibling for the node, or null if node was
  587. #            the rightmost child of its parent.
  588.  
  589. proc ::struct::tree::_next {name node} {
  590.     # The 'root' has no siblings.
  591.     if { [string equal $node "root"] } {
  592.     return {}
  593.     }
  594.     
  595.     if { ![_exists $name $node] } {
  596.     error "node \"$node\" does not exist in tree \"$name\""
  597.     }
  598.     
  599.     # Locate the parent and our place in its list of children.
  600.     upvar ::struct::tree::tree${name}::parent   parent
  601.     upvar ::struct::tree::tree${name}::children children
  602.     
  603.     set parentNode $parent($node)
  604.     set  index [lsearch -exact $children($parentNode) $node]
  605.     
  606.     # Go to the node to the right and return its name.
  607.     return [lindex $children($parentNode) [incr index]]
  608. }
  609.  
  610. # ::struct::tree::_numchildren --
  611. #
  612. #    Return the number of immediate children for a given node of a tree.
  613. #
  614. # Arguments:
  615. #    name        Name of the tree object.
  616. #    node        Node to look up.
  617. #
  618. # Results:
  619. #    numchildren    Number of immediate children for the node.
  620.  
  621. proc ::struct::tree::_numchildren {name node} {
  622.     if { ![_exists $name $node] } {
  623.     error "node \"$node\" does not exist in tree \"$name\""
  624.     }
  625.     
  626.     upvar ::struct::tree::tree${name}::children children
  627.     return [llength $children($node)]
  628. }
  629.  
  630. # ::struct::tree::_parent --
  631. #
  632. #    Return the name of the parent node of a node in a tree.
  633. #
  634. # Arguments:
  635. #    name    Name of the tree.
  636. #    node    Node to look up.
  637. #
  638. # Results:
  639. #    parent    Parent of node $node
  640.  
  641. proc ::struct::tree::_parent {name node} {
  642.     if { ![_exists $name $node] } {
  643.     error "node \"$node\" does not exist in tree \"$name\""
  644.     }
  645.     # FRINK: nocheck
  646.     return [set ::struct::tree::tree${name}::parent($node)]
  647. }
  648.  
  649. # ::struct::tree::_previous --
  650. #
  651. #    Return the left sibling for a given node of a tree.
  652. #
  653. # Arguments:
  654. #    name        Name of the tree object.
  655. #    node        Node to look up.
  656. #
  657. # Results:
  658. #    sibling        The left sibling for the node, or null if node was 
  659. #            the leftmost child of its parent.
  660.  
  661. proc ::struct::tree::_previous {name node} {
  662.     # The 'root' has no siblings.
  663.     if { [string equal $node "root"] } {
  664.     return {}
  665.     }
  666.     
  667.     if { ![_exists $name $node] } {
  668.     error "node \"$node\" does not exist in tree \"$name\""
  669.     }
  670.     
  671.     # Locate the parent and our place in its list of children.
  672.     upvar ::struct::tree::tree${name}::parent   parent
  673.     upvar ::struct::tree::tree${name}::children children
  674.     
  675.     set parentNode $parent($node)
  676.     set  index [lsearch -exact $children($parentNode) $node]
  677.     
  678.     # Go to the node to the right and return its name.
  679.     return [lindex $children($parentNode) [incr index -1]]
  680. }
  681.  
  682. # ::struct::tree::_set --
  683. #
  684. #    Set or get a value for a node in a tree.
  685. #
  686. # Arguments:
  687. #    name    Name of the tree.
  688. #    node    Node to modify or query.
  689. #    args    Optional arguments specifying a key and a value.  Format is
  690. #            ?-key key? ?value?
  691. #        If no key is specified, the key "data" is used.
  692. #
  693. # Results:
  694. #    val    Value associated with the given key of the given node
  695.  
  696. proc ::struct::tree::_set {name node args} {
  697.     if { ![_exists $name $node] } {
  698.     error "node \"$node\" does not exist in tree \"$name\""
  699.     }
  700.     upvar ::struct::tree::tree${name}::node$node data
  701.  
  702.     if { [llength $args] > 3 } {
  703.     error "wrong # args: should be \"$name set $node ?-key key?\
  704.         ?value?\""
  705.     }
  706.     
  707.     set key "data"
  708.     set haveValue 0
  709.     if { [llength $args] > 1 } {
  710.     foreach {flag key} $args break
  711.     if { ![string match "${flag}*" "-key"] } {
  712.         error "invalid option \"$flag\": should be key"
  713.     }
  714.     if { [llength $args] == 3 } {
  715.         set haveValue 1
  716.         set value [lindex $args end]
  717.     }
  718.     } elseif { [llength $args] == 1 } {
  719.     set haveValue 1
  720.     set value [lindex $args end]
  721.     }
  722.  
  723.     if { $haveValue } {
  724.     # Setting a value
  725.     return [set data($key) $value]
  726.     } else {
  727.     # Getting a value
  728.     if { ![info exists data($key)] } {
  729.         error "invalid key \"$key\" for node \"$node\""
  730.     }
  731.     return $data($key)
  732.     }
  733. }
  734.  
  735. # ::struct::tree::_size --
  736. #
  737. #    Return the number of descendants of a given node.  The default node
  738. #    is the special root node.
  739. #
  740. # Arguments:
  741. #    name    Name of the tree.
  742. #    node    Optional node to start counting from (default is root).
  743. #
  744. # Results:
  745. #    size    Number of descendants of the node.
  746.  
  747. proc ::struct::tree::_size {name {node root}} {
  748.     if { ![_exists $name $node] } {
  749.     error "node \"$node\" does not exist in tree \"$name\""
  750.     }
  751.     
  752.     # If the node is the root, we can do the cheap thing and just count the
  753.     # number of nodes (excluding the root node) that we have in the tree with
  754.     # array names
  755.     if { [string equal $node "root"] } {
  756.     set size [llength [array names ::struct::tree::tree${name}::parent]]
  757.     return [expr {$size - 1}]
  758.     }
  759.  
  760.     # Otherwise we have to do it the hard way and do a full tree search
  761.     upvar ::struct::tree::tree${name}::children children
  762.     set size 0
  763.     set st [list ]
  764.     foreach child $children($node) {
  765.     lappend st $child
  766.     }
  767.     while { [llength $st] > 0 } {
  768.     set node [lindex $st end]
  769.     set st [lreplace $st end end]
  770.     incr size
  771.     foreach child $children($node) {
  772.         lappend st $child
  773.     }
  774.     }
  775.     return $size
  776. }
  777.  
  778. # ::struct::tree::_splice --
  779. #
  780. #    Add a node to a tree, making a range of children from the given 
  781. #    parent children of the new node.
  782. #
  783. # Arguments:
  784. #    name        Name of the tree.
  785. #    parentNode    Parent to add the node to.
  786. #    from        Index at which to insert.
  787. #    to        Optional end of the range of children to replace.
  788. #            Defaults to 'end'.
  789. #    node        Optional node name; if given, must be unique.  If not
  790. #            given, a unique name will be generated.
  791. #
  792. # Results:
  793. #    node        Name of the node added to the tree.
  794.  
  795. proc ::struct::tree::_splice {name parentNode from {to end} args} {
  796.     if { [llength $args] == 0 } {
  797.     # No node name given; generate a unique node name
  798.     set node [__generateUniqueNodeName $name]
  799.     } else {
  800.     set node [lindex $args 0]
  801.     }
  802.  
  803.     if { [_exists $name $node] } {
  804.     error "node \"$node\" already exists in tree \"$name\""
  805.     }
  806.     
  807.     upvar ::struct::tree::tree${name}::children children
  808.     upvar ::struct::tree::tree${name}::parent   parent
  809.  
  810.     # Save the list of children that are moving
  811.     set moveChildren [lrange $children($parentNode) $from $to]
  812.     
  813.     # Remove those children from the parent
  814.     set children($parentNode) [lreplace $children($parentNode) $from $to]
  815.  
  816.     # Add the new node
  817.     _insert $name $parentNode $from $node
  818.     
  819.     # Move the children
  820.     set children($node) $moveChildren
  821.     foreach child $moveChildren {
  822.     set parent($child) $node
  823.     }
  824.     
  825.     return $node
  826. }
  827.  
  828. # ::struct::tree::_swap --
  829. #
  830. #    Swap two nodes in a tree.
  831. #
  832. # Arguments:
  833. #    name    Name of the tree.
  834. #    node1    First node to swap.
  835. #    node2    Second node to swap.
  836. #
  837. # Results:
  838. #    None.
  839.  
  840. proc ::struct::tree::_swap {name node1 node2} {
  841.     # Can't swap the magic root node
  842.     if { [string equal $node1 "root"] || [string equal $node2 "root"] } {
  843.     error "cannot swap root node"
  844.     }
  845.     
  846.     # Can only swap two real nodes
  847.     if { ![_exists $name $node1] } {
  848.     error "node \"$node1\" does not exist in tree \"$name\""
  849.     }
  850.     if { ![_exists $name $node2] } {
  851.     error "node \"$node2\" does not exist in tree \"$name\""
  852.     }
  853.  
  854.     # Can't swap a node with itself
  855.     if { [string equal $node1 $node2] } {
  856.     error "cannot swap node \"$node1\" with itself"
  857.     }
  858.  
  859.     # Swapping nodes means swapping their labels and values
  860.     upvar ::struct::tree::tree${name}::children children
  861.     upvar ::struct::tree::tree${name}::parent parent
  862.     upvar ::struct::tree::tree${name}::node${node1} node1Vals
  863.     upvar ::struct::tree::tree${name}::node${node2} node2Vals
  864.  
  865.     set parent1 $parent($node1)
  866.     set parent2 $parent($node2)
  867.  
  868.     # Replace node1 with node2 in node1's parent's children list, and
  869.     # node2 with node1 in node2's parent's children list
  870.     set i1 [lsearch -exact $children($parent1) $node1]
  871.     set i2 [lsearch -exact $children($parent2) $node2]
  872.  
  873.     set children($parent1) [lreplace $children($parent1) $i1 $i1 $node2]
  874.     set children($parent2) [lreplace $children($parent2) $i2 $i2 $node1]
  875.     
  876.     # Make node1 the parent of node2's children, and vis versa
  877.     foreach child $children($node2) {
  878.     set parent($child) $node1
  879.     }
  880.     foreach child $children($node1) {
  881.     set parent($child) $node2
  882.     }
  883.     
  884.     # Swap the children lists
  885.     set children1 $children($node1)
  886.     set children($node1) $children($node2)
  887.     set children($node2) $children1
  888.  
  889.     if { [string equal $node1 $parent2] } {
  890.     set parent($node1) $node2
  891.     set parent($node2) $parent1
  892.     } elseif { [string equal $node2 $parent1] } {
  893.     set parent($node1) $parent2
  894.     set parent($node2) $node1
  895.     } else {
  896.     set parent($node1) $parent2
  897.     set parent($node2) $parent1
  898.     }
  899.  
  900.     # Swap the values
  901.     set value1 [array get node1Vals]
  902.     unset node1Vals
  903.     array set node1Vals [array get node2Vals]
  904.     unset node2Vals
  905.     array set node2Vals $value1
  906.  
  907.     return
  908. }
  909.  
  910. # ::struct::tree::_unset --
  911. #
  912. #    Remove a keyed value from a node.
  913. #
  914. # Arguments:
  915. #    name    Name of the tree.
  916. #    node    Node to modify.
  917. #    args    Optional additional args specifying which key to unset;
  918. #        if given, must be of the form "-key key".  If not given,
  919. #        the key "data" is unset.
  920. #
  921. # Results:
  922. #    None.
  923.  
  924. proc ::struct::tree::_unset {name node {flag -key} {key data}} {
  925.     if { ![_exists $name $node] } {
  926.     error "node \"$node\" does not exist in tree \"$name\""
  927.     }
  928.     
  929.     if { ![string match "${flag}*" "-key"] } {
  930.     error "invalid option \"$flag\": should be \"$name unset\
  931.         $node ?-key key?\""
  932.     }
  933.  
  934.     upvar ::struct::tree::tree${name}::node${node} data
  935.     if { [info exists data($key)] } {
  936.     unset data($key)
  937.     }
  938.     return
  939. }
  940.  
  941. # ::struct::tree::_walk --
  942. #
  943. #    Walk a tree using a pre-order depth or breadth first
  944. #    search. Pre-order DFS is the default.  At each node that is visited,
  945. #    a command will be called with the name of the tree and the node.
  946. #
  947. # Arguments:
  948. #    name    Name of the tree.
  949. #    node    Node at which to start.
  950. #    args    Optional additional arguments specifying the type and order of
  951. #        the tree walk, and the command to execute at each node.
  952. #        Format is
  953. #            ?-type {bfs|dfs}? ?-order {pre|post|in|both}? -command cmd
  954. #
  955. # Results:
  956. #    None.
  957.  
  958. proc ::struct::tree::_walk {name node args} {
  959.     set usage "$name walk $node ?-type {bfs|dfs}? ?-order {pre|post|in|both}? -command cmd"
  960.  
  961.     if {[llength $args] > 6 || [llength $args] < 2} {
  962.     error "wrong # args: should be \"$usage\""
  963.     }
  964.  
  965.     if { ![_exists $name $node] } {
  966.     error "node \"$node\" does not exist in tree \"$name\""
  967.     }
  968.  
  969.     # Set defaults
  970.     set type dfs
  971.     set order pre
  972.     set cmd ""
  973.  
  974.     for {set i 0} {$i < [llength $args]} {incr i} {
  975.     set flag [lindex $args $i]
  976.     incr i
  977.     if { $i >= [llength $args] } {
  978.         error "value for \"$flag\" missing: should be \"$usage\""
  979.     }
  980.     switch -glob -- $flag {
  981.         "-type" {
  982.         set type [string tolower [lindex $args $i]]
  983.         }
  984.         "-order" {
  985.         set order [string tolower [lindex $args $i]]
  986.         }
  987.         "-command" {
  988.         set cmd [lindex $args $i]
  989.         }
  990.         default {
  991.         error "unknown option \"$flag\": should be \"$usage\""
  992.         }
  993.     }
  994.     }
  995.     
  996.     # Make sure we have a command to run, otherwise what's the point?
  997.     if { [string equal $cmd ""] } {
  998.     error "no command specified: should be \"$usage\""
  999.     }
  1000.  
  1001.     # Validate that the given type is good
  1002.     switch -glob -- $type {
  1003.     "dfs" {
  1004.         set type "dfs"
  1005.     }
  1006.     "bfs" {
  1007.         set type "bfs"
  1008.     }
  1009.     default {
  1010.         error "invalid search type \"$type\": should be dfs, or bfs"
  1011.     }
  1012.     }
  1013.     
  1014.     # Validate that the given order is good
  1015.     switch -glob -- $order {
  1016.     "pre" {
  1017.         set order pre
  1018.     }
  1019.     "post" {
  1020.         set order post
  1021.     }
  1022.     "in" {
  1023.         set order in
  1024.     }
  1025.     "both" {
  1026.         set order both
  1027.     }
  1028.     default {
  1029.         error "invalid search order \"$order\":\
  1030.             should be pre, post, both, or in"
  1031.     }
  1032.     }
  1033.  
  1034.     if {[string equal $order "in"] && [string equal $type "bfs"]} {
  1035.     error "unable to do a ${order}-order breadth first walk"
  1036.     }
  1037.  
  1038.     # Do the walk
  1039.     upvar ::struct::tree::tree${name}::children children
  1040.     set st [list ]
  1041.     lappend st $node
  1042.  
  1043.     # Compute some flags for the possible places of command evaluation
  1044.     set leave [expr {[string equal $order post] \
  1045.         || [string equal $order both]}]
  1046.     set enter [expr {[string equal $order pre] \
  1047.         || [string equal $order both]}]
  1048.     set touch [string equal $order in]
  1049.  
  1050.     if {$leave} {
  1051.     set lvlabel leave
  1052.     } elseif {$touch} {
  1053.     # in-order does not provide a sense
  1054.     # of nesting for the parent, hence
  1055.     # no enter/leave, just 'visit'.
  1056.     set lvlabel visit
  1057.     }
  1058.  
  1059.     if { [string equal $type "dfs"] } {
  1060.     # Depth-first walk, several orders of visiting nodes
  1061.     # (pre, post, both, in)
  1062.  
  1063.     array set visited {}
  1064.  
  1065.     while { [llength $st] > 0 } {
  1066.         set node [lindex $st end]
  1067.  
  1068.         if {[info exists visited($node)]} {
  1069.         # Second time we are looking at this 'node'.
  1070.         # Pop it, then evaluate the command (post, both, in).
  1071.  
  1072.         set st [lreplace $st end end]
  1073.  
  1074.         if {$leave || $touch} {
  1075.             # Evaluate the command at this node
  1076.             WalkCall $name $node $lvlabel $cmd
  1077.         }
  1078.         } else {
  1079.         # First visit of this 'node'.
  1080.         # Do *not* pop it from the stack so that we are able
  1081.         # to visit again after its children
  1082.  
  1083.         # Remember it.
  1084.         set visited($node) .
  1085.  
  1086.         if {$enter} {
  1087.             # Evaluate the command at this node (pre, both)
  1088.             WalkCall $name $node "enter" $cmd
  1089.         }
  1090.  
  1091.         # Add the children of this node to the stack.
  1092.         # The exact behaviour depends on the chosen
  1093.         # order. For pre, post, both-order we just
  1094.         # have to add them in reverse-order so that
  1095.         # they will be popped left-to-right. For in-order
  1096.         # we have rearrange the stack so that the parent
  1097.         # is revisited immediately after the first child.
  1098.         # (but only if there is ore than one child,)
  1099.  
  1100.         set clist        $children($node)
  1101.         set len [llength $clist]
  1102.  
  1103.         if {$touch && ($len > 1)} {
  1104.             # Pop node from stack, insert into list of children
  1105.             set st    [lreplace $st end end]
  1106.             set clist [linsert $clist 1 $node]
  1107.             incr len
  1108.         }
  1109.  
  1110.         for {set i [expr {$len - 1}]} {$i >= 0} {incr i -1} {
  1111.             lappend st [lindex $clist $i]
  1112.         }
  1113.         }
  1114.     }
  1115.     } else {
  1116.     # Breadth first walk (pre, post, both)
  1117.     # No in-order possible. Already captured.
  1118.  
  1119.     if {$leave} {
  1120.         set backward $st
  1121.     }
  1122.  
  1123.     while { [llength $st] > 0 } {
  1124.         set node [lindex   $st 0]
  1125.         set st   [lreplace $st 0 0]
  1126.  
  1127.         if {$enter} {
  1128.         # Evaluate the command at this node
  1129.         WalkCall $name $node "enter" $cmd
  1130.         }
  1131.  
  1132.         # Add this node's children
  1133.         # And create a mirrored version in case of post/both order.
  1134.  
  1135.         foreach child $children($node) {
  1136.         lappend st $child
  1137.         if {$leave} {
  1138.             set backward [linsert $backward 0 $child]
  1139.         }
  1140.         }
  1141.     }
  1142.  
  1143.     if {$leave} {
  1144.         foreach node $backward {
  1145.         # Evaluate the command at this node
  1146.         WalkCall $name $node "leave" $cmd
  1147.         }
  1148.     }
  1149.     }
  1150.     return
  1151. }
  1152.  
  1153. # ::struct::tree::WalkCall --
  1154. #
  1155. #    Helper command to 'walk' handling the evaluation
  1156. #    of the user-specified command. Information about
  1157. #    the tree, node and current action are substituted
  1158. #    into the command before it evaluation.
  1159. #
  1160. # Arguments:
  1161. #    tree    Tree we are walking
  1162. #    node    Node we are at.
  1163. #    action    The current action.
  1164. #    cmd    The command to call, already partially substituted.
  1165. #
  1166. # Results:
  1167. #    None.
  1168.  
  1169. proc ::struct::tree::WalkCall {tree node action cmd} {
  1170.     uplevel 3 [string map [list \
  1171.         %n [list $node]    \
  1172.         %a [list $action]    \
  1173.         %t [list $tree]    \
  1174.         %% %]         \
  1175.         $cmd]
  1176.     return
  1177. }
  1178.