// file: scl.h // author: Steve Norman // scl (Simple Class Library) Version 1.2 (Sept. 10, 1997) // // This code has been carefully tested. // However, that is NOT a GUARANTEE that this code is completely // free of defects. // // If any defects are discovered that interfere with the development // of programs in ENGG 335 labs in Fall 1997, this code will be // replaced with a new version, and announcements will be made in // lectures and labs to tell students to make sure that they are using // the new version. // // No defects were discovered in Fall 1997. (That STILL does NOT // GUARANTEE that the code is defect-free.) Except for changes to // this comment, this code has not been changed. // // Copyright (C) 1997 by S. A. Norman of the University of Calgary // Dept of Electrical and Computer Engineering. Permission is // granted to use this code, modified or unmodified, for any // purpose you like. I request only that you maintain this // copyright notice in your code. #ifndef SCL_H #define SCL_H #include // *** global functions for range checking void scl_range_fail(int index, int size, const char* type_str); inline void scl_range_check(int index, int size, const char* type_str) { if (index < 0 || index >= size) scl_range_fail(index, size, type_str); } // *** sclString class and related inline functions class ostream; class istream; class sclString { public: sclString(); sclString(char c); sclString(const char* p); sclString(const sclString& source); ~sclString(); sclString& operator =(char c); sclString& operator =(const char* p); sclString& operator =(const sclString& rhs); // supply pointer to null-terminated C string const char* c_str() const; // access to single chars const char operator [](int index) const; char& operator [](int index); // length inquiry, growing and shrinking int length() const; void append(char c); void append(const char* p); void append(const sclString& s); void truncate(int new_length); // global functions for I/O friend ostream& operator <<(ostream& ostr, const sclString& s); friend istream& operator >>(istream& istr, sclString& s); friend istream& getline(istream& istr, sclString& s); private: char *storage; int lengthM; // does not count terminating '\0' int capacityM; // includes '\0', so must be > lengthM; enum { MEM_CHUNK_SIZE = 16 }; void alloc_buffer(int min_cap); void prepare_for_append(int new_length); void expand_for_input(); static char * const empty_string; static void dispose_of(char* p); }; inline const char* sclString::c_str() const { return storage; } inline const char sclString::operator [](int index) const { scl_range_check(index, lengthM, "sclString"); return storage[index]; } inline char& sclString::operator [](int index) { scl_range_check(index, lengthM, "sclString"); return storage[index]; } inline int sclString::length() const { return lengthM; } inline void sclString::dispose_of(char *p) { if (p != empty_string) delete [] p; } // 6 comparisons of sclString with sclString inline int operator ==(const sclString& lhs, const sclString& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) == 0; } inline int operator !=(const sclString& lhs, const sclString& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) != 0; } inline int operator <(const sclString& lhs, const sclString& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) < 0; } inline int operator <=(const sclString& lhs, const sclString& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) <= 0; } inline int operator >(const sclString& lhs, const sclString& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) > 0; } inline int operator >=(const sclString& lhs, const sclString& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) >= 0; } // 6 comparisons of sclString (left side) with const char * (right side) inline int operator ==(const sclString& lhs, const char *rhs) { return strcmp(lhs.c_str(), rhs) == 0; } inline int operator !=(const sclString& lhs, const char *rhs) { return strcmp(lhs.c_str(), rhs) != 0; } inline int operator <(const sclString& lhs, const char *rhs) { return strcmp(lhs.c_str(), rhs) < 0; } inline int operator <=(const sclString& lhs, const char *rhs) { return strcmp(lhs.c_str(), rhs) <= 0; } inline int operator >(const sclString& lhs, const char *rhs) { return strcmp(lhs.c_str(), rhs) > 0; } inline int operator >=(const sclString& lhs, const char *rhs) { return strcmp(lhs.c_str(), rhs) >= 0; } // 6 comparisons of const char * (left side) with sclString (right side) inline int operator ==(const char *lhs, const sclString& rhs) { return strcmp(lhs, rhs.c_str()) == 0; } inline int operator !=(const char *lhs, const sclString& rhs) { return strcmp(lhs, rhs.c_str()) != 0; } inline int operator <(const char *lhs, const sclString& rhs) { return strcmp(lhs, rhs.c_str()) < 0; } inline int operator <=(const char *lhs, const sclString& rhs) { return strcmp(lhs, rhs.c_str()) <= 0; } inline int operator >(const char *lhs, const sclString& rhs) { return strcmp(lhs, rhs.c_str()) > 0; } inline int operator >=(const char *lhs, const sclString& rhs) { return strcmp(lhs, rhs.c_str()) >= 0; } // *** sclArray class and related inlines template class sclArray { public: sclArray(); sclArray(int init_size); sclArray(const T* p, int n_elements); sclArray(const sclArray& source); ~sclArray(); sclArray& operator =(const sclArray& rhs); void copy_from(const T* p, int n_elements); const T& operator [](int index) const; T& operator [](int index); int size() const; void resize(int new_size); // Advanced features for more efficient memory management. void tight_resize(int new_size); void reserve_capacity(int new_capacity); void tighten_capacity(); private: T* storage; int sizeM; int capacityM; void force_capacity(int new_capacity); }; template inline const T& sclArray::operator [](int index) const { scl_range_check(index, sizeM, "sclArray"); return storage[index]; } template inline T& sclArray::operator [](int index) { scl_range_check(index, sizeM, "sclArray"); return storage[index]; } template inline int sclArray::size() const { return sizeM; } // *** sclArray non-inline member functions template sclArray::sclArray() : storage(0), sizeM(0), capacityM(0) { } template sclArray::sclArray(int init_size) { if (init_size > 0) { sizeM = init_size; storage = new T [sizeM]; capacityM = sizeM; } else { capacityM = sizeM = 0; storage = 0; } } template sclArray::sclArray(const T* p, int n_elements) { if (n_elements > 0) { sizeM = n_elements; storage = new T [sizeM]; capacityM = sizeM; for (int i = 0; i < sizeM; i++) storage[i] = p[i]; } else { capacityM = sizeM = 0; storage = 0; } } template sclArray::sclArray(const sclArray& source) : sizeM(source.sizeM), capacityM(source.sizeM) { if (sizeM > 0) { storage = new T [sizeM]; for (int i = 0; i < sizeM; i++) storage[i] = source.storage[i]; } else storage = 0; } template sclArray::~sclArray() { delete [] storage; storage = 0; } template sclArray& sclArray::operator =(const sclArray& rhs) { if (this != &rhs) { sizeM = rhs.sizeM; if (sizeM == 0) { delete [] storage; storage = 0; capacityM = 0; } else if (capacityM != sizeM) { delete [] storage; storage = new T [sizeM]; capacityM = sizeM; } for (int i = 0; i < sizeM; i++) storage[i] = rhs.storage[i]; } return *this; } template void sclArray::copy_from(const T* p, int n_elements) { if (n_elements < 0) n_elements = 0; sizeM = n_elements; if (sizeM == 0) { delete [] storage; storage = 0; capacityM = 0; } else if (capacityM != n_elements) { delete [] storage; storage = new T [sizeM]; capacityM = sizeM; } for (int i = 0; i < sizeM; i++) storage[i] = p[i]; } template void sclArray::force_capacity(int new_capacity) { if (new_capacity < sizeM) sizeM = new_capacity; if (capacityM != new_capacity) { if (new_capacity == 0) { delete [] storage; storage = 0; capacityM = 0; } else { T* old_storage = storage; storage = new T [new_capacity]; capacityM = new_capacity; for (int i = 0; i < sizeM; i++) storage[i] = old_storage[i]; delete [] old_storage; } } } template void sclArray::resize(int new_size) { if (new_size < 0) new_size = 0; if (new_size > capacityM) force_capacity(3 * (new_size + 1) / 2); sizeM = new_size; } template void sclArray::tight_resize(int new_size) { if (new_size < 0) new_size = 0; force_capacity(new_size); sizeM = new_size; } template void sclArray::reserve_capacity(int new_capacity) { if (capacityM < new_capacity) force_capacity(new_capacity); } template void sclArray::tighten_capacity() { force_capacity(sizeM); } // *** sclGrid class and related inlines template class sclGrid { public: sclGrid(); sclGrid(int init_nrow, int init_ncol); sclGrid(const sclGrid& source); ~sclGrid(); sclGrid& operator =(const sclGrid& rhs); class Row { public: T& operator [](int col_index) { scl_range_check(col_index, row_size, "sclGrid column"); return row_element[col_index]; } const T& operator [](int col_index) const { scl_range_check(col_index, row_size, "sclGrid column"); return row_element[col_index]; } private: Row(T* p, int row_size_) : row_element(p), row_size(row_size_) { } T* row_element; int row_size; friend class sclGrid; }; // end nested class Row const Row operator [](int row_index) const { scl_range_check(row_index, nrowM, "sclGrid row"); return Row(storage[row_index], ncolM); } Row operator [](int row_index) { scl_range_check(row_index, nrowM, "sclGrid row"); return Row(storage[row_index], ncolM); } int nrow() const; int ncol() const; void resize(int new_nrow, int new_ncol); // Advanced features for more efficient memory management. void tight_resize(int new_nrow, int new_ncol); void reserve_capacity(int row_size, int col_size); void tighten_capacity(); private: T **storage; int nrowM; int ncolM; int nrow_available; int ncol_available; void alloc_storage(int nrow_arg, int ncol_arg); void force_capacity(int nrow_arg, int ncol_arg); static void dispose_of(T** p); void copy_elements(const sclGrid& source); }; template inline int sclGrid::nrow() const { return nrowM; } template inline int sclGrid::ncol() const { return ncolM; } // *** sclGrid non-inline member functions template sclGrid::sclGrid() : nrowM(0), ncolM(0) { alloc_storage(0, 0); } template sclGrid::sclGrid(int init_nrow, int init_ncol) { nrowM = (init_nrow > 0 && init_ncol > 0) ? init_nrow : 0; ncolM = (init_nrow > 0 && init_ncol > 0) ? init_ncol : 0; alloc_storage(init_nrow, init_ncol); } template sclGrid::sclGrid(const sclGrid& source) { nrowM = source.nrowM; ncolM = source.ncolM; alloc_storage(nrowM, ncolM); copy_elements(source); } template sclGrid::~sclGrid() { dispose_of(storage); } template sclGrid& sclGrid::operator =(const sclGrid& rhs) { if (this != &rhs) { if (nrowM != rhs.nrowM || ncolM != rhs.ncolM) { dispose_of(storage); nrowM = rhs.nrowM; ncolM = rhs.ncolM; alloc_storage(nrowM, ncolM); } copy_elements(rhs); } return *this; } template void sclGrid::resize(int new_nrow, int new_ncol) { if (new_nrow <= 0 || new_ncol <= 0) { new_nrow = 0; new_ncol = 0; } // Reallocate if necessary. if (new_nrow > nrow_available && new_ncol > ncol_available) force_capacity(3 * (new_nrow + 1) / 2, 3 * (new_ncol + 1) / 2); else if (new_nrow > nrow_available) force_capacity(3 * (new_nrow + 1) / 2, new_ncol); else if (new_ncol > ncol_available) force_capacity(new_nrow, 3 * (new_ncol + 1) / 2); nrowM = new_nrow; ncolM = new_ncol; } template void sclGrid::tight_resize(int new_nrow, int new_ncol) { if (new_nrow <= 0 || new_ncol <= 0) { new_nrow = 0; new_ncol = 0; } force_capacity(new_nrow, new_ncol); nrowM = new_nrow; ncolM = new_ncol; } template void sclGrid::reserve_capacity(int row_size, int col_size) { if (row_size < nrowM) row_size = nrowM; if (col_size < ncolM) col_size = ncolM; if (nrow_available < row_size || ncol_available < col_size) force_capacity(row_size, col_size); } template void sclGrid::tighten_capacity() { force_capacity(nrowM, ncolM); } template void sclGrid::alloc_storage(int nrow_arg, int ncol_arg) { if (nrow_arg <= 0 || ncol_arg <= 0) { nrow_available = ncol_available = 0; storage = 0; return; } nrow_available = nrow_arg; ncol_available = ncol_arg; storage = new T* [nrow_available]; storage[0] = new T [nrow_available * ncol_available]; for (int i = 1; i < nrow_available; i++) storage[i] = storage[i - 1] + ncol_available; } template void sclGrid::force_capacity(int nrow_arg, int ncol_arg) { if (nrow_arg < nrowM) nrowM = nrow_arg; if (ncol_arg < ncolM) ncolM = ncol_arg; if (nrow_arg != nrow_available || ncol_arg != ncol_available) { T** old_storage = storage; alloc_storage(nrow_arg, ncol_arg); for (int i = 0; i < nrowM; i++) for (int j = 0; j < ncolM; j++) storage[i][j] = old_storage[i][j]; dispose_of(old_storage); } } template void sclGrid::dispose_of(T** p) { if (p != 0) { delete [] p[0]; delete [] p; } } template void sclGrid::copy_elements(const sclGrid& source) { for (int i = 0; i < nrowM; i++) for (int j = 0; j < ncolM; j++) storage[i][j] = source.storage[i][j]; } #endif // #define SCL_H