#!/bin/sh # This is a shar archive. # The rest of this file is a shell script which will extract: # # 6_6.h 6_6sub_eq.c 6_6substr.c makefile tst.in tst1.c tst1.cmp # # To extract the files from this shell archive file simply # create a directory for this file, move the archive file # to it and enter the command # # sh filename # # The files will be extracted automatically. # Note: Do not use csh. # # Archive created: Mon Jul 30 23:08:12 EDT 1990 # echo x - 6_6.h sed 's/^X//' > 6_6.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // Exercise 6.6 // String class with value semantics, // delayed copying on assignment, and // substring and contenation operators. #ifndef STR_H # define STR_H # include # include // define the class to manage the // actual character string class srep { char *s; int size; int refcnt; friend class string; friend class substring; srep() { refcnt = 1; s = new char[size = 1]; s[0] = 0; } srep(int sz) { refcnt = 1; s = new char[size = sz]; s[0] = 0; } srep(char *x) { refcnt = 1; s = new char[size = strlen(x) + 1]; strcpy(s, x); } srep(char *x, int len) { refcnt = 1; s = new char[size = len + 1]; strncpy(s, x, len); } srep& operator=(srep &x) { delete s; refcnt = 1; s = new char[size = x.size]; strcpy(s, x.s); return *this; } srep& operator=(char *x) { delete s; refcnt = 1; s = new char[size = strlen(x) + 1]; strcpy(s, x); return *this; } // Reallocate the char space, copying // in the specified string. Delay deleting // the old string in case the string to // copy is from there. void realloc(char *ns, int nlen) { char *olds = s; s = new char[size = nlen]; strcpy(s, ns); delete olds; } ~srep() { delete s; } }; // a helper typedef for the cast // back into a character pointer typedef const char *charptr; class string { srep *p; friend class string_iterator; friend class substring; char *str() { return p->s; } int len() { return p->size; } int refcnt() // DELETE { return p->refcnt; } // DELETE public: // string s; string() { p = new srep; } // string s(5); string(int sz) { p = new srep(sz); } // string s("xyz"); string(char *s) { p = new srep(s); } // string s(string) string(string &s) { s.p->refcnt++; p = s.p; } // string(substring) string(substring&); ~string() { if (--p->refcnt == 0) delete p; } // s = string string& operator=(string &s) { s.p->refcnt++; if (--p->refcnt == 0) delete p; p = s.p; return *this; } // s = "xyz"; string& operator=(char *s) { if (p->refcnt > 1) { p->refcnt--; p = new srep(s); } else p->realloc(s, strlen(s) + 1); return *this; } // s = substring; string& operator=(substring&); // const char *c = s; charptr operator charptr() { return (charptr) str(); } // substring x = s(3,5); substring operator()(int i, int len = -1); // x = s[3]; // s[3] = 'x'; char &operator[](int i) { if (i < 0 || i >= len()) return str()[0]; else return str()[i]; } // concatenation // str = str1 + str2; friend string operator+(string &s1, string &s2) { string ret(s1.len() + s2.len() - 1); strcpy(ret.str(), s1.str()); strcat(ret.str(), s2.str()); return ret; } // append to end // str1 += str2; string &operator+=(string &s) { int nlen = len() + s.len(); // have to disconnect from // the old string if (p->refcnt > 1) { p->refcnt--; srep *oldp = p; p = new srep(oldp->s, nlen); strcat(str(), s.str()); } // we can reallocate the // current string area else { p->realloc(p->s, nlen); strcat(str(), s.str()); } return *this; } friend ostream& operator<<(ostream&, string&); friend istream& operator>>(istream&, string&); #define defop(op) \ friend int operator op(string &x, char *s) \ { return strcmp(x.str(), s) op 0; } \ friend int operator op(string &x, string &y) \ { return strcmp(x.str(), y.str()) op 0; } defop(==); defop(!=); defop(<); defop(<=); defop(>); defop(>=); # undef defop }; class string_iterator { char *cp; public: string_iterator(string &s) { cp = s.str(); } char& operator()() { char *r = cp++; return *r; } }; class substring { friend class string; char *s; // ptr to substring start int len; // length of substring string *str; // ptr to parent string substring(char *chptr, int stlen, string *stptr) { s = chptr; len = stlen; str = stptr; } public: // substring x = ... substring(substring &sst) { s = sst.s; len = sst.len; str = sst.str; } substring &operator=(substring&); substring &operator=(string&); substring &operator=(char*); // cout << substring friend ostream &operator<<(ostream&, substring&); }; // cout << string inline ostream &operator<<(ostream &s, string &x) { #ifdef NOTDEF // DELETE return s << x.str(); #else // DELETE return s << x.str() << // DELETE "[len=" << x.len() << ",ref=" << x.refcnt() << "]"; // DELETE #endif // DELETE } // cout << substring inline ostream &operator<<(ostream &out, substring &sst) { string st(sst); return out << st; } // cin >> string inline istream& operator>>(istream &s, string &x) { char buf[1024]; s >> buf; x = buf; return s; } // s = substring; inline string& string::operator=(substring &sst) { string st(sst); return *this = st; } // string(substring) string::string(substring &sst) { p = new srep(sst.s, sst.len); } // substring = string inline substring &substring::operator=(string &st) { return *this = st.str(); } // substring = substring inline substring &substring::operator=(substring &sst) { string st(sst); return *this = st; } #endif /* STR_H */ !EOF! ls -l 6_6.h echo x - 6_6sub_eq.c sed 's/^X//' > 6_6sub_eq.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // substring = "abc" #ifdef NOTDEF // DELETE #include #else // DELETE #include "6_6.h" // DELETE #endif // DELETE substring &substring::operator=(char *cp) { // disconnect current shared string if (str->p->refcnt > 1) { str->p->refcnt--; srep *oldp = str->p; int oldoffset = s - oldp->s; str->p = new srep(oldp->s, oldp->size); s = str->p->s + oldoffset; } const int stlen = strlen(cp); // same size, simply copy data if (len == stlen) { if (len > 0) memcpy(s, cp, len); } // expand or shrink data area else { // allocate the new data segment char *sps = str->p->s; const int s1len = s - sps; const int s3len = strlen(sps) - len - s1len; char *newdata = new char[s1len + stlen + s3len + 1]; // copy in the data if (s1len > 0) memcpy(newdata, sps, s1len); if (stlen > 0) memcpy(newdata+s1len, cp, stlen); if (s3len > 0) memcpy(newdata + s1len + stlen, s + len, s3len); newdata[s1len + stlen + s3len] = '\0'; // replace pointers delete str->p->s; str->p->s = newdata; str->p->size = s1len + stlen + s3len + 1; s = newdata + s1len; len = stlen; } return *this; } !EOF! ls -l 6_6sub_eq.c echo x - 6_6substr.c sed 's/^X//' > 6_6substr.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // substr = str(3, 5) #ifdef NOTDEF // DELETE #include #else // DELETE #include "6_6.h" // DELETE #endif // DELETE substring string::operator()(int index, int count) { char *s1 = str(); int s1len = strlen(s1); // convert left index, if necessary if (index < 0) index += s1len; // left index past end of string else if (index >= s1len) { substring sst(s1 + s1len, 0, this); return sst; } // convert count, if necessary int numleft = s1len - index; if (count > numleft || count < 0) count = numleft; // copy the substring substring sst(s1 + index, count, this); return sst; } !EOF! ls -l 6_6substr.c echo x - makefile sed 's/^X//' > makefile << '!EOF!' CC= CC -I. -I../../CC CFLAGS= ERROR= ../../error.o all: tst1 tst1: tst1.o 6_6sub_eq.o 6_6substr.o makefile $(CC) $(CFLAGS) tst1.o 6_6sub_eq.o 6_6substr.o -o tst1 $(ERROR) tst1.o: tst1.c 6_6.h 6_6sub_eq.o: 6_6sub_eq.c 6_6.h 6_6substr.o: 6_6substr.c 6_6.h CMP= tst1.cmp OUT= tst1.out tst1.out: tst1 tst.in ; tst1 < tst.in > tst1.out test: all $(OUT) $(CMP) cmp tst1.out tst1.cmp echo tests done !EOF! ls -l makefile echo x - tst.in sed 's/^X//' > tst.in << '!EOF!' hello there again done !EOF! ls -l tst.in echo x - tst1.c sed 's/^X//' > tst1.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include <6_6.h> #include main() { string x[100]; cout << "here we go\n"; for (int n = 0; cin>>x[n]; n++) { string y; if (n == 100) error("too many strings"); cout << (y = x[n]) << "\n"; if (y == "done") break; } cout << "here we go back again\n"; for (int i = n-1; 0 <= i; i--) cout << x[i] << "\n"; string f = "0123456789"; // creates string "0123456789" cout << "f = '" << f << "'\n"; cout << "f(3,3) = '" << f(3,3) << "'\n"; string g = f; cout << "g = '" << g << "'\n"; g(3,3) = "abc"; // creates string "0123456789" cout << "g(3,3)='abc' = '" << g << "'\n"; g = f; cout << "g = '" << g << "'\n"; g(3,5) = "abc"; // creates string "0123456789" cout << "g(3,5)='abc' = '" << g << "'\n"; g = f; cout << "g = '" << g << "'\n"; g(3,1) = "abc"; // creates string "0123456789" cout << "g(3,1)='abc' = '" << g << "'\n"; string f25 = f(2, 4); // creates string "2345" cout << "f25 = '" << f25 << "'\n"; string f69 = f(6); // creates string "6789" cout << "f69 = '" << f69 << "'\n"; string f57 = f(-5, 3); // creates string "567" cout << "f57 = '" << f57 << "'\n"; return 0; } !EOF! ls -l tst1.c echo x - tst1.cmp sed 's/^X//' > tst1.cmp << '!EOF!' here we go hello[len=6,ref=2] there[len=6,ref=2] again[len=6,ref=2] done[len=5,ref=2] here we go back again again[len=6,ref=1] there[len=6,ref=1] hello[len=6,ref=1] f = '0123456789[len=11,ref=1]' f(3,3) = '345[len=4,ref=1]' g = '0123456789[len=11,ref=2]' g(3,3)='abc' = '012abc6789[len=12,ref=1]' g = '0123456789[len=11,ref=2]' g(3,5)='abc' = '012abc89[len=9,ref=1]' g = '0123456789[len=11,ref=2]' g(3,1)='abc' = '012abc456789[len=13,ref=1]' f25 = '2345[len=5,ref=1]' f69 = '6789[len=5,ref=1]' f57 = '567[len=4,ref=1]' !EOF! ls -l tst1.cmp # The following exit is to ensure that extra garbage # after the end of the shar file will be ignored. exit 0