Home | History | Annotate | Line # | Download | only in lib
      1  1.1.1.4  christos # Copyright 2017-2024 Free Software Foundation, Inc.
      2      1.1  christos 
      3      1.1  christos # This program is free software; you can redistribute it and/or modify
      4      1.1  christos # it under the terms of the GNU General Public License as published by
      5      1.1  christos # the Free Software Foundation; either version 3 of the License, or
      6      1.1  christos # (at your option) any later version.
      7      1.1  christos #
      8      1.1  christos # This program is distributed in the hope that it will be useful,
      9      1.1  christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10      1.1  christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11      1.1  christos # GNU General Public License for more details.
     12      1.1  christos #
     13      1.1  christos # You should have received a copy of the GNU General Public License
     14      1.1  christos # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15      1.1  christos 
     16      1.1  christos # This file implements some simple data structures in Tcl.
     17      1.1  christos 
     18      1.1  christos # A namespace/commands to support a stack.
     19      1.1  christos #
     20      1.1  christos # To create a stack, call ::Stack::new, recording the returned object ID
     21      1.1  christos # for future calls to manipulate the stack object.
     22      1.1  christos #
     23      1.1  christos # Example:
     24      1.1  christos #
     25      1.1  christos # set sid [::Stack::new]
     26      1.1  christos # stack push $sid a
     27      1.1  christos # stack push $sid b
     28      1.1  christos # stack empty $sid;  # returns false
     29      1.1  christos # stack pop $sid;    # returns "b"
     30      1.1  christos # stack pop $sid;    # returns "a"
     31      1.1  christos # stack pop $sid;    # errors with "stack is empty"
     32      1.1  christos # stack delete $sid1
     33      1.1  christos 
     34      1.1  christos namespace eval ::Stack {
     35      1.1  christos     # A counter used to create object IDs
     36      1.1  christos     variable num_ 0
     37      1.1  christos 
     38      1.1  christos     # An array holding all object lists, indexed by object ID.
     39      1.1  christos     variable data_
     40      1.1  christos 
     41      1.1  christos     # Create a new stack object, returning its object ID.
     42      1.1  christos     proc new {} {
     43      1.1  christos 	variable num_
     44      1.1  christos 	variable data_
     45      1.1  christos 
     46      1.1  christos 	set oid [incr num_]
     47      1.1  christos 	set data_($oid) [list]
     48      1.1  christos 	return $oid
     49      1.1  christos     }
     50      1.1  christos 
     51      1.1  christos     # Delete the given stack ID.
     52      1.1  christos     proc delete {oid} {
     53      1.1  christos 	variable data_
     54      1.1  christos 
     55      1.1  christos 	error_if $oid
     56      1.1  christos 	unset data_($oid)
     57      1.1  christos     }
     58      1.1  christos 
     59      1.1  christos     # Returns whether the given stack is empty.
     60      1.1  christos     proc empty {oid} {
     61      1.1  christos 	variable data_
     62      1.1  christos 
     63      1.1  christos 	error_if $oid
     64      1.1  christos 	return [expr {[llength $data_($oid)] == 0}]
     65      1.1  christos     }
     66      1.1  christos 
     67      1.1  christos     # Push ELEM onto the stack given by OID.
     68      1.1  christos     proc push {oid elem} {
     69      1.1  christos 	variable data_
     70      1.1  christos 
     71      1.1  christos 	error_if $oid
     72      1.1  christos 	lappend data_($oid) $elem
     73      1.1  christos     }
     74      1.1  christos 
     75      1.1  christos     # Return and pop the top element on OID.  It is an error to pop
     76      1.1  christos     # an empty stack.
     77      1.1  christos     proc pop {oid} {
     78      1.1  christos 	variable data_
     79      1.1  christos 
     80      1.1  christos 	error_if $oid
     81      1.1  christos 	if {[llength $data_($oid)] == 0} {
     82      1.1  christos 	    ::error "stack is empty"
     83      1.1  christos 	}
     84      1.1  christos 	set elem [lindex $data_($oid) end]
     85      1.1  christos 	set data_($oid) [lreplace $data_($oid) end end]
     86      1.1  christos 	return $elem
     87      1.1  christos     }
     88      1.1  christos 
     89      1.1  christos     # Returns the depth of a given ID.
     90      1.1  christos     proc length {oid} {
     91      1.1  christos 	variable data_
     92      1.1  christos 
     93      1.1  christos 	error_if $oid
     94      1.1  christos 	return [llength $data_($oid)]
     95      1.1  christos     }
     96      1.1  christos 
     97      1.1  christos     # Error handler for invalid object IDs.
     98      1.1  christos     proc error_if {oid} {
     99      1.1  christos 	variable data_
    100      1.1  christos 
    101      1.1  christos 	if {![info exists data_($oid)]} {
    102      1.1  christos 	    ::error "object ID $oid does not exist"
    103      1.1  christos 	}
    104      1.1  christos     }
    105      1.1  christos 
    106      1.1  christos     # Export procs to be used.
    107      1.1  christos     namespace export empty push pop new delete length error_if
    108      1.1  christos 
    109      1.1  christos     # Create an ensemble command to use instead of requiring users
    110      1.1  christos     # to type namespace proc names.
    111      1.1  christos     namespace ensemble create -command ::stack
    112      1.1  christos }
    113      1.1  christos 
    114      1.1  christos # A namespace/commands to support a queue.
    115      1.1  christos #
    116      1.1  christos # To create a queue, call ::Queue::new, recording the returned queue ID
    117      1.1  christos # for future calls to manipulate the queue object.
    118      1.1  christos #
    119      1.1  christos # Example:
    120      1.1  christos #
    121      1.1  christos # set qid [::Queue::new]
    122      1.1  christos # queue push $qid a
    123      1.1  christos # queue push $qid b
    124      1.1  christos # queue empty $qid;  # returns false
    125      1.1  christos # queue pop $qid;    # returns "a"
    126      1.1  christos # queue pop $qid;    # returns "b"
    127      1.1  christos # queue pop $qid;    # errors with "queue is empty"
    128      1.1  christos # queue delete $qid
    129      1.1  christos 
    130      1.1  christos namespace eval ::Queue {
    131      1.1  christos 
    132      1.1  christos     # Remove and return the oldest element in the queue given by OID.
    133      1.1  christos     # It is an error to pop an empty queue.
    134      1.1  christos     proc pop {oid} {
    135      1.1  christos 	variable ::Stack::data_
    136      1.1  christos 
    137      1.1  christos 	error_if $oid
    138      1.1  christos 	if {[llength $data_($oid)] == 0} {
    139      1.1  christos 	    error "queue is empty"
    140      1.1  christos 	}
    141      1.1  christos 	set elem [lindex $data_($oid) 0]
    142      1.1  christos 	set data_($oid) [lreplace $data_($oid) 0 0]
    143      1.1  christos 	return $elem
    144      1.1  christos     }
    145      1.1  christos 
    146      1.1  christos     # "Unpush" ELEM back to the head of the queue given by QID.
    147      1.1  christos     proc unpush {oid elem} {
    148      1.1  christos 	variable ::Stack::data_
    149      1.1  christos 
    150      1.1  christos 	error_if $oid
    151      1.1  christos 	set data_($oid) [linsert $data_($oid) 0 $elem]
    152      1.1  christos     }
    153      1.1  christos 
    154      1.1  christos     # Re-use some common routines from the Stack implementation.
    155      1.1  christos     namespace import ::Stack::create ::Stack::new ::Stack::empty \
    156      1.1  christos 	::Stack::delete ::Stack::push ::Stack::length ::Stack::error_if
    157      1.1  christos 
    158      1.1  christos     # Export procs to be used.
    159      1.1  christos     namespace export new empty push pop new delete length error_if unpush
    160      1.1  christos 
    161      1.1  christos     # Create an ensemble command to use instead of requiring users
    162      1.1  christos     # to type namespace proc names.
    163      1.1  christos     namespace ensemble create -command ::queue
    164      1.1  christos }
    165