00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 namespace ::struct {}
00025
00026 namespace ::struct::skiplist {
00027
00028
00029
00030
00031
00032
00033
00034
00035 variable counter 0
00036
00037
00038 variable MAXLEVEL 16
00039 variable PROB .5
00040 variable MAXINT [expr {0x7FFFFFFF}]
00041
00042
00043 variable commands [list \
00044 "destroy" \
00045 "delete" \
00046 "insert" \
00047 "search" \
00048 "size" \
00049 "walk" \
00050 ]
00051
00052
00053 variable vars [list maxlevel probability]
00054
00055
00056 namespace export skiplist
00057 }
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 ret ::struct::skiplist::skiplist (optional name ="" , type args) {
00071 set usage "skiplist name ?-maxlevel ##? ?-probability ##?"
00072 variable counter
00073
00074 if { [llength [info level 0]] == 1 } {
00075 incr counter
00076 set name "skiplist${counter}"
00077 }
00078
00079 if { ![string equal [info commands ::$name] ""] } {
00080 error "command \"$name\" already exists, unable to create skiplist"
00081 }
00082
00083 # Handle the optional arguments
00084 set more_eval ""
00085 for {set i 0} {$i < [llength $args]} {incr i} {
00086 set flag [lindex $args $i]
00087 incr i
00088 if { $i >= [llength $args] } {
00089 error "value for \"$flag\" missing: should be \"$usage\""
00090 }
00091 set value [lindex $args $i]
00092 switch -glob -- $flag {
00093 "-maxl*" {
00094 set n [catch {set value [expr $value]}]
00095 if {$n || $value <= 0} {
00096 error "value for the maxlevel option must be greater than 0"
00097 }
00098 append more_eval "; set state(maxlevel) $value"
00099 }
00100 "-prob*" {
00101 set n [catch {set value [expr $value]}]
00102 if {$n || $value <= 0 || $value >= 1} {
00103 error "probability must be between 0 and 1"
00104 }
00105 append more_eval "; set state(prob) $value"
00106 }
00107 default {
00108 error "unknown option \"$flag\": should be \"$usage\""
00109 }
00110 }
00111 }
00112
00113 # Set up the namespace for this skiplist
00114 namespace eval ::struct::skiplist::skiplist$name {
00115 variable state
00116 variable nodes
00117
00118 # NB. maxlevel and prob may be overridden by $more_eval at the end
00119 set state(maxlevel) $::struct::skiplist::MAXLEVEL
00120 set state(prob) $::struct::skiplist::PROB
00121 set state(level) 1
00122 set state(cnt) 0
00123 set state(size) 0
00124
00125 set nodes(nil,key) $::struct::skiplist::MAXINT
00126 set nodes(header,key) "---"
00127 set nodes(header,value) "---"
00128
00129 for {set i 1} {$i < $state(maxlevel)} {incr i} {
00130 set nodes(header,$i) nil
00131 }
00132 } $more_eval
00133
00134 # Create the command to manipulate the skiplist
00135 interp alias {} ::$name {} ::struct::skiplist::SkiplistProc $name
00136
00137 return $name
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 ret ::struct::skiplist::SkiplistProc (type name , optional cmd ="" , type args) {
00155 # Do minimal args checks here
00156 if { [llength [info level 0]] == 2 } {
00157 error "wrong # args: should be \"$name option ?arg arg ...?\""
00158 }
00159
00160 # Split the args into command and args components
00161 if { [llength [info commands ::struct::skiplist::_$cmd]] == 0 } {
00162 variable commands
00163 set optlist [join $commands ", "]
00164 set optlist [linsert $optlist "end-1" "or"]
00165 error "bad option \"$cmd\": must be $optlist"
00166 }
00167 eval [linsert $args 0 ::struct::skiplist::_$cmd $name]
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 ret ::struct::skiplist::_destroy (type name) {
00181 namespace delete ::struct::skiplist::skiplist$name
00182 interp alias {} ::$name {}
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 ret ::struct::skiplist::_search (type name , type key) {
00198 upvar ::struct::skiplist::skiplist${name}::state state
00199 upvar ::struct::skiplist::skiplist${name}::nodes nodes
00200
00201 set x header
00202 for {set i $state(level)} {$i >= 1} {incr i -1} {
00203 while {1} {
00204 set fwd $nodes($x,$i)
00205 if {$nodes($fwd,key) == $::struct::skiplist::MAXINT} break
00206 if {$nodes($fwd,key) >= $key} break
00207 set x $fwd
00208 }
00209 }
00210 set x $nodes($x,1)
00211 if {$nodes($x,key) == $key} {
00212 return [list 1 $nodes($x,value)]
00213 }
00214 return 0
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 ret ::struct::skiplist::_insert (type name , type key , type value) {
00231 upvar ::struct::skiplist::skiplist${name}::state state
00232 upvar ::struct::skiplist::skiplist${name}::nodes nodes
00233
00234 set x header
00235 for {set i $state(level)} {$i >= 1} {incr i -1} {
00236 while {1} {
00237 set fwd $nodes($x,$i)
00238 if {$nodes($fwd,key) == $::struct::skiplist::MAXINT} break
00239 if {$nodes($fwd,key) >= $key} break
00240 set x $fwd
00241 }
00242 set update($i) $x
00243 }
00244 set x $nodes($x,1)
00245
00246 # Does the node already exist?
00247 if {$nodes($x,key) == $key} {
00248 set nodes($x,value) $value
00249 return 0
00250 }
00251
00252 # Here to insert item
00253 incr state(size)
00254 set lvl [randomLevel $state(prob) $state(level) $state(maxlevel)]
00255
00256 # Did the skip list level increase???
00257 if {$lvl > $state(level)} {
00258 for {set i [expr {$state(level) + 1}]} {$i <= $lvl} {incr i} {
00259 set update($i) header
00260 }
00261 set state(level) $lvl
00262 }
00263
00264 # Create a unique new node name and fill in the key, value parts
00265 set x [incr state(cnt)]
00266 set nodes($x,key) $key
00267 set nodes($x,value) $value
00268
00269 for {set i 1} {$i <= $lvl} {incr i} {
00270 set nodes($x,$i) $nodes($update($i),$i)
00271 set nodes($update($i),$i) $x
00272 }
00273
00274 return $lvl
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 ret ::struct::skiplist::_delete (type name , type key) {
00290 upvar ::struct::skiplist::skiplist${name}::state state
00291 upvar ::struct::skiplist::skiplist${name}::nodes nodes
00292
00293 set x header
00294 for {set i $state(level)} {$i >= 1} {incr i -1} {
00295 while {1} {
00296 set fwd $nodes($x,$i)
00297 if {$nodes($fwd,key) >= $key} break
00298 set x $fwd
00299 }
00300 set update($i) $x
00301 }
00302 set x $nodes($x,1)
00303
00304 # Did we find a node to delete?
00305 if {$nodes($x,key) != $key} {
00306 return 0
00307 }
00308
00309 # Here when we found a node to delete
00310 incr state(size) -1
00311
00312 # Unlink this node from all the linked lists that include to it
00313 for {set i 1} {$i <= $state(level)} {incr i} {
00314 set fwd $nodes($update($i),$i)
00315 if {$nodes($fwd,key) != $key} break
00316 set nodes($update($i),$i) $nodes($x,$i)
00317 }
00318
00319 # Delete all traces of this node
00320 foreach v [array names nodes($x,*)] {
00321 unset nodes($v)
00322 }
00323
00324 # Fix up the level in case it went down
00325 while {$state(level) > 1} {
00326 if {! [string equal "nil" $nodes(header,$state(level))]} break
00327 incr state(level) -1
00328 }
00329
00330 return 1
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 ret ::struct::skiplist::_size (type name) {
00344 upvar ::struct::skiplist::skiplist${name}::state state
00345
00346 return $state(size)
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 ret ::struct::skiplist::_walk (type name , type cmd) {
00363 upvar ::struct::skiplist::skiplist${name}::nodes nodes
00364
00365 for {set x $nodes(header,1)} {$x != "nil"} {set x $nodes($x,1)} {
00366 # Evaluate the command at this node
00367 set cmdcpy $cmd
00368 lappend cmdcpy $nodes($x,key) $nodes($x,value)
00369 uplevel 2 $cmdcpy
00370 }
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 ret ::struct::skiplist::randomLevel (type prob , type level , type maxlevel) {
00387
00388 set lvl 1
00389 while {(rand() < $prob) && ($lvl < $maxlevel)} {
00390 incr lvl
00391 }
00392
00393 if {$lvl > $level} {
00394 set lvl [expr {$level + 1}]
00395 }
00396
00397 return $lvl
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 ret ::struct::skiplist::_dump (type name) {
00411 upvar ::struct::skiplist::skiplist${name}::state state
00412 upvar ::struct::skiplist::skiplist${name}::nodes nodes
00413
00414
00415 puts "Current level $state(level)"
00416 puts "Maxlevel: $state(maxlevel)"
00417 puts "Probability: $state(prob)"
00418 puts ""
00419 puts "NODE KEY FORWARD"
00420 for {set x header} {$x != "nil"} {set x $nodes($x,1)} {
00421 puts -nonewline [format "%-6s %3s %4s" $x $nodes($x,key) $nodes($x,1)]
00422 for {set i 2} {[info exists nodes($x,$i)]} {incr i} {
00423 puts -nonewline [format %4s $nodes($x,$i)]
00424 }
00425 puts ""
00426 }
00427 }
00428
00429
00430
00431
00432 namespace ::struct {
00433
00434 namespace import -force skiplist::skiplist
00435 namespace export skiplist
00436 }
00437 package provide struct::skiplist 1.3
00438