| 1 | # queue.tcl -- |
|---|
| 2 | # |
|---|
| 3 | # Queue implementation 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 | # |
|---|
| 10 | # RCS: @(#) $Id: queue.tcl,v 1.13 2005/09/30 23:48:41 andreas_kupries Exp $ |
|---|
| 11 | |
|---|
| 12 | namespace eval ::struct {} |
|---|
| 13 | namespace eval ::struct::queue { |
|---|
| 14 | # The queues array holds all of the queues you've made |
|---|
| 15 | variable queues |
|---|
| 16 | |
|---|
| 17 | # counter is used to give a unique name for unnamed queues |
|---|
| 18 | variable counter 0 |
|---|
| 19 | |
|---|
| 20 | # Only export one command, the one used to instantiate a new queue |
|---|
| 21 | namespace export queue |
|---|
| 22 | } |
|---|
| 23 | |
|---|
| 24 | # ::struct::queue::queue -- |
|---|
| 25 | # |
|---|
| 26 | # Create a new queue with a given name; if no name is given, use |
|---|
| 27 | # queueX, where X is a number. |
|---|
| 28 | # |
|---|
| 29 | # Arguments: |
|---|
| 30 | # name name of the queue; if null, generate one. |
|---|
| 31 | # |
|---|
| 32 | # Results: |
|---|
| 33 | # name name of the queue created |
|---|
| 34 | |
|---|
| 35 | proc ::struct::queue::queue {args} { |
|---|
| 36 | variable queues |
|---|
| 37 | variable counter |
|---|
| 38 | |
|---|
| 39 | switch -exact -- [llength [info level 0]] { |
|---|
| 40 | 1 { |
|---|
| 41 | # Missing name, generate one. |
|---|
| 42 | incr counter |
|---|
| 43 | set name "queue${counter}" |
|---|
| 44 | } |
|---|
| 45 | 2 { |
|---|
| 46 | # Standard call. New empty queue. |
|---|
| 47 | set name [lindex $args 0] |
|---|
| 48 | } |
|---|
| 49 | default { |
|---|
| 50 | # Error. |
|---|
| 51 | return -code error \ |
|---|
| 52 | "wrong # args: should be \"queue ?name?\"" |
|---|
| 53 | } |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | # FIRST, qualify the name. |
|---|
| 57 | if {![string match "::*" $name]} { |
|---|
| 58 | # Get caller's namespace; append :: if not global namespace. |
|---|
| 59 | set ns [uplevel 1 [list namespace current]] |
|---|
| 60 | if {"::" != $ns} { |
|---|
| 61 | append ns "::" |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | set name "$ns$name" |
|---|
| 65 | } |
|---|
| 66 | if {[llength [info commands $name]]} { |
|---|
| 67 | return -code error \ |
|---|
| 68 | "command \"$name\" already exists, unable to create queue" |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | # Initialize the queue as empty |
|---|
| 72 | set queues($name) [list ] |
|---|
| 73 | |
|---|
| 74 | # Create the command to manipulate the queue |
|---|
| 75 | interp alias {} $name {} ::struct::queue::QueueProc $name |
|---|
| 76 | |
|---|
| 77 | return $name |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | ########################## |
|---|
| 81 | # Private functions follow |
|---|
| 82 | |
|---|
| 83 | # ::struct::queue::QueueProc -- |
|---|
| 84 | # |
|---|
| 85 | # Command that processes all queue object commands. |
|---|
| 86 | # |
|---|
| 87 | # Arguments: |
|---|
| 88 | # name name of the queue object to manipulate. |
|---|
| 89 | # args command name and args for the command |
|---|
| 90 | # |
|---|
| 91 | # Results: |
|---|
| 92 | # Varies based on command to perform |
|---|
| 93 | |
|---|
| 94 | proc ::struct::queue::QueueProc {name {cmd ""} args} { |
|---|
| 95 | # Do minimal args checks here |
|---|
| 96 | if { [llength [info level 0]] == 2 } { |
|---|
| 97 | error "wrong # args: should be \"$name option ?arg arg ...?\"" |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | # Split the args into command and args components |
|---|
| 101 | set sub _$cmd |
|---|
| 102 | if { [llength [info commands ::struct::queue::$sub]] == 0 } { |
|---|
| 103 | set optlist [lsort [info commands ::struct::queue::_*]] |
|---|
| 104 | set xlist {} |
|---|
| 105 | foreach p $optlist { |
|---|
| 106 | set p [namespace tail $p] |
|---|
| 107 | lappend xlist [string range $p 1 end] |
|---|
| 108 | } |
|---|
| 109 | set optlist [linsert [join $xlist ", "] "end-1" "or"] |
|---|
| 110 | return -code error \ |
|---|
| 111 | "bad option \"$cmd\": must be $optlist" |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | uplevel 1 [linsert $args 0 ::struct::queue::_$cmd $name] |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | # ::struct::queue::_clear -- |
|---|
| 118 | # |
|---|
| 119 | # Clear a queue. |
|---|
| 120 | # |
|---|
| 121 | # Arguments: |
|---|
| 122 | # name name of the queue object. |
|---|
| 123 | # |
|---|
| 124 | # Results: |
|---|
| 125 | # None. |
|---|
| 126 | |
|---|
| 127 | proc ::struct::queue::_clear {name} { |
|---|
| 128 | variable queues |
|---|
| 129 | set queues($name) [list ] |
|---|
| 130 | return |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | # ::struct::queue::_destroy -- |
|---|
| 134 | # |
|---|
| 135 | # Destroy a queue object by removing it's storage space and |
|---|
| 136 | # eliminating it's proc. |
|---|
| 137 | # |
|---|
| 138 | # Arguments: |
|---|
| 139 | # name name of the queue object. |
|---|
| 140 | # |
|---|
| 141 | # Results: |
|---|
| 142 | # None. |
|---|
| 143 | |
|---|
| 144 | proc ::struct::queue::_destroy {name} { |
|---|
| 145 | variable queues |
|---|
| 146 | unset queues($name) |
|---|
| 147 | interp alias {} $name {} |
|---|
| 148 | return |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | # ::struct::queue::_get -- |
|---|
| 152 | # |
|---|
| 153 | # Get an item from a queue. |
|---|
| 154 | # |
|---|
| 155 | # Arguments: |
|---|
| 156 | # name name of the queue object. |
|---|
| 157 | # count number of items to get; defaults to 1 |
|---|
| 158 | # |
|---|
| 159 | # Results: |
|---|
| 160 | # item first count items from the queue; if there are not enough |
|---|
| 161 | # items in the queue, throws an error. |
|---|
| 162 | |
|---|
| 163 | proc ::struct::queue::_get {name {count 1}} { |
|---|
| 164 | variable queues |
|---|
| 165 | if { $count < 1 } { |
|---|
| 166 | error "invalid item count $count" |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | if { $count > [llength $queues($name)] } { |
|---|
| 170 | error "insufficient items in queue to fill request" |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | if { $count == 1 } { |
|---|
| 174 | # Handle this as a special case, so single item gets aren't listified |
|---|
| 175 | set item [lindex $queues($name) 0] |
|---|
| 176 | set queues($name) [lreplace $queues($name) 0 0] |
|---|
| 177 | return $item |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | # Otherwise, return a list of items |
|---|
| 181 | set index [expr {$count - 1}] |
|---|
| 182 | set result [lrange $queues($name) 0 $index] |
|---|
| 183 | set queues($name) [lreplace $queues($name) 0 $index] |
|---|
| 184 | |
|---|
| 185 | return $result |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | # ::struct::queue::_peek -- |
|---|
| 189 | # |
|---|
| 190 | # Retrieve the value of an item on the queue without removing it. |
|---|
| 191 | # |
|---|
| 192 | # Arguments: |
|---|
| 193 | # name name of the queue object. |
|---|
| 194 | # count number of items to peek; defaults to 1 |
|---|
| 195 | # |
|---|
| 196 | # Results: |
|---|
| 197 | # items top count items from the queue; if there are not enough items |
|---|
| 198 | # to fulfill the request, throws an error. |
|---|
| 199 | |
|---|
| 200 | proc ::struct::queue::_peek {name {count 1}} { |
|---|
| 201 | variable queues |
|---|
| 202 | if { $count < 1 } { |
|---|
| 203 | error "invalid item count $count" |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | if { $count > [llength $queues($name)] } { |
|---|
| 207 | error "insufficient items in queue to fill request" |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | if { $count == 1 } { |
|---|
| 211 | # Handle this as a special case, so single item pops aren't listified |
|---|
| 212 | return [lindex $queues($name) 0] |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | # Otherwise, return a list of items |
|---|
| 216 | set index [expr {$count - 1}] |
|---|
| 217 | return [lrange $queues($name) 0 $index] |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | # ::struct::queue::_put -- |
|---|
| 221 | # |
|---|
| 222 | # Put an item into a queue. |
|---|
| 223 | # |
|---|
| 224 | # Arguments: |
|---|
| 225 | # name name of the queue object |
|---|
| 226 | # args items to put. |
|---|
| 227 | # |
|---|
| 228 | # Results: |
|---|
| 229 | # None. |
|---|
| 230 | |
|---|
| 231 | proc ::struct::queue::_put {name args} { |
|---|
| 232 | variable queues |
|---|
| 233 | if { [llength $args] == 0 } { |
|---|
| 234 | error "wrong # args: should be \"$name put item ?item ...?\"" |
|---|
| 235 | } |
|---|
| 236 | foreach item $args { |
|---|
| 237 | lappend queues($name) $item |
|---|
| 238 | } |
|---|
| 239 | return |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | # ::struct::queue::_unget -- |
|---|
| 243 | # |
|---|
| 244 | # Put an item into a queue. At the _front_! |
|---|
| 245 | # |
|---|
| 246 | # Arguments: |
|---|
| 247 | # name name of the queue object |
|---|
| 248 | # item item to put at the front of the queue |
|---|
| 249 | # |
|---|
| 250 | # Results: |
|---|
| 251 | # None. |
|---|
| 252 | |
|---|
| 253 | proc ::struct::queue::_unget {name item} { |
|---|
| 254 | variable queues |
|---|
| 255 | if {![llength $queues($name)]} { |
|---|
| 256 | set queues($name) [list $item] |
|---|
| 257 | } else { |
|---|
| 258 | set queues($name) [linsert $queues($name) 0 $item] |
|---|
| 259 | } |
|---|
| 260 | return |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | # ::struct::queue::_size -- |
|---|
| 264 | # |
|---|
| 265 | # Return the number of objects on a queue. |
|---|
| 266 | # |
|---|
| 267 | # Arguments: |
|---|
| 268 | # name name of the queue object. |
|---|
| 269 | # |
|---|
| 270 | # Results: |
|---|
| 271 | # count number of items on the queue. |
|---|
| 272 | |
|---|
| 273 | proc ::struct::queue::_size {name} { |
|---|
| 274 | variable queues |
|---|
| 275 | return [llength $queues($name)] |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | # ### ### ### ######### ######### ######### |
|---|
| 279 | ## Ready |
|---|
| 280 | |
|---|
| 281 | namespace eval ::struct { |
|---|
| 282 | # Get 'queue::queue' into the general structure namespace. |
|---|
| 283 | namespace import -force queue::queue |
|---|
| 284 | namespace export queue |
|---|
| 285 | } |
|---|
| 286 | package provide struct::queue 1.4 |
|---|