stack.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 namespace ::struct {}
00013
00014 namespace ::struct::stack {
00015
00016 variable stacks
00017
00018
00019 variable counter 0
00020
00021
00022 namespace export stack
00023 }
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 ret ::struct::stack::stack (type args) {
00037 variable stacks
00038 variable counter
00039
00040 switch -exact -- [llength [info level 0]] {
00041 1 {
00042 # Missing name, generate one.
00043 incr counter
00044 set name "stack${counter}"
00045 }
00046 2 {
00047 # Standard call. New empty stack.
00048 set name [lindex $args 0]
00049 }
00050 default {
00051 # Error.
00052 return -code error \
00053 "wrong # args: should be \"stack ?name?\""
00054 }
00055 }
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 [list 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 stack"
00070 }
00071
00072 set stacks($name) [list ]
00073
00074 # Create the command to manipulate the stack
00075 interp alias {} $name {} ::struct::stack::StackProc $name
00076
00077 return $name
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 ret ::struct::stack::StackProc (type name , type cmd , type args) {
00095 # Do minimal args checks here
00096 if { [llength [info level 0]] == 2 } {
00097 return -code error "wrong # args: should be \"$name option ?arg arg ...?\""
00098 }
00099
00100 # Split the args into command and args components
00101 set sub _$cmd
00102 if { [llength [info commands ::struct::stack::$sub]] == 0 } {
00103 set optlist [lsort [info commands ::struct::stack::_*]]
00104 set xlist {}
00105 foreach p $optlist {
00106 set p [namespace tail $p]
00107 lappend xlist [string range $p 1 end]
00108 }
00109 set optlist [linsert [join $xlist ", "] "end-1" "or"]
00110 return -code error \
00111 "bad option \"$cmd\": must be $optlist"
00112 }
00113
00114 uplevel 1 [linsert $args 0 ::struct::stack::$sub $name]
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 ret ::struct::stack::_clear (type name) {
00128 set ::struct::stack::stacks($name) [list ]
00129 return
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 ret ::struct::stack::_destroy (type name) {
00144 unset ::struct::stack::stacks($name)
00145 interp alias {} $name {}
00146 return
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 ret ::struct::stack::_peek (type name , optional count =1) {
00162 variable stacks
00163 if { $count < 1 } {
00164 error "invalid item count $count"
00165 }
00166
00167 if { $count > [llength $stacks($name)] } {
00168 error "insufficient items on stack to fill request"
00169 }
00170
00171 if { $count == 1 } {
00172 # Handle this as a special case, so single item pops aren't listified
00173 set item [lindex $stacks($name) end]
00174 return $item
00175 }
00176
00177 # Otherwise, return a list of items
00178 set result [list ]
00179 for {set i 0} {$i < $count} {incr i} {
00180 lappend result [lindex $stacks($name) "end-${i}"]
00181 }
00182 return $result
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 ret ::struct::stack::_pop (type name , optional count =1) {
00198 variable stacks
00199 if { $count > [llength $stacks($name)] } {
00200 error "insufficient items on stack to fill request"
00201 } elseif { $count < 1 } {
00202 error "invalid item count $count"
00203 }
00204
00205 if { $count == 1 } {
00206 # Handle this as a special case, so single item pops aren't listified
00207 set item [lindex $stacks($name) end]
00208 set stacks($name) [lreplace $stacks($name) end end]
00209 return $item
00210 }
00211
00212 # Otherwise, return a list of items
00213 set result [list ]
00214 for {set i 0} {$i < $count} {incr i} {
00215 lappend result [lindex $stacks($name) "end-${i}"]
00216 }
00217
00218 # Remove these items from the stack
00219 incr i -1
00220 set stacks($name) [lreplace $stacks($name) "end-${i}" end]
00221
00222 return $result
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 ret ::struct::stack::_push (type name , type args) {
00237 if { [llength $args] == 0 } {
00238 error "wrong # args: should be \"$name push item ?item ...?\""
00239 }
00240 foreach item $args {
00241 lappend ::struct::stack::stacks($name) $item
00242 }
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 ret ::struct::stack::_rotate (type name , type count , type steps) {
00258 variable stacks
00259 set len [llength $stacks($name)]
00260 if { $count > $len } {
00261 error "insufficient items on stack to fill request"
00262 }
00263
00264 # Rotation algorithm:
00265 # do
00266 # Find the insertion point in the stack
00267 # Move the end item to the insertion point
00268 # repeat $steps times
00269
00270 set start [expr {$len - $count}]
00271 set steps [expr {$steps % $count}]
00272 for {set i 0} {$i < $steps} {incr i} {
00273 set item [lindex $stacks($name) end]
00274 set stacks($name) [lreplace $stacks($name) end end]
00275 set stacks($name) [linsert $stacks($name) $start $item]
00276 }
00277 return
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 ret ::struct::stack::_size (type name) {
00291 return [llength $::struct::stack::stacks($name)]
00292 }
00293
00294
00295
00296
00297 namespace ::struct {
00298
00299 namespace import -force stack::stack
00300 namespace export stack
00301 }
00302 package provide struct::stack 1.3.1
00303