home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
LIBRARY
/
FSTR.SA
< prev
next >
Wrap
Text File
|
1995-02-05
|
13KB
|
387 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
-- fstr.sa: Buffers for efficiently constructing strings.
-------------------------------------------------------------------
class FSTR < $IS_EQ{FSTR}, $IS_LT{FSTR}, $HASH is
-- Buffers for efficiently constructing strings by repeated
-- concatenation using amortized doubling.
include FLIST{CHAR}
asize->asize,loc->loc; -- Needs to be public for some uses.
-- Some useful features are:
-- size:INT The current string size.
-- create(n:INT):SAME A buffer of initial size `n'.
-- copy:SAME A copy of self.
-- aget(ind:INT):CHAR The character `ind'.
-- aset(ind:INT, c:CHAR) Set character `ind' to `c'.
-- is_eq(l:SAME):BOOL True if self equals l as strings.
-- is_empty:BOOL True if self is the empty string.
-- clear Make self represent the empty string.
-- elt!:CHAR The characters in self.
-- elt!(beg:INT):CHAR Characters starting at `beg'.
-- elt!(beg,num:INT):CHAR `num' chars beginning at `beg'.
-- elt!(beg,num,step:INT):CHAR `num' chars beginning at `beg',
-- stepping by `step'.
-- ind!:INT The indices of the buffer.
-- contains(c:CHAR):BOOL True if self contains `c'.
-- to_reverse Reverse the order of the characters.
create:SAME is
-- A new buffer.
return new(16) end;
create(sz:INT):SAME
-- A new buffer of size `sz'.
pre sz>=0 is
return new(sz) end;
acopy(s:STR) is
-- overridden by a MACRO. Added by MBK.
loop aset![s.aelt!]; end;
end;
acopyn(s:STR,n:INT) pre n <= s.length is
-- overridden by a MACRO. Added by MBK.
loop aset!(s[n.times!]) end;
end;
acopyn(s:FSTR,n:INT) pre n <= s.length is
-- overridden by a MACRO. Added by MBK.
loop aset!(s[n.times!]) end;
end;
create(s:STR):SAME is
-- added by MBK to make STR::fstr:FSTR faster
if void(s) then
return create;
-- else -- NLP
end; -- NLP
l ::= s.length;
r::=new(l); -- why 16? Why not?
r.acopyn(s,l); -- this puppy is macroized into memcpy
r.loc := l;
return r;
-- end; -- NLP
end;
length:INT is
-- The number of characters in self. Another name for `size'.
return size end;
push(c:CHAR):SAME is
-- Add a new character to the end of self and return it.
-- If self is void, create a new list. Usage: `l:=l.push(e)'.
-- This routine needs to go fast too, which is the reason behind
-- the "l" temporary. Modified by MBK.
r:SAME;
l:INT;
if void(self) then r:=create; l := 0;
elsif loc<asize then r:=self; l := r.loc; -- normal path
else r:=new(2*asize); l := loc; r.acopyn(self,l) end;
r.loc:=l+1;
r[l]:=c;
return r;
end;
str:STR is
-- A string version of self.
return STR::from_fstr(self) end;
clear is
-- Set self to the empty string. Retain the array.
-- Self may be void.
if ~void(self) then loc:=0 end end;
acopy(beg:INT,src:STR) is
-- overwridden by MACROS
loop aset!(beg,src.aelt!) end end;
plus(s:STR):SAME
-- Append the string `s' to self and return it.
-- modified by MBK to make it go fast. Called by compiler frequently.
post result.str = initial(self).str + s is
r:SAME;
l ::= s.length;
if void(self) then
r:=create(2*l);
elsif (loc + l < asize) then
r:=self;
else
r :=new(2*(asize+l)); r.loc := loc; r.acopy(self);
end;
if (l = 0) then return r; end;
r.acopy(r.loc,s); -- This one is MACROIZED to a memcpy.
r.loc := r.loc + l;
-- r::=self; loop r:=r.push(s.elt!) end; return r end;
return r; end;
plus(s:SAME):SAME
-- Append `s' to self and return it.
post result.str = initial(self).str + s.str is
r::=self; loop r:=r.push(s.elt!) end; return r end;
plus(b:BOOL):SAME is
-- Append `b' to self and return it.
if b then return self + "true"
-- else return self + "false" end end; -- NLP
end; return self + "false"; end; -- NLP
plus(c:CHAR):SAME is
-- Append `c' to self and return it.
return push(c) end;
plus(i:INT):SAME is
-- Append `i' to self and return it.
return i.str_in(self) end;
plus(f:FLT):SAME is
-- Append `f' to self and return it.
return (self + (f.str)) end;
-- OLD, better version, does not work as yet return f.str_in(self) end;
private is_eq_helper(s:SAME,i:INT):BOOL is
-- Matt Kennel, INLS. The reason for this
-- function's existence is that it will be overridden
-- by "memcmp" in MACROS.
loop if elt!/=s.elt! then return false end; end;
return true;
end;
private is_eq_helper(s:STR,i:INT):BOOL is
-- Matt Kennel, INLS. The reason for this
-- function's existence is that it will be overridden
-- by "memcmp" in MACROS.
loop if elt!/=s.aelt! then return false end; end;
return true;
end;
is_eq(s:SAME):BOOL
-- True if `s' equals self. Either may be void. MBK.
post result = (initial(self).str.is_eq(s.str)) is
s1,s2:INT;
if void(self) then s1 := -1; else s1 := loc; end;
if void(s) then s2 := -1; else s2 := s.loc; end;
-- -1 is an otherwise illegal value.
-- We thus distinguish 'void' from 0 length FSTR.
if s1 /= s2 then return false end;
return is_eq_helper(s,s1); -- MACROized.
end;
is_eq(s:STR):BOOL is
-- so you can say `` if FSTR = "blabitty blah blah blah" ''
s1,s2:INT;
if void(self) then s1 := -1; else s1 := loc; end;
if void(s) then s2 := -1; else s2 := s.size; end;
-- -1 is an otherwise illegal value.
-- We thus distinguish 'void' from 0 length FSTR.
if s1 /= s2 then return false end;
return is_eq_helper(s,s1); -- MACROized.
end;
-- is_eq(s:SAME):BOOL is
-- -- True if `s' equals self. Either may be void.
-- if s.size/=size then return false end;
-- loop if elt!/=s.elt! then return false end end;
-- return true end;
is_neq(s:SAME):BOOL is
-- True if `s' is not equal to self. Either may be void.
return ~is_eq(s) end;
is_lt(s:SAME):BOOL is
-- True if self is lexicographically before `s'.
-- Void is before everything else.
if size=0 then
if s.size/=0 then return true else return false end end;
if s.size=0 then return false end;
loop c::=elt!; sc::=s.elt!;
if c.is_gt(sc) then return false
elsif c.is_lt(sc) then return true end end;
if size<s.size then return true
-- else return false end end; -- NLP
end; return false; end; -- NLP
hash:INT is
-- Keep It Simple, Stupid.
if void(self) then return 0 end;
if (length = 0) then return 0 end;
i::= length-1;
r:INT:=532415.uplus([i].int);
-- 532415 = 'A' * (2^13-1)
i := i-1;
loop while!(i>=0);
r := (r.utimes(1664525)).uplus(1013904223).uplus([i].int);
i := i-1
end;
return r;
end;
hash0:INT is
-- An inexpensive to compute hash function of self.
-- Gives an INT with rightmost 24 bits. Also gives
-- lousy hash functions.
-- Void gives 0.
r::=0;
loop i::=ind!; r:=r.bxor([i].int.lshift(i.band(15))) end;
return r end;
append_file(nm:STR):SAME is
-- Open the file named `nm' in the current directory, append
-- its contents to self, close the file, and return the new
-- buffer. Do nothing if the file cannot be opened.
fd::=C_STR::c_str_file_open(nm);
if fd<0 then return self end;
sz::=C_STR::c_str_file_size(fd);
if sz=0 then return self end;
r:SAME;
bst:INT;
if void(self) then
r:=new(sz); bst:=0; r.loc:=sz;
elsif sz<=asize-loc then
r:=self; bst:=loc; r.loc:=loc+sz;
else
r:=new((2*asize).max(loc+sz)); bst:=loc;
r.acopy(self); r.loc:=loc+sz; end;
C_STR::c_str_file_in_fstr(fd,r,0,sz,bst);
C_STR::c_str_file_close(fd);
return r end;
append_file_range(nm:STR,st,sz:INT):SAME is
-- Open the file named `nm' in the current directory, append
-- at most `sz' characters starting at `st' to self (only as
-- many as are there), close the file, and return the new buffer.
-- Do nothing if the file cannot be opened.
fd::=C_STR::c_str_file_open(nm);
if fd<0 then return self end;
fsz::=C_STR::c_str_file_size(fd);
if fsz=0 then return self end;
asz::=(fsz-st).min(sz); -- Actual size of range.
r:SAME;
bst:INT;
if void(self) then
r:=new(asz); bst:=0; r.loc:=asz;
elsif asz<=asize-loc then
r:=self; bst:=loc; r.loc:=loc+asz;
else
r:=new((2*asize).max(loc+asz)); bst:=loc;
r.acopy(self); r.loc:=loc+asz; end;
C_STR::c_str_file_in_fstr(fd,r,st,asz,bst);
C_STR::c_str_file_close(fd);
return r end;
is_upper:BOOL is
-- True if each alphabetic character of self is upper case.
-- Self may be void.
loop if elt!.is_upper.not then return false end end;
return true end;
is_lower:BOOL is
-- True if each alphabetic character of self is lower case.
-- Self may be void.
loop if elt!.is_lower.not then return false end end;
return true end;
head(i:INT):SAME
-- The first `i' characters of self.
-- Self may be void if i=0.
pre i.is_bet(0,size) is
if void(self) then return void end;
r::=#SAME(i); r.acopy(self); r.loc := i; return r end;
tail(i:INT):SAME
-- The last `i' characters of self.
-- Self may be void if i=0.
pre i.is_bet(0,size) post result.size = i is
if void(self) then return self end;
r::=#SAME(i); r.acopy(0,i,asize-i,self); r.loc := i; return r end;
substring(beg,num:INT):SAME
-- The substring with `num' charcters whose first character has
-- index `beg'. Self may be void if beg=0 and num=0.
pre num>=0 and beg.is_bet(0,size-num) post result.size = num is
if void(self) then return void end;
r::=#SAME(num); r.acopy(0,num,beg,self); r.loc := num; return r end;
separate!(s:FSTR!):FSTR is
-- On the first iteration just outputs `s', on successive
-- iterations it outputs self followed by `s'. Useful for
-- forming lists,
-- Eg: loop #OUT + ", ".separate!(a.elt!) end;
yield s; loop yield self + s end end;
end; -- class FSTR
-------------------------------------------------------------------
class TEST_FSTR is
include TEST;
main is
class_name("FSTR");
s ::= #FSTR;
test("length",s.length.str,"0");
s := s+'c';
test("length2",s.length.str,"1");
test("+char, str",s.str,"c");
s.clear;
test("clear",s.str,"");
s := s+"TEST";
test("plus s",s.str,"TEST");
s := s+2;
test("plus int",s.str,"TEST2");
s := s+3.0;
test("plus float",s.str,"TEST23");
test("is_eq",s.is_eq("TEST23").str,"true");
s.clear;
s := s+"test";
s_test ::= s.copy;
test("copy",(s_test).str,"test");
test("is_eq 2",(s_test.is_eq("test")).str,"true");
test("is_eq 3",(s_test.is_eq("no_test")).str,"false");
--Forgotten what the sugar is! test("is_neq",(s_test/=("test")).str,"true");
-- test("is_eq",(s_test=("no_test")).str,"false");
-- test("hash"
-- test("append_file" append_file_range
s.clear;
s := s+"TEST";
s_TEST ::= s.copy;
test("copy 2",s_TEST.str,"TEST");
s_TEST := s_TEST+"TEST OF A LONGER STRING THAT SHOULD DOUBLE";
test("plus str",s_TEST.str,"TESTTEST OF A LONGER STRING THAT SHOULD DOUBLE");
s := s+s;
test("plus fstr",s.str,"TESTTEST");
s.clear;
s := s+"TEST"+500;
test("plus int2",s.str,"TEST500");
s.clear; s := s+"TEST"+(-1000);
test("plus int2",s.str,"TEST-1000");
s.clear; s := s+"TEST"+463.479;
test("plus float2",s.str,"TEST463.479");
s.clear; s := s+"TEST"+(-12463.479);
test("plus float3",s.str,"TEST-12463.5");
s_TEST.clear; s_TEST := s_TEST+"TEST";
s_test.clear; s_test := s_test+"test";
test("is_upper",s_TEST.is_upper.str,"true");
test("is_upper",s_test.is_upper.str,"false");
test("is_lower",s_TEST.is_lower.str,"false");
test("is_lower",s_test.is_lower.str,"true");
finish;
end;
end; -- class TEST_FSTR
-------------------------------------------------------------------