frunes.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 FRUNES < $FTEXT_STRING{RUNE,RUNES,FRUNES}
class FRUNES < $FTEXT_STRING{RUNE,RUNES,FRUNES} is
-- This class implements the concept of a fast (mutable) text string -
-- in this case of runes (potentially variable width characters).
-- Version 1.0 Apr 99. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 12 Apr 99 kh Original for Version 8 of text classes
include FTEXT_STRING{RUNE,RUNES}
plus -> raw_plus ;
include FTEXT_INCL{RUNE}
oct_acopy -> oct_acopy,
ind! -> ;
private const Default_Size : CARD := 16 ; -- character codes -- not runes!
private attr indices : FLIST{CARD} ; -- of rune initial code indices
create(
sz : CARD,
lib : LIBCHARS
) : SAME
pre ~void(lib)
post ~void(result)
is
-- This routine creates a new buffer for the given code count.
if sz = 0 then
return void
end ;
me : SAME := raw_create(sz * lib.my_size) ;
me.priv_lib := REP_LIB_LIST::index(lib) ;
me.indices := FLIST{CARD}::create ;
return me
end ;
create(
sz : CARD
) : SAME is
-- This routine creates a new buffer of the given storage size.
return create(sz,LIBCHARS::default)
end ;
create(
lib : LIBCHARS
) : SAME is
-- This routine creates a new buffer of the given storage size.
return create(Default_Size,lib)
end ;
create : SAME is
-- This routine returns a new buffer.
return create(Default_Size,LIBCHARS::default)
end ;
create(
src : RUNES
) : SAME is
-- This routine creates and fills a buffer from src.
if (src.size = 0) then
return create -- just produce a default buffer
else
res : SAME := create(src.asize,src.index_lib) ;
res.acopy(src) ;
res.loc := src.asize ;
res.buffer_scan ;
return res
end
end ;
nil : SAME is
-- This routine returns a new nil (empty but not void) string.
return create
end ;
binstr : BINSTR
pre ~void(self)
and (loc > 0)
post (result.size = loc)
is
-- This routine returns the text string as a binary string.
res : BINSTR := BINSTR::create(loc) ;
loop
index : CARD := 0.upto!(loc - 1) ;
res.aset!(oct_aget(index))
end ;
return res
end ;
size : CARD
pre true
post ((void(self)
or (loc = 0))
and (result = 0))
or (result = indices.size)
is
-- This routine returns the number of runes in self or, if self is
-- void, then zero.
if void(self)
or (loc = 0) then
return 0
else
return indices.size
end
end ;
push(
elem : RUNE
) : SAME
pre void(self)
or (index_lib = elem.lib)
post (result.size = (initial(size) + 1))
is
-- This routine appends a new element to the end of self and returns it.
-- If self is void, create a new list.
res : SAME ;
loc_size : CARD := size ; -- which may, of course, be zero!
if void(self) then
res := create(2 * elem.asize,elem.lib) ;
res.loc := 0
elsif (loc < (asize - elem.asize)) then
res := self
else
res := create(2 * (asize + elem.asize),index_lib) ;
-- Amortised doubling
res.loc := loc ;
res.acopy(self) ;
SYS::destroy(self) -- old one shouldn't be used now.
end ;
res.aset(loc_size,elem) ;
res.buffer_scan ;
return res
end ;
plus(
elem : RUNE
) : SAME
pre true
post ~void(result)
and ((void(self)
and (result.loc = 1))
or (result.loc = initial(self.loc) + 1))
is
-- This routine appends elem to self and returns it.
return self.push(elem)
end ;
plus(
fstr : SAME
) : SAME
pre (index_lib = fstr.index_lib)
post ~void(result)
and ((void(self)
and (result.loc = str.size))
or (result.loc = initial(self.loc) + str.size))
is
-- This routine appends the rune string fstr to self and returns it.
res : SAME := raw_plus(fstr) ;
res.buffer_scan ;
return res
end ;
plus(
str : RUNES
) : SAME
pre ~void(self)
and (index_lib = str.index_lib)
post ~void(result)
and ((void(self)
and (result.loc = str.size))
or (result.loc = initial(self.loc) + str.size))
is
-- This routine appends the string str to self and returns the resulting
-- string.
res : SAME := raw_plus(str) ;
res.buffer_scan ;
return res
end ;
aget(
index : CARD
) : RUNE
pre ~void(self)
and (index < indices.size)
post true
is
-- This routine is the 'array' indexing facility for runes in a string
-- of runes, returning the rune indexed.
loc_stop : CARD ;
if index < (indices.size - 1) then
loc_stop := indices[index + 1]
else
loc_stop := loc
end ;
loc_res : BINSTR := BINSTR::create ;
loop
loc_index : CARD := indices[index].upto!(loc_stop - 1) ;
loc_res := loc_res + oct_aget(loc_index)
end ;
return RUNE::build(loc_res.cursor,index_lib)
end ;
aset(
index : CARD,
elem : RUNE
)
pre ~void(self)
and ~void(elem)
and (index <= size)
post true
is
-- This routine is the 'array' indexing facility for a rune string which
-- is only applicable if it is known that either the element to be set is at
-- the end of the current contents and there is space for the element or that
-- the size of the element to be inserted is identical to the size of that
-- being replaced.
if index = indices.size then
indices := indices.push(loc) ;
loc := loc + elem.asize
end ;
loop
loc_index : CARD := indices[index].up! ;
aset(loc_index,elem.aelt!)
end
end ;
vset(
index : CARD,
elem : RUNE
) : SAME
pre ~void(self)
and (index <= (indices.size - 1))
post true
is
-- This routine is the 'array' indexing facility for the case where
-- the number of codes in elem is different from the number currently at that
-- index position in the string. A new rune string has to be produced if the
-- resulting length is different from that currently allocated.
if index = (indices.size - 1)
and (indices[index] + elem.size) < asize then
aset(index,elem) ;
return self
else
return head(index - 1) + elem + tail((indices.size - 1) - index)
end
end ;
buffer_scan
pre ~void(self)
and (loc > 0)
post (indices.size = size)
is
-- This routine scans the buffer and sets up a new index list from
-- the actual contents.
loc_bin : BINSTR := binstr ;
loc_index : CARD := 0 ;
indices := FLIST{CARD}::create ; -- a new empty list!
loop
loc_elem : BINSTR := loc_bin.chunk!(index_lib.my_size) ;
if ~(CHAR_CODE::create(loc_elem,index_lib)).is_combining then
indices := indices.push(loc_index)
end ;
loc_index := loc_index + index_lib.my_size
end
end ;
append_file(
name : STR
) : SAME
pre true
post (result = self) -- if file couldn't be found
or (result.size > initial(size)) -- and contains the file contents
is
-- This routine attempts to open the file which has the given name. If
-- successful then the contents of the file are appended to self which is
-- returned after closing the file.
--
-- NOTE If there is a file reading error then an exception is raised!
fyle : TEXT_FILE := TEXT_FILE::open_for_read(name) ;
if void(fyle) then
return self
end ;
loc_buff : SAME := fyle.frunes ;
fyle.close ;
res : SAME ;
if void(self) then
res := loc_buff ;
res.priv_lib := REP_LIB_LIST::index(LIBCHARS::default)
else
loc_buff.priv_lib := priv_lib ;
res := self + loc_buff
end ;
res.buffer_scan ;
return res
end ;
append_file_range(
name : STR,
start,
size : CARD
) : SAME
pre true
post (result = self) -- if file couldn't be found
or (result.size > initial(size)) -- and contains the file contents
is
-- This routine attempts to open the named file and append the contents
-- (starting at start for size octets) to self. If the file cannot be opened
-- then nothing is done.
fyle : REFERENCE := FILE_SYS::open(name,FILE_MODES::Read_Text) ;
if void(fyle) then
return self
end ;
file_size : CARD ;
if ~FILE_SYS::size(fyle,out file_size) then
return self
end ;
if file_size = 0 then
return self
end ;
actual_size : CARD := (file_size - start).min(size) ; -- in octets
res : SAME ;
buffer_start : CARD ;
if void(self) then
res := create(actual_size,LIBCHARS::default) ;
buffer_start := 0 ;
res.loc := actual_size
elsif actual_size <= (actual_size - loc) then
res := self ;
buffer_start := loc ;
res.loc := loc + actual_size
else
res := create((2 * asize).max(loc + actual_size),index_lib) ;
res.acopy(self) ;
buffer_start := loc ;
res.loc := loc + actual_size
end ;
-- NOTE This reading routine starts to store data at
-- the buffer_start position, not necessarily its beginning.
if ~FILE_SYS::file_read(res,actual_size,inout buffer_start,start,fyle) then
SYS_ERROR::create.error(self,SYS_EXCEPT::Access_Error,name)
end ;
FILE_SYS::close(fyle) ;
res.buffer_scan ; -- set up index list!
return res
end ;
separate!(
str : RUNES
) : RUNES
pre ~void(str)
and ~void(self)
and (index_lib = str.index_lib)
post (result.str = str.str)
or (result.str = self.str + str.str)
is
-- On the first iteration this iter yields the string str. On successive
-- iterations it yields self followed by str. Created for use in forming
-- lists whose elements are separated by self.
yield str ;
loc_fstr : SAME := create(index_lib) + str ;
loop
num : CARD := (loc + str.asize) / index_lib.my_size ;
fstr : SAME := create(num,index_lib) ;
fstr.loc := num ;
fstr.acopy(self) ;
fstr.acopy(loc,loc_fstr) ;
yield fstr.runes
end
end ;
runes : RUNES
pre ~void(self)
post ~void(result) -- |||recursive||| create(result) = self
is
-- This routine returns a text string version of self.
return RUNES::from_frunes(self) ;
end ;
end ; -- FRUNES