set rcsId {$Id: xifo.tcl,v 2.1 1999/08/14 21:49:18 jfontain Exp $}

# source stooop.tcl
# namespace import stooop::*

class xifo {
    proc xifo {this size} {
        set ($this,size) $size
        empty $this
    }

    proc ~xifo {this} {
        variable ${this}data
        catch {unset ${this}data}
    }

    proc in {this data} {
        variable ${this}data
        tidyUp $this
        if {[array size ${this}data]>=$($this,size)} {
            unset ${this}data($($this,first))
            incr ($this,first)
        }
        set ${this}data([incr ($this,last)]) $data
    }

    proc tidyUp {this} {                                                                           ;# warning: for internal use only
        variable ${this}data
        catch {
            unset ${this}data($($this,unset))
            unset ($this,unset)
        }
    }

    proc empty {this} {
        variable ${this}data
        catch {unset ${this}data}
        catch {unset ($this,unset)}
        set ($this,first) 0
        set ($this,last) -1
    }

    proc isEmpty {this} {
        variable ${this}data
        return [expr {[array size ${this}data]==0}]
    }

    virtual proc out {this}

    virtual proc data {this}
}

class lifo {
    proc lifo {this {size 2147483647}} xifo {$size} {}

    proc ~lifo {this} {}

    proc out {this} {
        xifo::tidyUp $this
        if {[array size xifo::${this}data]==0} {
            error "lifo $this out error, empty"
        }
        set xifo::($this,unset) $xifo::($this,last)    ;# delay unsetting popped data to improve performance by avoiding a data copy
        incr xifo::($this,last) -1
        return [set xifo::${this}data($xifo::($this,unset))]
    }

    proc data {this} {
        set list {}
        set first $xifo::($this,first)
        for {set index $xifo::($this,last)} {$index>=$first} {incr index -1} {
            lappend list [set xifo::${this}data($index)]
        }
        return $list
    }
}

class fifo {
    proc fifo {this {size 2147483647}} xifo {$size} {}

    proc ~fifo {this} {}

    proc out {this} {
        xifo::tidyUp $this
        if {[array size xifo::${this}data]==0} {
            error "fifo $this out error, empty"
        }
        set xifo::($this,unset) $xifo::($this,first)   ;# delay unsetting popped data to improve performance by avoiding a data copy
        incr xifo::($this,first)
        return [set xifo::${this}data($xifo::($this,unset))]
    }

    proc data {this} {
        set list {}
        set last $xifo::($this,last)
        for {set index $xifo::($this,first)} {$index<=$last} {incr index} {
            lappend list [set xifo::${this}data($index)]
        }
        return $list
    }
}

# here are a few lines of example code:
#    proc exercise {id} {
#        for {set u 0} {$u<10} {incr u} {
#            xifo::in $id $u
#        }
#        puts [xifo::out $id]
#        puts [xifo::data $id]
#        xifo::in $id $u
#        xifo::in $id [incr u]
#        puts [xifo::data $id]
#    }
#    set id [new lifo 10]
#    exercise $id
#    delete $id
#    set id [new fifo 10]
#    exercise $id
#    delete $id
