// $Id: String.h,v 1.3 1995/04/03 01:17:47 leavens Exp leavens $

// AUTHOR: Gary T. Leavens, from an earlier version by Al Baker.

#ifndef _STRING_H
#define _STRING_H

#include <iostream.h>
#include "bool.h"

// The implementation may assume that the program
// never runs out of memory for operator new.

class String {

  // ABSTRACTLY: a sequence of characters.  We use <c0,c1,c2,...,cn-1>
  // as notation for a sequence of characters of length n.
  // A String with abstract value <c0,c1,c2,...,cn-1> has as
  // legal indexes the numbers 0 .. n-1 (inclusive).

  // Note that since the length is intrinsic in a String,
  // there will usually *not* be (although there could be)
  // a null character at the end of the sequence.

public:

String();
  // MODIFIES: self
  // POST: self == <> (the empty sequence of characters)
  
String(char c);
  // MODIFIES: self
  // POST: self == <c> (a singleton sequence of characters)

String(const char* s);
  // PRE: s is a null-character-terminated array of characters.
  // MODIFIES: self
  // POST: the value of self is a sequence of characters which is the
  // same as the characters in s up to but *not* including the null character.
  // That is, for 0 <= i <= strlen(s), the ith character of self is
  // the ith character of s.

String(const String& str);  // copy constructor
  // MODIFIES: self
  // POST: self and str have same sequence of characters,
  // but self and str do *not* share any storage.
  // (That is, the objects used to store self and str are distinct.)

~String();
  // MODIFIES: self
  // POST: the memory occupied by self has been reclaimed,
  // and thus the abstract value of self is undefined.

String& operator = (const String& str);
  // PRE: the object self is different from the object str.
  // MODIFIES: self
  // POST: FCTVAL == the object self &&
  // self and str have same sequence of characters,
  // but self and str do *not* share any storage.
  
int Length() const;
  // POST: FCTVAL == the length of self

String Substring (int start, int end) const;
  // MODIFIES: cerr
  // POST: 0 <= start <= end <= (length of self) -->
  // FCTVAL == a String with abstract value
  // the sequence of characters beginning with 0-based index start,
  // and containing all of the characters of self's abstract value
  // up to but not including the one with index end
  // && self and FCTVAL do *not* share any storage
  // && cerr is unchanged.
  // !(0 <= start <= end <= (length of self)) --> an error message is printed
  // to cerr and the program is halted.
  // EXAMPLE: Suppose the abstract value of self is <T,h,i,s,_,i,s>:
  // if start is 0 && end is 4, then FCTVAL would have abstract value <T,h,i,s>
  // if start is 3 && end is 6, then FCTVAL would have abstract value <s,_,i>
  // if start is 0 && end is 0, then FCTVAL would have abstract value <>
  // if start is 7 && end is 7, then FCTVAL would have abstract value <>

int Find(const String& str) const;
  // POST: If str is a substring of self, then FCTVAL is the first character
  // position in self where str starts (indexed from 0).  
  // If str is not a substring of self, then FCTVAL = -1.

char operator [](int i) const;
  // MODIFIES: cerr
  // POST: (i is a legal index of self) -->
  // FCTVAL == the "i-th" character in self (indexed from 0)
  // && cerr is unchanged.
  // (i is not a legal index of self) --> an error message is printed
  // to cerr and the program is halted.

void SetChar(int i, char c);
  // MODIFIES: cerr
  // PRE: i is a legal index of self
  // POST: (i is a legal index of self) -->
  // self is the same sequence as self<entry>,
  // except that the ith character is made to be c
  // && cerr is unchanged.
  // (i is not a legal index of self) --> an error message is printed
  // to cerr and the program is halted.

Boolean operator < (const String& str2) const;
  // POST: FCTVAL == (self < str2)
  //        -- Here (and in all the relational operators we are talking about
  //        -- strict lexicographical ordering on the abstract values.
  // EXAMPLE: Suppose the abstract value of self is <A,l,b,e,r,t>:
  // if the abstract value of str2 is <a,l,b,e,r,t>, then FCTVAL == true,
  // if the abstract value of str2 is <A,l>, then FCTVAL == false,
  // if the abstract value of str2 is <A,l,b,u,m>, then FCTVAL == true

Boolean operator > (const String& str2) const;
  // POST: FCTVAL == (self > str2)

Boolean operator >= (const String& str2) const;
  // POST: FCTVAL == (self >= str2)

Boolean operator <= (const String& str2) const;
  // POST: FCTVAL == (self <= str2)

Boolean operator == (const String& str2) const;
  // POST: FCTVAL == (self == str2)

Boolean operator != (const String& str2) const;
  // POST: FCTVAL == (self != str2)

String operator + (const String& str2) const;
  // POST: FCTVAL == a String with abstract value the sequence of characters
  // beginning those in self, followed by those in str2.
  // && FCTVAL does not share any storage with self and str2.
  // EXAMPLE: suppose the abstract value of self is <M,a,r,y>.
  // If the abstract value of str2 is <>,
  // then the abstract value of FCTVAL would be <M,a,r,y>.
  // If the abstract value of str2 is <b,e,t,h>,
  // then the abstract value of FCTVAL would be <M,a,r,y,b,e,t,h>.
  // -- so this is string concatenation.

char * ToCppString() const;
  // POST: FCTVAL == a pointer to newly allocated space containing the
  // characters in self and a trailing null character.
  // Note that this means that self and the space pointed to by FCTVAL
  // do *not* share any storage.

void AddChar(char ch);
  // MODIFIES: self
  // POST: the abstract value of self is the sequence of characters in the
  // abstract value of self<entry>, with ch added to the end.
  // EXAMPLE: if the abstract value of self<entry> is <A,d,d>
  // and ch is 's', then the abstract value becomes <A,d,d,s>.

#include "String.pri" 
};

#endif

ostream& operator << (ostream& out, const String& str);
  // PRE: out is in a good state
  // MODIFIES: out
  // POST: FCTVAL == the object out && the characters in str are added to out.
