Copyright (C) 1988 Free Software Foundation
written by Doug Lea (dl@rocky.oswego.edu)
This file is part of the GNU C++ Library. This library is free
software; you can redistribute it and/or modify it under the terms of
the GNU Library General Public License 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 the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
String class implementation
void String::error(const char* msg
) const
(*lib_error_handler
)("String", msg
);
String::operator const char*() const
return (const char*)chars();
StrRep _nilStrRep
= { 0, 1, { 0 } }; // nil strings point here
String _nilString
; // nil SubStrings point here
the following inline fcts are specially designed to work
in support of String classes, and are not meant as generic replacements
for libc "str" functions.
inline copy fcts - I like left-to-right from->to arguments.
all versions assume that `to' argument is non-null
These are worth doing inline, rather than through calls because,
via procedural integration, adjacent copy calls can be smushed
together by the optimizer.
inline static void ncopy(const char* from
, char* to
, int n
)
if (from
!= to
) while (--n
>= 0) *to
++ = *from
++;
// copy n bytes, null-terminate
inline static void ncopy0(const char* from
, char* to
, int n
)
while (--n
>= 0) *to
++ = *from
++;
inline static void scopy(const char* from
, char* to
)
if (from
!= 0) while((*to
++ = *from
++) != 0);
inline static void revcopy(const char* from
, char* to
, short n
)
if (from
!= 0) while (--n
>= 0) *to
-- = *from
--;
inline static int slen(const char* t
) // inline strlen
// minimum & maximum representable rep size
#define MAXStrRep_SIZE ((1 << (sizeof(short) * CHAR_BIT - 1)) - 1)
#define MINStrRep_SIZE 16
#ifndef MALLOC_MIN_OVERHEAD
#define MALLOC_MIN_OVERHEAD 4
// The basic allocation primitive:
// Always round request to something close to a power of two.
// This ensures a bit of padding, which often means that
// concatenations don't have to realloc. Plus it tends to
// be faster when lots of Strings are created and discarded,
// since just about any version of malloc (op new()) will
// be faster when it can reuse identically-sized chunks
inline static StrRep
* Snew(int newsiz
)
unsigned int siz
= sizeof(StrRep
) + newsiz
+ MALLOC_MIN_OVERHEAD
;
unsigned int allocsiz
= MINStrRep_SIZE
;
while (allocsiz
< siz
) allocsiz
<<= 1;
allocsiz
-= MALLOC_MIN_OVERHEAD
;
if (allocsiz
>= MAXStrRep_SIZE
)
(*lib_error_handler
)("String", "Requested length out of range");
StrRep
* rep
= (StrRep
*) new char[allocsiz
];
rep
->sz
= allocsiz
- sizeof(StrRep
);
// Do-something-while-allocating routines.
// We live with two ways to signify empty Sreps: either the
// null pointer (0) or a pointer to the nilStrRep.
// We always signify unknown source lengths (usually when fed a char*)
// via len == -1, in which case it is computed.
// allocate, copying src if nonull
StrRep
* Salloc(StrRep
* old
, const char* src
, int srclen
, int newlen
)
if (old
== &_nilStrRep
) old
= 0;
if (srclen
< 0) srclen
= slen(src
);
if (newlen
< srclen
) newlen
= srclen
;
if (old
== 0 || newlen
> old
->sz
)
ncopy0(src
, rep
->s
, srclen
);
if (old
!= rep
&& old
!= 0) delete old
;
// reallocate: Given the initial allocation scheme, it will
// generally be faster in the long run to get new space & copy
StrRep
* Sresize(StrRep
* old
, int newlen
)
if (old
== &_nilStrRep
) old
= 0;
else if (newlen
> old
->sz
)
ncopy0(old
->s
, rep
->s
, old
->len
);
// like allocate, but we know that src is a StrRep
StrRep
* Scopy(StrRep
* old
, StrRep
* s
)
if (old
== &_nilStrRep
) old
= 0;
if (s
== &_nilStrRep
) s
= 0;
return (old
== 0)? &_nilStrRep
: old
;
if (old
== 0 || newlen
> old
->sz
)
if (old
!= 0) delete old
;
ncopy0(s
->s
, rep
->s
, newlen
);
// allocate & concatenate
StrRep
* Scat(StrRep
* old
, const char* s
, int srclen
, const char* t
, int tlen
)
if (old
== &_nilStrRep
) old
= 0;
if (srclen
< 0) srclen
= slen(s
);
if (tlen
< 0) tlen
= slen(t
);
int newlen
= srclen
+ tlen
;
if (old
== 0 || newlen
> old
->sz
||
(t
>= old
->s
&& t
< &(old
->s
[old
->len
]))) // beware of aliasing
ncopy(s
, rep
->s
, srclen
);
ncopy0(t
, &(rep
->s
[srclen
]), tlen
);
if (old
!= rep
&& old
!= 0) delete old
;
StrRep
* Scat(StrRep
* old
, const char* s
, int srclen
, const char* t
, int tlen
,
if (old
== &_nilStrRep
) old
= 0;
if (srclen
< 0) srclen
= slen(s
);
if (tlen
< 0) tlen
= slen(t
);
if (ulen
< 0) ulen
= slen(u
);
int newlen
= srclen
+ tlen
+ ulen
;
if (old
== 0 || newlen
> old
->sz
||
(t
>= old
->s
&& t
< &(old
->s
[old
->len
])) ||
(u
>= old
->s
&& u
< &(old
->s
[old
->len
])))
ncopy(s
, rep
->s
, srclen
);
ncopy(t
, &(rep
->s
[srclen
]), tlen
);
ncopy0(u
, &(rep
->s
[srclen
+tlen
]), ulen
);
if (old
!= rep
&& old
!= 0) delete old
;
// like cat, but we know that new stuff goes in the front of existing rep
StrRep
* Sprepend(StrRep
* old
, const char* t
, int tlen
)
if (old
== &_nilStrRep
|| old
== 0)
s
= 0; old
= 0; srclen
= 0;
s
= old
->s
; srclen
= old
->len
;
if (tlen
< 0) tlen
= slen(t
);
int newlen
= srclen
+ tlen
;
if (old
== 0 || newlen
> old
->sz
||
(t
>= old
->s
&& t
< &(old
->s
[old
->len
])))
revcopy(&(s
[srclen
]), &(rep
->s
[newlen
]), srclen
+1);
if (old
!= rep
&& old
!= 0) delete old
;
// string compare: first argument is known to be non-null
inline static int scmp(const char* a
, const char* b
)
while ((diff
= *a
- *b
++) == 0 && *a
++ != 0);
inline static int ncmp(const char* a
, int al
, const char* b
, int bl
)
int n
= (al
<= bl
)? al
: bl
;
while (n
-- > 0) if ((diff
= *a
++ - *b
++) != 0) return diff
;
int fcompare(const String
& x
, const String
& y
)
const char* a
= x
.chars();
const char* b
= y
.chars();
int n
= (al
<= bl
)? al
: bl
;
if ((diff
= ac
- bc
) != 0)
if (ac
>= 'a' && ac
<= 'z')
if (bc
>= 'a' && bc
<= 'z')
if ((diff
= ac
- bc
) != 0)
// these are not inline, but pull in the above inlines, so are
int compare(const String
& x
, const char* b
)
return scmp(x
.chars(), b
);
int compare(const String
& x
, const String
& y
)
return scmp(x
.chars(), y
.chars());
int compare(const String
& x
, const SubString
& y
)
return ncmp(x
.chars(), x
.length(), y
.chars(), y
.length());
int compare(const SubString
& x
, const String
& y
)
return ncmp(x
.chars(), x
.length(), y
.chars(), y
.length());
int compare(const SubString
& x
, const SubString
& y
)
return ncmp(x
.chars(), x
.length(), y
.chars(), y
.length());
int compare(const SubString
& x
, const char* b
)
const char* a
= x
.chars();
while (n
-- > 0) if ((diff
= *a
++ - *b
++) != 0) return diff
;
return (*b
== 0) ? 0 : -1;
int String::search(int start
, int sl
, char c
) const
const char* a
= &(s
[start
]);
const char* lasta
= &(s
[sl
]);
while (a
< lasta
) if (*a
++ == c
) return --a
- s
;
const char* a
= &(s
[sl
+ start
+ 1]);
while (--a
>= s
) if (*a
== c
) return a
- s
;
int String::search(int start
, int sl
, const char* t
, int tl
) const
if (tl
< 0) tl
= slen(t
);
const char* lasts
= &(s
[sl
- tl
]);
const char* lastt
= &(t
[tl
]);
const char* p
= &(s
[start
]);
while (*x
++ == *y
++) if (y
>= lastt
) return --p
- s
;
const char* firsts
= &(s
[tl
- 1]);
const char* lastt
= &(t
[tl
- 1]);
const char* p
= &(s
[sl
+ start
+ 1]);
while (*x
-- == *y
--) if (y
< t
) return ++x
- s
;
int String::match(int start
, int sl
, int exact
, const char* t
, int tl
) const
if (tl
< 0) tl
= slen(t
);
start
= sl
+ start
- tl
+ 1;
if (start
< 0 || (exact
&& start
!= 0))
else if (exact
&& sl
- start
!= tl
)
if (sl
== 0 || tl
== 0 || sl
- start
< tl
|| start
>= sl
)
const char* s
= &(rep
->s
[start
]);
while (--n
>= 0) if (*s
++ != *t
++) return -1;
void SubString::assign(StrRep
* ysrc
, const char* ys
, int ylen
)
if (&S
== &_nilString
) return;
if (ylen
< 0) ylen
= slen(ys
);
int sl
= targ
->len
- len
+ ylen
;
if (ysrc
== targ
|| sl
>= targ
->sz
)
ncopy(oldtarg
->s
, targ
->s
, pos
);
ncopy(ys
, &(targ
->s
[pos
]), ylen
);
scopy(&(oldtarg
->s
[pos
+ len
]), &(targ
->s
[pos
+ ylen
]));
ncopy(ys
, &(targ
->s
[pos
]), len
);
ncopy(ys
, &(targ
->s
[pos
]), ylen
);
scopy(&(targ
->s
[pos
+ len
]), &(targ
->s
[pos
+ ylen
]));
revcopy(&(targ
->s
[targ
->len
]), &(targ
->s
[sl
]), targ
->len
-pos
-len
+1);
ncopy(ys
, &(targ
->s
[pos
]), ylen
);
int String::_gsub(const char* pat
, int pl
, const char* r
, int rl
)
if (pl
< 0) pl
= slen(pat
);
if (rl
< 0) rl
= slen(r
);
if (sl
<= 0 || pl
<= 0 || sl
< pl
)
// prepare to make new rep
int pos
= search(si
, sl
, pat
, pl
);
int mustfit
= xi
+ remaining
+ rl
- pl
;
if (nrep
!= 0) nrep
->len
= xi
;
nrep
= Sresize(nrep
, mustfit
);
ncopy(&(s
[si
]), &(x
[xi
]), pos
);
ncopy(r
, &(x
[xi
+ pos
]), rl
);
nrep
= Sresize(nrep
, xi
+remaining
);
ncopy0(&(s
[si
]), &(x
[xi
]), remaining
);
nrep
->len
= xi
+ remaining
;
if (nrep
->len
<= rep
->sz
) // fit back in if possible
ncopy0(nrep
->s
, rep
->s
, rep
->len
);
int String::_gsub(const Regex
& pat
, const char* r
, int rl
)
if (rl
< 0) rl
= slen(r
);
int pos
, pl
= 0; // how long is a regular expression?
pos
= pat
.search(s
, sl
, pl
, si
); // unlike string search, the pos returned here is absolute
int mustfit
= xi
+ remaining
+ rl
- pl
;
if (nrep
!= 0) nrep
->len
= xi
;
nrep
= Sresize(nrep
, mustfit
);
ncopy(&(s
[si
]), &(x
[xi
]), pos
);
ncopy(r
, &(x
[xi
+ pos
]), rl
);
nrep
= Sresize(nrep
, xi
+remaining
);
ncopy0(&(s
[si
]), &(x
[xi
]), remaining
);
nrep
->len
= xi
+ remaining
;
if (nrep
->len
<= rep
->sz
) // fit back in if possible
ncopy0(nrep
->s
, rep
->s
, rep
->len
);
void String::del(int pos
, int len
)
if (pos
< 0 || len
<= 0 || (unsigned)(pos
+ len
) > length()) return;
int nlen
= length() - len
;
ncopy0(&(rep
->s
[first
]), &(rep
->s
[pos
]), length() - first
);
void String::del(const Regex
& r
, int startpos
)
int first
= r
.search(chars(), length(), mlen
, startpos
);
void String::del(const char* t
, int startpos
)
int p
= search(startpos
, length(), t
, tlen
);
void String::del(const String
& y
, int startpos
)
del(search(startpos
, length(), y
.chars(), y
.length()), y
.length());
void String::del(const SubString
& y
, int startpos
)
del(search(startpos
, length(), y
.chars(), y
.length()), y
.length());
void String::del(char c
, int startpos
)
del(search(startpos
, length(), c
), 1);
SubString
String::at(int first
, int len
)
return _substr(first
, len
);
SubString
String::operator() (int first
, int len
)
return _substr(first
, len
);
SubString
String::before(int pos
)
SubString
String::through(int pos
)
return _substr(0, pos
+1);
SubString
String::after(int pos
)
return _substr(pos
+ 1, length() - (pos
+ 1));
SubString
String::from(int pos
)
return _substr(pos
, length() - pos
);
SubString
String::at(const String
& y
, int startpos
)
int first
= search(startpos
, length(), y
.chars(), y
.length());
return _substr(first
, y
.length());
SubString
String::at(const SubString
& y
, int startpos
)
int first
= search(startpos
, length(), y
.chars(), y
.length());
return _substr(first
, y
.length());
SubString
String::at(const Regex
& r
, int startpos
)
int first
= r
.search(chars(), length(), mlen
, startpos
);
return _substr(first
, mlen
);
SubString
String::at(const char* t
, int startpos
)
int first
= search(startpos
, length(), t
, tlen
);
return _substr(first
, tlen
);
SubString
String::at(char c
, int startpos
)
int first
= search(startpos
, length(), c
);
return _substr(first
, 1);
SubString
String::before(const String
& y
, int startpos
)
int last
= search(startpos
, length(), y
.chars(), y
.length());
SubString
String::before(const SubString
& y
, int startpos
)
int last
= search(startpos
, length(), y
.chars(), y
.length());
SubString
String::before(const Regex
& r
, int startpos
)
int first
= r
.search(chars(), length(), mlen
, startpos
);
return _substr(0, first
);
SubString
String::before(char c
, int startpos
)
int last
= search(startpos
, length(), c
);
SubString
String::before(const char* t
, int startpos
)
int last
= search(startpos
, length(), t
, tlen
);
SubString
String::through(const String
& y
, int startpos
)
int last
= search(startpos
, length(), y
.chars(), y
.length());
if (last
>= 0) last
+= y
.length();
SubString
String::through(const SubString
& y
, int startpos
)
int last
= search(startpos
, length(), y
.chars(), y
.length());
if (last
>= 0) last
+= y
.length();
SubString
String::through(const Regex
& r
, int startpos
)
int first
= r
.search(chars(), length(), mlen
, startpos
);
if (first
>= 0) first
+= mlen
;
return _substr(0, first
);
SubString
String::through(char c
, int startpos
)
int last
= search(startpos
, length(), c
);
if (last
>= 0) last
+= 1;
SubString
String::through(const char* t
, int startpos
)
int last
= search(startpos
, length(), t
, tlen
);
if (last
>= 0) last
+= tlen
;
SubString
String::after(const String
& y
, int startpos
)
int first
= search(startpos
, length(), y
.chars(), y
.length());
if (first
>= 0) first
+= y
.length();
return _substr(first
, length() - first
);
SubString
String::after(const SubString
& y
, int startpos
)
int first
= search(startpos
, length(), y
.chars(), y
.length());
if (first
>= 0) first
+= y
.length();
return _substr(first
, length() - first
);
SubString
String::after(char c
, int startpos
)
int first
= search(startpos
, length(), c
);
if (first
>= 0) first
+= 1;
return _substr(first
, length() - first
);
SubString
String::after(const Regex
& r
, int startpos
)
int first
= r
.search(chars(), length(), mlen
, startpos
);
if (first
>= 0) first
+= mlen
;
return _substr(first
, length() - first
);
SubString
String::after(const char* t
, int startpos
)
int first
= search(startpos
, length(), t
, tlen
);
if (first
>= 0) first
+= tlen
;
return _substr(first
, length() - first
);
SubString
String::from(const String
& y
, int startpos
)
int first
= search(startpos
, length(), y
.chars(), y
.length());
return _substr(first
, length() - first
);
SubString
String::from(const SubString
& y
, int startpos
)
int first
= search(startpos
, length(), y
.chars(), y
.length());
return _substr(first
, length() - first
);
SubString
String::from(const Regex
& r
, int startpos
)
int first
= r
.search(chars(), length(), mlen
, startpos
);
return _substr(first
, length() - first
);
SubString
String::from(char c
, int startpos
)
int first
= search(startpos
, length(), c
);
return _substr(first
, length() - first
);
SubString
String::from(const char* t
, int startpos
)
int first
= search(startpos
, length(), t
, tlen
);
return _substr(first
, length() - first
);
int split(const String
& src
, String results
[], int n
, const String
& sep
)
const char* s
= x
.chars();
while (i
< n
&& pos
< sl
)
int p
= x
.search(pos
, sl
, sep
.chars(), sep
.length());
results
[i
].rep
= Salloc(results
[i
].rep
, &(s
[pos
]), p
- pos
, p
- pos
);
int split(const String
& src
, String results
[], int n
, const Regex
& r
)
const char* s
= x
.chars();
while (i
< n
&& pos
< sl
)
p
= r
.search(s
, sl
, matchlen
, pos
);
results
[i
].rep
= Salloc(results
[i
].rep
, &(s
[pos
]), p
- pos
, p
- pos
);
#if defined(__GNUG__) && !defined(NO_NRV)
String
join(String src
[], int n
, const String
& separator
) return x
;
for (int i
= 0; i
< n
; ++i
)
xlen
+= (n
- 1) * sep
.length();
for (i
= 0; i
< n
- 1; ++i
)
ncopy(src
[i
].chars(), &(x
.rep
->s
[j
]), src
[i
].length());
ncopy(sep
.chars(), &(x
.rep
->s
[j
]), sep
.length());
ncopy0(src
[i
].chars(), &(x
.rep
->s
[j
]), src
[i
].length());
String
join(String src
[], int n
, const String
& separator
)
for (int i
= 0; i
< n
; ++i
)
xlen
+= (n
- 1) * sep
.length();
for (i
= 0; i
< n
- 1; ++i
)
ncopy(src
[i
].chars(), &(x
.rep
->s
[j
]), src
[i
].length());
ncopy(sep
.chars(), &(x
.rep
->s
[j
]), sep
.length());
ncopy0(src
[i
].chars(), &(x
.rep
->s
[j
]), src
[i
].length());
StrRep
* Sreverse(StrRep
* src
, StrRep
* dest
)
dest
= Salloc(dest
, src
->s
, n
, n
);
StrRep
* Supcase(StrRep
* src
, StrRep
* dest
)
if (src
!= dest
) dest
= Salloc(dest
, src
->s
, n
, n
);
for (; p
< e
; ++p
) if (islower(*p
)) *p
= toupper(*p
);
StrRep
* Sdowncase(StrRep
* src
, StrRep
* dest
)
if (src
!= dest
) dest
= Salloc(dest
, src
->s
, n
, n
);
for (; p
< e
; ++p
) if (isupper(*p
)) *p
= tolower(*p
);
StrRep
* Scapitalize(StrRep
* src
, StrRep
* dest
)
if (src
!= dest
) dest
= Salloc(dest
, src
->s
, n
, n
);
if (at_word
= islower(*p
))
at_word
= isupper(*p
) || isdigit(*p
);
else if (!islower(*p
) && !isdigit(*p
))
#if defined(__GNUG__) && !defined(NO_NRV)
String
replicate(char c
, int n
) return w
;
w
.rep
= Sresize(w
.rep
, n
);
while (n
-- > 0) *p
++ = c
;
String
replicate(const String
& y
, int n
) return w
w
.rep
= Sresize(w
.rep
, n
* len
);
ncopy(y
.chars(), p
, len
);
String
common_prefix(const String
& x
, const String
& y
, int startpos
) return r
;
const char* xchars
= x
.chars();
const char* ychars
= y
.chars();
const char* xs
= &(xchars
[startpos
]);
const char* topx
= &(xchars
[x
.length()]);
const char* ys
= &(ychars
[startpos
]);
const char* topy
= &(ychars
[y
.length()]);
for (int l
= 0; xs
< topx
&& ys
< topy
&& *xs
++ == *ys
++; ++l
);
r
.rep
= Salloc(r
.rep
, ss
, l
, l
);
String
common_suffix(const String
& x
, const String
& y
, int startpos
) return r
;
const char* xchars
= x
.chars();
const char* ychars
= y
.chars();
const char* xs
= &(xchars
[x
.length() + startpos
]);
const char* botx
= xchars
;
const char* ys
= &(ychars
[y
.length() + startpos
]);
const char* boty
= ychars
;
for (int l
= 0; xs
>= botx
&& ys
>= boty
&& *xs
== *ys
; --xs
, --ys
, ++l
);
r
.rep
= Salloc(r
.rep
, ++xs
, l
, l
);
String
replicate(char c
, int n
)
w
.rep
= Sresize(w
.rep
, n
);
while (n
-- > 0) *p
++ = c
;
String
replicate(const String
& y
, int n
)
w
.rep
= Sresize(w
.rep
, n
* len
);
ncopy(y
.chars(), p
, len
);
String
common_prefix(const String
& x
, const String
& y
, int startpos
)
const char* xchars
= x
.chars();
const char* ychars
= y
.chars();
const char* xs
= &(xchars
[startpos
]);
const char* topx
= &(xchars
[x
.length()]);
const char* ys
= &(ychars
[startpos
]);
const char* topy
= &(ychars
[y
.length()]);
for (int l
= 0; xs
< topx
&& ys
< topy
&& *xs
++ == *ys
++; ++l
);
r
.rep
= Salloc(r
.rep
, ss
, l
, l
);
String
common_suffix(const String
& x
, const String
& y
, int startpos
)
const char* xchars
= x
.chars();
const char* ychars
= y
.chars();
const char* xs
= &(xchars
[x
.length() + startpos
]);
const char* botx
= xchars
;
const char* ys
= &(ychars
[y
.length() + startpos
]);
const char* boty
= ychars
;
for (int l
= 0; xs
>= botx
&& ys
>= boty
&& *xs
== *ys
; --xs
, --ys
, ++l
);
r
.rep
= Salloc(r
.rep
, ++xs
, l
, l
);
istream
& operator>>(istream
& s
, String
& x
)
if (!s
.ipfx(0) || (!(s
.flags() & ios::skipws
) && !ws(s
)))
s
.clear(ios::failbit
|s
.rdstate()); // Redundant if using GNU iostreams.
x
.rep
= Sresize(x
.rep
, 20);
register streambuf
*sb
= s
.rdbuf();
while ((ch
= sb
->sbumpc()) != EOF
)
x
.rep
= Sresize(x
.rep
, i
+1);
int new_state
= s
.rdstate();
if (i
== 0) new_state
|= ios::failbit
;
if (ch
== EOF
) new_state
|= ios::eofbit
;
int readline(istream
& s
, String
& x
, char terminator
, int discard
)
x
.rep
= Sresize(x
.rep
, 80);
register streambuf
*sb
= s
.rdbuf();
while ((ch
= sb
->sbumpc()) != EOF
)
if (ch
!= terminator
|| !discard
)
x
.rep
= Sresize(x
.rep
, i
+1);
if (ch
== EOF
) s
.clear(ios::eofbit
|s
.rdstate());
ostream
& operator<<(ostream
& s
, const SubString
& x
)
const char* a
= x
.chars();
const char* lasta
= &(a
[x
.length()]);
// from John.Willis@FAS.RI.CMU.EDU
int String::freq(const SubString
& y
) const
for (unsigned int i
= 0; i
< length(); i
++)
if (match(i
,length(),0,y
.chars(), y
.length())>= 0) found
++;
int String::freq(const String
& y
) const
for (unsigned int i
= 0; i
< length(); i
++)
if (match(i
,length(),0,y
.chars(),y
.length()) >= 0) found
++;
int String::freq(const char* t
) const
for (unsigned int i
= 0; i
< length(); i
++)
if (match(i
,length(),0,t
) >= 0) found
++;
int String::freq(char c
) const
for (unsigned int i
= 0; i
< length(); i
++)
if (match(i
,length(),0,&c
,1) >= 0) found
++;
if (rep
== 0 // don't have a rep
|| rep
->len
> rep
->sz
// string oustide bounds
|| rep
->s
[rep
->len
] != 0) // not null-terminated
error("invariant failure");
int SubString::OK() const
int v
= S
!= (const char*)0; // have a String;
v
&= S
.OK(); // that is legal
v
&= pos
+ len
>= S
.rep
->len
;// pos and len within bounds
if (!v
) S
.error("SubString invariant failure");