fgap_list.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand        --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute  and/or modify it under the terms of the GNU Library General --
-- Public  License (LGPL)  as published  by the  Free  Software  Foundation; --
-- either version 2 of the license, or (at your option) any later version.   --
-- This  library  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details.       --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------


class FGAP_LIST{T} < $STR

class FGAP_LIST{T} < $STR is -- This class is an array replacement for linked lists. It has an -- array based structure like LIST, but supports insertions and deletions -- from the middle of the list as well as the end. -- This structure consists of an extensible array with a "gap" region -- in the middle. When an insertion or deletion is required, the gap is first -- moved to the proper location by moving elements around. Element access is -- by index and skips over the gap wherever it may lie. As long as most -- insertions and deletions are fairly close in location to the preceding -- one, the movement of elements accross the gap will not be extensive. -- Algorithms which are based on doubly linked lists often have a single -- pointer which moves up and down the list inserting and deleting elements -- as it moves. Such algorithms will also operate efficiently with gap -- lists. Sometimes this structure is refered to as a "double stack" since -- it may be viewed as two stacks which approach one another. It has found -- wide use in text editors (such as GNU Emacs) and turns out to be much more -- efficient in practice than more obvious structures such as a linked list -- of strings for each line. -- Version 1.3 Nov 98. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 11 Apr 94 so Original -- 12 Jul 96 bg Modified for Sather 1.1 -- 19 Mar 97 kh Changed to CARD from INT -- 6 Nov 98 kh Refined, added pre/post conditions. private include COMPARE{T} ; private include AREF{T} ; include ELT_FILTERS{T} ; include CONTAINER_STR{T} ; private attr gap_start, gap_size : CARD ; -- These two control the start and size of the gap. private const Default_Size : CARD := 5 ; create : SAME is -- This routine creates a gap with the default size. me : SAME := new(Default_Size) ; me.gap_size := Default_Size ; return me end ; create( arr : $ELT{T} ) : SAME pre ~void(arr) post ~void(result) is -- This routone creates a new gap list which is given the contents of -- the array arr. me : SAME := create ; loop me := me.append(arr.elt!) end ; return me end ; create_sized( cnt : CARD ) : SAME is -- This routine creates a new gap list with the given initial size. me : SAME := new(cnt) ; me.gap_size := cnt ; return me end ; is_empty : BOOL is -- This predicate returns true if and only if self has no elements. return (gap_size = asize) end ; has_ind( location : CARD ) : BOOL pre ~void(self) post true is -- This predicate returns true if and only if self has an element at -- the given location. return location < size end ; equals( other : $ARR{T} ) : BOOL is -- This predicate returns true if and only if all of the elements of -- other are the same as self when taken in the same sequence. if other.size /= size then return false end ; loop if ~elt_eq(other.elt!,elt!) then return false end end ; return true end ; size : CARD pre ~void(self) post (result = (asize - gap_size)) is -- This routine returns the total number of elements in the list. return asize - gap_size end ; private move_gap( location : CARD ) pre (location <= size) post (gap_start = location) is -- This private routine is used to move the list gap to start at the -- position given. index : CARD ; if location <= gap_start then base : CARD := location + gap_size ; index := gap_start + gap_size - 1 ; loop until!(index < base) ; [index] := [index - gap_size] ; index := index - 1 end else index := gap_start ; loop until!(index = location) ; [index] := [index + gap_size] ; index := index + 1 end end ; gap_start := location end ; clear pre ~void(self) post (gap_size = asize) and (gap_start = 0) is -- This routine clears all elements of self. index : CARD := 0 ; loop until!(index = asize) ; [index] := elt_nil ; index := index + 1 end ; gap_start := 0 ; gap_size := asize end ; insert( location : CARD, elem : T ) : SAME pre ~void(self) and (location <= size) post (result.size = (initial(size) + 1)) and (result[location] = elem) is -- This routine inserts elem at the given location, pushing later -- elements forward. There is no restriction on where in the list -- an element may be inserted. res : SAME := self ; if gap_size = 0 then -- no gap, so double size res := new(2 * asize) ; res.gap_start := asize ; res.gap_size := res.asize - res.gap_start ; loop res.set!(elt!) end ; clear -- help the garbage collector end ; res.move_gap(location) ; res[location] := elem ; res.gap_start := res.gap_start + 1 ; res.gap_size := res.gap_size - 1 ; return res end ; append( elem : T ) : SAME pre ~void(self) post (result.size = (size + 1)) and (result[size] = elem) is -- This routine appends the new element to the list by using the list -- insertion routine. return insert(size,elem) end ; delete( location : CARD ) : SAME pre ~void(self) and has_ind(location) post (gap_size = (initial(gap_size) + 1)) is -- This routine deletes the element at the given location. move_gap(location) ; gap_size := gap_size + 1 ; return self end ; replace( location : CARD, elem : T ) pre ~void(self) and has_ind(location) post ((location < gap_start) and ([location] = elem)) or ((location >= gap_start) and ([gap_size + location] = elem)) is -- This routine replaces the current element at the given location -- by elem. if location < gap_start then [location] := elem else [gap_size + location] := elem end end ; get( location : CARD ) : T pre ~void(self) and has_ind(location) post ((location < gap_start) and (result = [location])) or ((location >= gap_start) and (result = [gap_size + location])) is -- This routine retrieves the element at the given locqtion in self. if location < gap_start then return [location] else return [gap_size + location] end end ; set( location : CARD, val : T ) pre ~void(self) and has_ind(location) post ((location < gap_start) and ([location] = val)) or ((location >= gap_start) and ([gap_size + location] = val)) is -- This routine sets the element at the given location to have the value -- val. It is a synonym for replace. if location < gap_start then [location] := val else [gap_size + location] := val end end ; elt! : T pre ~void(self) post ~void(result) is -- This iter yields the list elements in sequence, ignoring the gap -- wherever that may be. index : CARD := 0 ; sz : CARD := size ; loop until!(index = sz) ; yield get(index); index := index + 1 end end ; set!( elem : T ) pre ~void(self) post true is -- This iter sets successive elements of self to have the value elem -- (which is re-evaluated on each resumption). index : CARD := 0 ; sz : CARD := size ; loop until!(index = sz) ; [index] := elem ; yield ; index := index + 1 end end ; end ; -- FGAP_LIST