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