stack.tcl

Go to the documentation of this file.
00001 /*  stack.tcl --*/
00002 /* */
00003 /*  Stack implementation for Tcl.*/
00004 /* */
00005 /*  Copyright (c) 1998-2000 by Ajuba Solutions.*/
00006 /* */
00007 /*  See the file "license.terms" for information on usage and redistribution*/
00008 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00009 /*  */
00010 /*  RCS: @(#) $Id: stack.tcl,v 1.13 2005/10/03 17:52:22 andreas_kupries Exp $*/
00011 
00012 namespace ::struct {}
00013 
00014 namespace ::struct::stack {
00015     /*  The stacks array holds all of the stacks you've made*/
00016     variable stacks
00017     
00018     /*  counter is used to give a unique name for unnamed stacks*/
00019     variable counter 0
00020 
00021     /*  Only export one command, the one used to instantiate a new stack*/
00022     namespace export stack
00023 }
00024 
00025 /*  ::struct::stack::stack --*/
00026 /* */
00027 /*  Create a new stack with a given name; if no name is given, use*/
00028 /*  stackX, where X is a number.*/
00029 /* */
00030 /*  Arguments:*/
00031 /*  name    name of the stack; if null, generate one.*/
00032 /* */
00033 /*  Results:*/
00034 /*  name    name of the stack created*/
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 /*  Private functions follow*/
00082 
00083 /*  ::struct::stack::StackProc --*/
00084 /* */
00085 /*  Command that processes all stack object commands.*/
00086 /* */
00087 /*  Arguments:*/
00088 /*  name    name of the stack object to manipulate.*/
00089 /*  args    command name and args for the command*/
00090 /* */
00091 /*  Results:*/
00092 /*  Varies based on command to perform*/
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 /*  ::struct::stack::_clear --*/
00118 /* */
00119 /*  Clear a stack.*/
00120 /* */
00121 /*  Arguments:*/
00122 /*  name    name of the stack object.*/
00123 /* */
00124 /*  Results:*/
00125 /*  None.*/
00126 
00127 ret  ::struct::stack::_clear (type name) {
00128     set ::struct::stack::stacks($name) [list ]
00129     return
00130 }
00131 
00132 /*  ::struct::stack::_destroy --*/
00133 /* */
00134 /*  Destroy a stack object by removing it's storage space and */
00135 /*  eliminating it's proc.*/
00136 /* */
00137 /*  Arguments:*/
00138 /*  name    name of the stack object.*/
00139 /* */
00140 /*  Results:*/
00141 /*  None.*/
00142 
00143 ret  ::struct::stack::_destroy (type name) {
00144     unset ::struct::stack::stacks($name)
00145     interp alias {} $name {}
00146     return
00147 }
00148 
00149 /*  ::struct::stack::_peek --*/
00150 /* */
00151 /*  Retrieve the value of an item on the stack without popping it.*/
00152 /* */
00153 /*  Arguments:*/
00154 /*  name    name of the stack object.*/
00155 /*  count   number of items to pop; defaults to 1*/
00156 /* */
00157 /*  Results:*/
00158 /*  items   top count items from the stack; if there are not enough items*/
00159 /*      to fulfill the request, throws an error.*/
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 /*  ::struct::stack::_pop --*/
00186 /* */
00187 /*  Pop an item off a stack.*/
00188 /* */
00189 /*  Arguments:*/
00190 /*  name    name of the stack object.*/
00191 /*  count   number of items to pop; defaults to 1*/
00192 /* */
00193 /*  Results:*/
00194 /*  item    top count items from the stack; if the stack is empty, */
00195 /*      returns a list of count nulls.*/
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 /*  ::struct::stack::_push --*/
00226 /* */
00227 /*  Push an item onto a stack.*/
00228 /* */
00229 /*  Arguments:*/
00230 /*  name    name of the stack object*/
00231 /*  args    items to push.*/
00232 /* */
00233 /*  Results:*/
00234 /*  None.*/
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 /*  ::struct::stack::_rotate --*/
00246 /* */
00247 /*  Rotate the top count number of items by step number of steps.*/
00248 /* */
00249 /*  Arguments:*/
00250 /*  name    name of the stack object.*/
00251 /*  count   number of items to rotate.*/
00252 /*  steps   number of steps to rotate.*/
00253 /* */
00254 /*  Results:*/
00255 /*  None.*/
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 /*  ::struct::stack::_size --*/
00281 /* */
00282 /*  Return the number of objects on a stack.*/
00283 /* */
00284 /*  Arguments:*/
00285 /*  name    name of the stack object.*/
00286 /* */
00287 /*  Results:*/
00288 /*  count   number of items on the stack.*/
00289 
00290 ret  ::struct::stack::_size (type name) {
00291     return [llength $::struct::stack::stacks($name)]
00292 }
00293 
00294 /*  ### ### ### ######### ######### #########*/
00295 /*  Ready*/
00296 
00297 namespace ::struct {
00298     /*  Get 'stack::stack' into the general structure namespace.*/
00299     namespace import -force stack::stack
00300     namespace export stack
00301 }
00302 package provide struct::stack 1.3.1
00303 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1