00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 package require Tcl 8.2
00013
00014 namespace ::struct {}
00015
00016 namespace ::struct::tree {
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 variable counter 0
00034
00035
00036 namespace export tree
00037 }
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 ret ::struct::tree::tree (optional name ="") {
00051 variable counter
00052
00053 if {[llength [info level 0]] == 1} {
00054 incr counter
00055 set name "tree${counter}"
00056 }
00057 # FIRST, qualify the name.
00058 if {![string match "::*" $name]} {
00059 # Get caller's namespace; append :: if not global namespace.
00060 set ns [uplevel 1 namespace current]
00061 if {"::" != $ns} {
00062 append ns "::"
00063 }
00064
00065 set name "$ns$name"
00066 }
00067 if {[llength [info commands $name]]} {
00068 return -code error \
00069 "command \"$name\" already exists, unable to create tree"
00070 }
00071
00072 # Set up the namespace for the object,
00073 # identical to the object command.
00074 namespace eval $name {
00075 # Set up root node's child list
00076 variable children
00077 set children(root) [list]
00078
00079 # Set root node's parent
00080 variable parent
00081 set parent(root) [list]
00082
00083 # Set up the node attribute mapping
00084 variable attribute
00085 array set attribute {}
00086
00087 # Set up a counter for use in creating unique node names
00088 variable nextUnusedNode
00089 set nextUnusedNode 1
00090
00091 # Set up a counter for use in creating node attribute arrays.
00092 variable nextAttr
00093 set nextAttr 0
00094 }
00095
00096 # Create the command to manipulate the tree
00097 interp alias {} ::$name {} ::struct::tree::TreeProc $name
00098
00099 return $name
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 ret ::struct::tree::TreeProc (type name , optional cmd ="" , type args) {
00118 # Do minimal args checks here
00119 if { [llength [info level 0]] == 2 } {
00120 return -code error "wrong # args: should be \"$name option ?arg arg ...?\""
00121 }
00122
00123 # Split the args into command and args components
00124 set sub _$cmd
00125 if { [llength [info commands ::struct::tree::$sub]] == 0 } {
00126 set optlist [lsort [info commands ::struct::tree::_*]]
00127 set xlist {}
00128 foreach p $optlist {
00129 set p [namespace tail $p]
00130 lappend xlist [string range $p 1 end]
00131 }
00132 set optlist [linsert [join $xlist ", "] "end-1" "or"]
00133 return -code error \
00134 "bad option \"$cmd\": must be $optlist"
00135 }
00136 return [uplevel 1 [linsert $args 0 ::struct::tree::$sub $name]]
00137 }
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 ret ::struct::tree::_children (type name , type node) {
00151 if { ![_exists $name $node] } {
00152 return -code error "node \"$node\" does not exist in tree \"$name\""
00153 }
00154
00155 variable ${name}::children
00156 return $children($node)
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 ret ::struct::tree::_cut (type name , type node) {
00173 if { [string equal $node "root"] } {
00174 # Can't delete the special root node
00175 return -code error "cannot cut root node"
00176 }
00177
00178 if { ![_exists $name $node] } {
00179 return -code error "node \"$node\" does not exist in tree \"$name\""
00180 }
00181
00182 variable ${name}::parent
00183 variable ${name}::children
00184
00185 # Locate our parent, children and our location in the parent
00186 set parentNode $parent($node)
00187 set childNodes $children($node)
00188
00189 set index [lsearch -exact $children($parentNode) $node]
00190
00191 # Excise this node from the parent list,
00192 set newChildren [lreplace $children($parentNode) $index $index]
00193
00194 # Put each of the children of $node into the parent's children list,
00195 # in the place of $node, and update the parent pointer of those nodes.
00196 foreach child $childNodes {
00197 set newChildren [linsert $newChildren $index $child]
00198 set parent($child) $parentNode
00199 incr index
00200 }
00201 set children($parentNode) $newChildren
00202
00203 KillNode $name $node
00204 return
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 ret ::struct::tree::_delete (type name , type node) {
00220 if { [string equal $node "root"] } {
00221 # Can't delete the special root node
00222 return -code error "cannot delete root node"
00223 }
00224 if { ![_exists $name $node] } {
00225 return -code error "node \"$node\" does not exist in tree \"$name\""
00226 }
00227
00228 variable ${name}::children
00229 variable ${name}::parent
00230
00231 # Remove this node from its parent's children list
00232 set parentNode $parent($node)
00233 set index [lsearch -exact $children($parentNode) $node]
00234 set children($parentNode) [lreplace $children($parentNode) $index $index]
00235
00236 # Yes, we could use the stack structure implemented in ::struct::stack,
00237 # but it's slower than inlining it. Since we don't need a sophisticated
00238 # stack, don't bother.
00239 set st [list]
00240 foreach child $children($node) {
00241 lappend st $child
00242 }
00243
00244 KillNode $name $node
00245
00246 while { [llength $st] > 0 } {
00247 set node [lindex $st end]
00248 set st [lreplace $st end end]
00249 foreach child $children($node) {
00250 lappend st $child
00251 }
00252
00253 KillNode $name $node
00254 }
00255 return
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 ret ::struct::tree::_depth (type name , type node) {
00270 if { ![_exists $name $node] } {
00271 return -code error "node \"$node\" does not exist in tree \"$name\""
00272 }
00273 variable ${name}::parent
00274 set depth 0
00275 while { ![string equal $node "root"] } {
00276 incr depth
00277 set node $parent($node)
00278 }
00279 return $depth
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 ret ::struct::tree::_destroy (type name) {
00293 namespace delete $name
00294 interp alias {} ::$name {}
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 ret ::struct::tree::_exists (type name , type node) {
00309 return [info exists ${name}::parent($node)]
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 ret ::struct::tree::_get (type name , type node , optional flag =-key , optional key =data) {
00326 if {![_exists $name $node]} {
00327 return -code error "node \"$node\" does not exist in tree \"$name\""
00328 }
00329
00330 variable ${name}::attribute
00331 if {![info exists attribute($node)]} {
00332 # No attribute data for this node,
00333 # except for the default key 'data'.
00334
00335 if {[string equal $key data]} {
00336 return ""
00337 }
00338 return -code error "invalid key \"$key\" for node \"$node\""
00339 }
00340
00341 upvar ${name}::$attribute($node) data
00342 if {![info exists data($key)]} {
00343 return -code error "invalid key \"$key\" for node \"$node\""
00344 }
00345 return $data($key)
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 ret ::struct::tree::_getall (type name , type node , type args) {
00360 if {![_exists $name $node]} {
00361 return -code error "node \"$node\" does not exist in tree \"$name\""
00362 }
00363 if {[llength $args]} {
00364 return -code error "wrong # args: should be \"$name getall $node\""
00365 }
00366
00367 variable ${name}::attribute
00368 if {![info exists attribute($node)]} {
00369 # Only default key is present, invisibly.
00370 return {data {}}
00371 }
00372
00373 upvar ${name}::$attribute($node) data
00374 return [array get data]
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 ret ::struct::tree::_keys (type name , type node , type args) {
00389 if {![_exists $name $node]} {
00390 return -code error "node \"$node\" does not exist in tree \"$name\""
00391 }
00392 if {[llength $args]} {
00393 return -code error "wrong # args: should be \"$name keys $node\""
00394 }
00395
00396 variable ${name}::attribute
00397 if {![info exists attribute($node)]} {
00398 # No attribute data for this node,
00399 # except for the default key 'data'.
00400 return {data}
00401 }
00402
00403 upvar ${name}::$attribute($node) data
00404 return [array names data]
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 ret ::struct::tree::_keyexists (type name , type node , optional flag =-key , optional key =data) {
00421 if {![_exists $name $node]} {
00422 return -code error "node \"$node\" does not exist in tree \"$name\""
00423 }
00424 if {![string equal $flag "-key"]} {
00425 return -code error "invalid option \"$flag\": should be -key"
00426 }
00427
00428 variable ${name}::attribute
00429 if {![info exists attribute($node)]} {
00430 # No attribute data for this node,
00431 # except for the default key 'data'.
00432
00433 return [string equal $key data]
00434 }
00435
00436 upvar ${name}::$attribute($node) data
00437 return [info exists data($key)]
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 ret ::struct::tree::_index (type name , type node) {
00452 if { [string equal $node "root"] } {
00453 # The special root node has no parent, thus no index in it either.
00454 return -code error "cannot determine index of root node"
00455 }
00456
00457 if { ![_exists $name $node] } {
00458 return -code error "node \"$node\" does not exist in tree \"$name\""
00459 }
00460
00461 variable ${name}::children
00462 variable ${name}::parent
00463
00464 # Locate the parent and ourself in its list of children
00465 set parentNode $parent($node)
00466
00467 return [lsearch -exact $children($parentNode) $node]
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 ret ::struct::tree::_insert (type name , type parentNode , type index , type args) {
00486 if { [llength $args] == 0 } {
00487 # No node name was given; generate a unique one
00488 set args [list [GenerateUniqueNodeName $name]]
00489 }
00490 if { ![_exists $name $parentNode] } {
00491 return -code error "parent node \"$parentNode\" does not exist in tree \"$name\""
00492 }
00493
00494 variable ${name}::parent
00495 variable ${name}::children
00496
00497 # Make sure the index is numeric
00498 if { ![string is integer $index] } {
00499 # If the index is not numeric, make it numeric by lsearch'ing for
00500 # the value at index, then incrementing index (because "end" means
00501 # just past the end for inserts)
00502 set val [lindex $children($parentNode) $index]
00503 set index [expr {[lsearch -exact $children($parentNode) $val] + 1}]
00504 }
00505
00506 foreach node $args {
00507 if {[_exists $name $node] } {
00508 # Move the node to its new home
00509 if { [string equal $node "root"] } {
00510 return -code error "cannot move root node"
00511 }
00512
00513 # Cannot make a node its own descendant (I'm my own grandpaw...)
00514 set ancestor $parentNode
00515 while { ![string equal $ancestor "root"] } {
00516 if { [string equal $ancestor $node] } {
00517 return -code error "node \"$node\" cannot be its own descendant"
00518 }
00519 set ancestor $parent($ancestor)
00520 }
00521 # Remove this node from its parent's children list
00522 set oldParent $parent($node)
00523 set ind [lsearch -exact $children($oldParent) $node]
00524 set children($oldParent) [lreplace $children($oldParent) $ind $ind]
00525
00526 # If the node is moving within its parent, and its old location
00527 # was before the new location, decrement the new location, so that
00528 # it gets put in the right spot
00529 if { [string equal $oldParent $parentNode] && $ind < $index } {
00530 incr index -1
00531 }
00532 } else {
00533 # Set up the new node
00534 set children($node) [list]
00535 }
00536
00537 # Add this node to its parent's children list
00538 set children($parentNode) [linsert $children($parentNode) $index $node]
00539
00540 # Update the parent pointer for this node
00541 set parent($node) $parentNode
00542 incr index
00543 }
00544
00545 return $args
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559 ret ::struct::tree::_isleaf (type name , type node) {
00560 if { ![_exists $name $node] } {
00561 return -code error "node \"$node\" does not exist in tree \"$name\""
00562 }
00563
00564 variable ${name}::children
00565 return [expr {[llength $children($node)] == 0}]
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 ret ::struct::tree::_move (type name , type parentNode , type index , type node , type args) {
00585 set args [linsert $args 0 $node]
00586
00587 # Can only move a node to a real location in the tree
00588 if { ![_exists $name $parentNode] } {
00589 return -code error "parent node \"$parentNode\" does not exist in tree \"$name\""
00590 }
00591
00592 variable ${name}::parent
00593 variable ${name}::children
00594
00595 # Make sure the index is numeric
00596 if { ![string is integer $index] } {
00597 # If the index is not numeric, make it numeric by lsearch'ing for
00598 # the value at index, then incrementing index (because "end" means
00599 # just past the end for inserts)
00600 set val [lindex $children($parentNode) $index]
00601 set index [expr {[lsearch -exact $children($parentNode) $val] + 1}]
00602 }
00603
00604 # Validate all nodes to move before trying to move any.
00605 foreach node $args {
00606 if { [string equal $node "root"] } {
00607 return -code error "cannot move root node"
00608 }
00609
00610 # Can only move real nodes
00611 if { ![_exists $name $node] } {
00612 return -code error "node \"$node\" does not exist in tree \"$name\""
00613 }
00614
00615 # Cannot move a node to be a descendant of itself
00616 set ancestor $parentNode
00617 while { ![string equal $ancestor "root"] } {
00618 if { [string equal $ancestor $node] } {
00619 return -code error "node \"$node\" cannot be its own descendant"
00620 }
00621 set ancestor $parent($ancestor)
00622 }
00623 }
00624
00625 # Remove all nodes from their current parent's children list
00626 foreach node $args {
00627 set oldParent $parent($node)
00628 set ind [lsearch -exact $children($oldParent) $node]
00629
00630 set children($oldParent) [lreplace $children($oldParent) $ind $ind]
00631
00632 # Update the nodes parent value
00633 set parent($node) $parentNode
00634 }
00635
00636 # Add all nodes to their new parent's children list
00637 set children($parentNode) \
00638 [eval [list linsert $children($parentNode) $index] $args]
00639
00640 return
00641 }
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 ret ::struct::tree::_next (type name , type node) {
00656 # The 'root' has no siblings.
00657 if { [string equal $node "root"] } {
00658 return {}
00659 }
00660
00661 if { ![_exists $name $node] } {
00662 return -code error "node \"$node\" does not exist in tree \"$name\""
00663 }
00664
00665 # Locate the parent and our place in its list of children.
00666 variable ${name}::parent
00667 variable ${name}::children
00668
00669 set parentNode $parent($node)
00670 set index [lsearch -exact $children($parentNode) $node]
00671
00672 # Go to the node to the right and return its name.
00673 return [lindex $children($parentNode) [incr index]]
00674 }
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 ret ::struct::tree::_numchildren (type name , type node) {
00688 if { ![_exists $name $node] } {
00689 return -code error "node \"$node\" does not exist in tree \"$name\""
00690 }
00691
00692 variable ${name}::children
00693 return [llength $children($node)]
00694 }
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 ret ::struct::tree::_parent (type name , type node) {
00708 if { ![_exists $name $node] } {
00709 return -code error "node \"$node\" does not exist in tree \"$name\""
00710 }
00711 # FRINK: nocheck
00712 return [set ${name}::parent($node)]
00713 }
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 ret ::struct::tree::_previous (type name , type node) {
00728 # The 'root' has no siblings.
00729 if { [string equal $node "root"] } {
00730 return {}
00731 }
00732
00733 if { ![_exists $name $node] } {
00734 return -code error "node \"$node\" does not exist in tree \"$name\""
00735 }
00736
00737 # Locate the parent and our place in its list of children.
00738 variable ${name}::parent
00739 variable ${name}::children
00740
00741 set parentNode $parent($node)
00742 set index [lsearch -exact $children($parentNode) $node]
00743
00744 # Go to the node to the right and return its name.
00745 return [lindex $children($parentNode) [incr index -1]]
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 ret ::struct::tree::_serialize (type name , optional node =root) {
00760 if {![_exists $name $node]} {
00761 return -code error "node \"$node\" does not exist in tree \"$name\""
00762 }
00763 Serialize $name $node tree attr
00764 return [list $tree [array get attr]]
00765 }
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781 ret ::struct::tree::_set (type name , type node , type args) {
00782 if {![_exists $name $node]} {
00783 return -code error "node \"$node\" does not exist in tree \"$name\""
00784 }
00785 if {[llength $args] > 3} {
00786 return -code error "wrong # args: should be \"$name set [list $node] ?-key key?\
00787 ?value?\""
00788 }
00789
00790 # Process the arguments ...
00791
00792 set key "data"
00793 set haveValue 0
00794 if {[llength $args] > 1} {
00795 foreach {flag key} $args break
00796 if {![string match "${flag}*" "-key"]} {
00797 return -code error "invalid option \"$flag\": should be key"
00798 }
00799 if {[llength $args] == 3} {
00800 set haveValue 1
00801 set value [lindex $args end]
00802 }
00803 } elseif {[llength $args] == 1} {
00804 set haveValue 1
00805 set value [lindex $args end]
00806 }
00807
00808 if {$haveValue} {
00809 # Setting a value. This may have to create
00810 # the attribute array for this particular
00811 # node
00812
00813 variable ${name}::attribute
00814 if {![info exists attribute($node)]} {
00815 # No attribute data for this node,
00816 # so create it as we need it.
00817 GenAttributeStorage $name $node
00818 }
00819 upvar ${name}::$attribute($node) data
00820
00821 return [set data($key) $value]
00822 } else {
00823 # Getting a value
00824
00825 return [_get $name $node -key $key]
00826 }
00827 }
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 ret ::struct::tree::_append (type name , type node , type args) {
00844 if {![_exists $name $node]} {
00845 return -code error "node \"$node\" does not exist in tree \"$name\""
00846 }
00847 if {
00848 ([llength $args] != 1) &&
00849 ([llength $args] != 3)
00850 } {
00851 return -code error "wrong # args: should be \"$name set [list $node] ?-key key?\
00852 value\""
00853 }
00854 if {[llength $args] == 3} {
00855 foreach {flag key} $args break
00856 if {![string equal $flag "-key"]} {
00857 return -code error "invalid option \"$flag\": should be -key"
00858 }
00859 } else {
00860 set key "data"
00861 }
00862
00863 set value [lindex $args end]
00864
00865 variable ${name}::attribute
00866 if {![info exists attribute($node)]} {
00867 # No attribute data for this node,
00868 # so create it as we need it.
00869 GenAttributeStorage $name $node
00870 }
00871 upvar ${name}::$attribute($node) data
00872
00873 return [append data($key) $value]
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 ret ::struct::tree::_lappend (type name , type node , type args) {
00891 if {![_exists $name $node]} {
00892 return -code error "node \"$node\" does not exist in tree \"$name\""
00893 }
00894 if {
00895 ([llength $args] != 1) &&
00896 ([llength $args] != 3)
00897 } {
00898 return -code error "wrong # args: should be \"$name lappend [list $node] ?-key key?\
00899 value\""
00900 }
00901 if {[llength $args] == 3} {
00902 foreach {flag key} $args break
00903 if {![string equal $flag "-key"]} {
00904 return -code error "invalid option \"$flag\": should be -key"
00905 }
00906 } else {
00907 set key "data"
00908 }
00909
00910 set value [lindex $args end]
00911
00912 variable ${name}::attribute
00913 if {![info exists attribute($node)]} {
00914 # No attribute data for this node,
00915 # so create it as we need it.
00916 GenAttributeStorage $name $node
00917 }
00918 upvar ${name}::$attribute($node) data
00919
00920 return [lappend data($key) $value]
00921 }
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935 ret ::struct::tree::_size (type name , optional node =root) {
00936 if { ![_exists $name $node] } {
00937 return -code error "node \"$node\" does not exist in tree \"$name\""
00938 }
00939
00940 # If the node is the root, we can do the cheap thing and just count the
00941 # number of nodes (excluding the root node) that we have in the tree with
00942 # array names
00943 if { [string equal $node "root"] } {
00944 set size [llength [array names ${name}::parent]]
00945 return [expr {$size - 1}]
00946 }
00947
00948 # Otherwise we have to do it the hard way and do a full tree search
00949 variable ${name}::children
00950 set size 0
00951 set st [list ]
00952 foreach child $children($node) {
00953 lappend st $child
00954 }
00955 while { [llength $st] > 0 } {
00956 set node [lindex $st end]
00957 set st [lreplace $st end end]
00958 incr size
00959 foreach child $children($node) {
00960 lappend st $child
00961 }
00962 }
00963 return $size
00964 }
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 ret ::struct::tree::_splice (type name , type parentNode , type from , optional to =end , type args) {
00984 if { [llength $args] == 0 } {
00985 # No node name given; generate a unique node name
00986 set node [GenerateUniqueNodeName $name]
00987 } else {
00988 set node [lindex $args 0]
00989 }
00990
00991 if { [_exists $name $node] } {
00992 return -code error "node \"$node\" already exists in tree \"$name\""
00993 }
00994
00995 variable ${name}::children
00996 variable ${name}::parent
00997
00998 # Save the list of children that are moving
00999 set moveChildren [lrange $children($parentNode) $from $to]
01000
01001 # Remove those children from the parent
01002 set children($parentNode) [lreplace $children($parentNode) $from $to]
01003
01004 # Add the new node
01005 _insert $name $parentNode $from $node
01006
01007 # Move the children
01008 set children($node) $moveChildren
01009 foreach child $moveChildren {
01010 set parent($child) $node
01011 }
01012
01013 return $node
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 ret ::struct::tree::_swap (type name , type node1 , type node2) {
01029 # Can't swap the magic root node
01030 if {[string equal $node1 "root"] || [string equal $node2 "root"]} {
01031 return -code error "cannot swap root node"
01032 }
01033
01034 # Can only swap two real nodes
01035 if {![_exists $name $node1]} {
01036 return -code error "node \"$node1\" does not exist in tree \"$name\""
01037 }
01038 if {![_exists $name $node2]} {
01039 return -code error "node \"$node2\" does not exist in tree \"$name\""
01040 }
01041
01042 # Can't swap a node with itself
01043 if {[string equal $node1 $node2]} {
01044 return -code error "cannot swap node \"$node1\" with itself"
01045 }
01046
01047 # Swapping nodes means swapping their labels and values
01048 variable ${name}::children
01049 variable ${name}::parent
01050
01051 set parent1 $parent($node1)
01052 set parent2 $parent($node2)
01053
01054 # Replace node1 with node2 in node1's parent's children list, and
01055 # node2 with node1 in node2's parent's children list
01056 set i1 [lsearch -exact $children($parent1) $node1]
01057 set i2 [lsearch -exact $children($parent2) $node2]
01058
01059 set children($parent1) [lreplace $children($parent1) $i1 $i1 $node2]
01060 set children($parent2) [lreplace $children($parent2) $i2 $i2 $node1]
01061
01062 # Make node1 the parent of node2's children, and vis versa
01063 foreach child $children($node2) {
01064 set parent($child) $node1
01065 }
01066 foreach child $children($node1) {
01067 set parent($child) $node2
01068 }
01069
01070 # Swap the children lists
01071 set children1 $children($node1)
01072 set children($node1) $children($node2)
01073 set children($node2) $children1
01074
01075 if { [string equal $node1 $parent2] } {
01076 set parent($node1) $node2
01077 set parent($node2) $parent1
01078 } elseif { [string equal $node2 $parent1] } {
01079 set parent($node1) $parent2
01080 set parent($node2) $node1
01081 } else {
01082 set parent($node1) $parent2
01083 set parent($node2) $parent1
01084 }
01085
01086 # Swap the values
01087 # More complicated now with the possibility that nodes do not have
01088 # attribute storage associated with them.
01089
01090 variable ${name}::attribute
01091
01092 if {
01093 [set ia [info exists attribute($node1)]] ||
01094 [set ib [info exists attribute($node2)]]
01095 } {
01096 # At least one of the nodes has attribute data. We simply swap
01097 # the references to the arrays containing them. No need to
01098 # copy the actual data around.
01099
01100 if {$ia && $ib} {
01101 set tmp $attribute($node1)
01102 set attribute($node1) $attribute($node2)
01103 set attribute($node2) $tmp
01104 } elseif {$ia} {
01105 set attribute($node2) $attribute($node1)
01106 unset attribute($node1)
01107 } elseif {$ib} {
01108 set attribute($node1) $attribute($node2)
01109 unset attribute($node2)
01110 } else {
01111 return -code error "Impossible condition."
01112 }
01113 } ; # else: No attribute storage => Nothing to do {}
01114
01115 return
01116 }
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132 ret ::struct::tree::_unset (type name , type node , optional flag =-key , optional key =data) {
01133 if {![_exists $name $node]} {
01134 return -code error "node \"$node\" does not exist in tree \"$name\""
01135 }
01136 if {![string match "${flag}*" "-key"]} {
01137 return -code error "invalid option \"$flag\": should be \"$name unset\
01138 [list $node] ?-key key?\""
01139 }
01140
01141 variable ${name}::attribute
01142 if {![info exists attribute($node)]} {
01143 # No attribute data for this node,
01144 # except for the default key 'data'.
01145 GenAttributeStorage $name $node
01146 }
01147 upvar ${name}::$attribute($node) data
01148
01149 catch {unset data($key)}
01150 return
01151 }
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170 ret ::struct::tree::_walk (type name , type node , type args) {
01171 set usage "$name walk $node ?-type {bfs|dfs}? ?-order {pre|post|in|both}? -command cmd"
01172
01173 if {[llength $args] > 6 || [llength $args] < 2} {
01174 return -code error "wrong # args: should be \"$usage\""
01175 }
01176
01177 if { ![_exists $name $node] } {
01178 return -code error "node \"$node\" does not exist in tree \"$name\""
01179 }
01180
01181 # Set defaults
01182 set type dfs
01183 set order pre
01184 set cmd ""
01185
01186 for {set i 0} {$i < [llength $args]} {incr i} {
01187 set flag [lindex $args $i]
01188 incr i
01189 if { $i >= [llength $args] } {
01190 return -code error "value for \"$flag\" missing: should be \"$usage\""
01191 }
01192 switch -glob -- $flag {
01193 "-type" {
01194 set type [string tolower [lindex $args $i]]
01195 }
01196 "-order" {
01197 set order [string tolower [lindex $args $i]]
01198 }
01199 "-command" {
01200 set cmd [lindex $args $i]
01201 }
01202 default {
01203 return -code error "unknown option \"$flag\": should be \"$usage\""
01204 }
01205 }
01206 }
01207
01208 # Make sure we have a command to run, otherwise what's the point?
01209 if { [string equal $cmd ""] } {
01210 return -code error "no command specified: should be \"$usage\""
01211 }
01212
01213 # Validate that the given type is good
01214 switch -exact -- $type {
01215 "dfs" - "bfs" {
01216 set type $type
01217 }
01218 default {
01219 return -code error "invalid search type \"$type\": should be dfs, or bfs"
01220 }
01221 }
01222
01223 # Validate that the given order is good
01224 switch -exact -- $order {
01225 "pre" - "post" - "in" - "both" {
01226 set order $order
01227 }
01228 default {
01229 return -code error "invalid search order \"$order\":\
01230 should be pre, post, both, or in"
01231 }
01232 }
01233
01234 if {[string equal $order "in"] && [string equal $type "bfs"]} {
01235 return -code error "unable to do a ${order}-order breadth first walk"
01236 }
01237
01238 # Do the walk
01239 variable ${name}::children
01240 set st [list ]
01241 lappend st $node
01242
01243 # Compute some flags for the possible places of command evaluation
01244 set leave [expr {[string equal $order post] || [string equal $order both]}]
01245 set enter [expr {[string equal $order pre] || [string equal $order both]}]
01246 set touch [string equal $order in]
01247
01248 if {$leave} {
01249 set lvlabel leave
01250 } elseif {$touch} {
01251 # in-order does not provide a sense
01252 # of nesting for the parent, hence
01253 # no enter/leave, just 'visit'.
01254 set lvlabel visit
01255 }
01256
01257 if { [string equal $type "dfs"] } {
01258 # Depth-first walk, several orders of visiting nodes
01259 # (pre, post, both, in)
01260
01261 array set visited {}
01262
01263 while { [llength $st] > 0 } {
01264 set node [lindex $st end]
01265
01266 if {[info exists visited($node)]} {
01267 # Second time we are looking at this 'node'.
01268 # Pop it, then evaluate the command (post, both, in).
01269
01270 set st [lreplace $st end end]
01271
01272 if {$leave || $touch} {
01273 # Evaluate the command at this node
01274 WalkCall $name $node $lvlabel $cmd
01275 }
01276 } else {
01277 # First visit of this 'node'.
01278 # Do *not* pop it from the stack so that we are able
01279 # to visit again after its children
01280
01281 # Remember it.
01282 set visited($node) .
01283
01284 if {$enter} {
01285 # Evaluate the command at this node (pre, both)
01286 WalkCall $name $node "enter" $cmd
01287 }
01288
01289 # Add the children of this node to the stack.
01290 # The exact behaviour depends on the chosen
01291 # order. For pre, post, both-order we just
01292 # have to add them in reverse-order so that
01293 # they will be popped left-to-right. For in-order
01294 # we have rearrange the stack so that the parent
01295 # is revisited immediately after the first child.
01296 # (but only if there is ore than one child,)
01297
01298 set clist $children($node)
01299 set len [llength $clist]
01300
01301 if {$touch && ($len > 1)} {
01302 # Pop node from stack, insert into list of children
01303 set st [lreplace $st end end]
01304 set clist [linsert $clist 1 $node]
01305 incr len
01306 }
01307
01308 for {set i [expr {$len - 1}]} {$i >= 0} {incr i -1} {
01309 lappend st [lindex $clist $i]
01310 }
01311 }
01312 }
01313 } else {
01314 # Breadth first walk (pre, post, both)
01315 # No in-order possible. Already captured.
01316
01317 if {$leave} {
01318 set backward $st
01319 }
01320
01321 while { [llength $st] > 0 } {
01322 set node [lindex $st 0]
01323 set st [lreplace $st 0 0]
01324
01325 if {$enter} {
01326 # Evaluate the command at this node
01327 WalkCall $name $node "enter" $cmd
01328 }
01329
01330 # Add this node's children
01331 # And create a mirrored version in case of post/both order.
01332
01333 foreach child $children($node) {
01334 lappend st $child
01335 if {$leave} {
01336 set backward [linsert $backward 0 $child]
01337 }
01338 }
01339 }
01340
01341 if {$leave} {
01342 foreach node $backward {
01343 # Evaluate the command at this node
01344 WalkCall $name $node "leave" $cmd
01345 }
01346 }
01347 }
01348 return
01349 }
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 ret ::struct::tree::WalkCall (type tree , type node , type action , type cmd) {
01368 set subs [list %n [list $node] %a [list $action] %t [list $tree] %% %]
01369 uplevel 2 [string map $subs $cmd]
01370 return
01371 }
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383 ret ::struct::tree::GenerateUniqueNodeName (type name) {
01384 variable ${name}::nextUnusedNode
01385 while {[_exists $name "node${nextUnusedNode}"]} {
01386 incr nextUnusedNode
01387 }
01388 return "node${nextUnusedNode}"
01389 }
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402 ret ::struct::tree::KillNode (type name , type node) {
01403 variable ${name}::parent
01404 variable ${name}::children
01405 variable ${name}::attribute
01406
01407 # Remove all record of $node
01408 unset parent($node)
01409 unset children($node)
01410
01411 if {[info exists attribute($node)]} {
01412 # FRINK: nocheck
01413 unset ${name}::$attribute($node)
01414 unset attribute($node)
01415 }
01416 return
01417 }
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430 ret ::struct::tree::GenAttributeStorage (type name , type node) {
01431 variable ${name}::nextAttr
01432 variable ${name}::attribute
01433
01434 set attr "a[incr nextAttr]"
01435 set attribute($node) $attr
01436 upvar ${name}::$attr data
01437 set data(data) ""
01438 return
01439 }
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452 ret ::struct::tree::Serialize (type name , type node , type tvar , type avar) {
01453 upvar 1 $tvar tree $avar attr
01454
01455 variable ${name}::children
01456 variable ${name}::attribute
01457
01458 # Store attribute data
01459 if {[info exists attribute($node)]} {
01460 set attr($node) [array get ${name}::$attribute($node)]
01461 } else {
01462 set attr($node) {}
01463 }
01464
01465 # Build tree structure as nested list.
01466
01467 set subtrees [list]
01468 foreach c $children($node) {
01469 Serialize $name $c sub attr
01470 lappend subtrees $sub
01471 }
01472
01473 set tree [list $node $subtrees]
01474 return
01475 }
01476
01477
01478
01479
01480 namespace ::struct {
01481
01482 namespace import -force tree::tree
01483 namespace export tree
01484 }
01485 package provide struct::tree 1.2.2
01486