home *** CD-ROM | disk | FTP | other *** search
- //////////////////////////////////////////////////////////////////
- // vector.mth: Template methods for fixed-length shared vectors.
- // Copyright(c) 1993 Azarona Software. All rights reserved.
- //////////////////////////////////////////////////////////////////
- #include "placenew.h"
-
- template<class TYPE>
- void *VecRep<TYPE>::operator new(size_t n, unsigned d)
- // The new operator overloaded for VecRep, so
- // that the vector elements are stored immediately
- // after the reference count. Here, n is sizeof(VecRep)
- // and d is the number of elements to be allocated in the
- // vector. If allocation fails or d == 0, we reference
- // null_rep, the null VecRep object.
- {
- // Compute what pointer to object should be.
- // Note: One element already accounted for in n.
- void *p = (d == 0) ? 0 : new char[n+(d-1)*sizeof(TYPE)];
- if (p == 0) { // If pointer is null, bind to null_rep
- p = &null_rep;
- null_rep.refcnt++;
- }
- return p;
- }
-
- template<class TYPE>
- void VecRep<TYPE>::operator delete(void *p)
- // The delete operator is overloaded to delete
- // all of the vector data, as well as the
- // refcnt and alloclen fields.
- {
- // Since null_rep is allocated statically,
- // p should never point to null_rep.
- // However, it might under the following conditions:
- // (1) A vector is declared in the static segment,
- // (2) the allocation of dynamic memory for the
- // vector fails, (3) the null_rep object hasn't
- // been constructed yet. This condition occurs
- // very rarely, but it can happen.
- if (p != &null_rep) delete[] (char *)p;
- }
-
- template<class TYPE>
- VecRep<TYPE>::VecRep(unsigned d)
- // Constructor to initialize a shared vector rep.
- {
- if (this != &null_rep) {
- // We only want to do the following if we're
- // not referencing null_rep.
- alloclen = d;
- refcnt = 1;
- // We must call the placement constructor for
- // all but the first element
- TYPE *q = data + 1;
- for(unsigned i = 1; i<d; i++, q++) new(q) TYPE;
- }
- }
-
-
- template<class TYPE>
- void VecRep<TYPE>::~VecRep()
- // Destructor to explicitly destroy all elements
- // of the vector, except the first. Note that this
- // effectively keeps null_rep's only element from
- // being destroyed too many times.
- {
- TYPE *q = data + 1;
- for(unsigned i = 1; i<alloclen; i++, q++) q->TYPE::~TYPE();
- }
-
-
- template<class TYPE>
- void Vector<TYPE>::Bind(const Vector<TYPE> &v)
- // This function binds us to the same data that
- // v is bound to, thus sharing v's data.
- // ASSUMES vector not already bound.
- {
- rep = v.rep;
- rep->refcnt++;
- }
-
- template<class TYPE>
- void Vector<TYPE>::Unbind()
- // Unbinds this vector from the shared data. The data
- // is disposed of properly if reference count goes to 0.
- // WARNING: This function should only be called by the
- // destructor, or be immediately followed by a call to
- // Bind(). That's because our internal pointers might
- // be left pointing to freed memory.
- {
- rep->refcnt--;
- // Note: delete handles the possibility of trying to
- // delete null_rep.
- if (rep->refcnt == 0) delete rep;
- }
-
- template<class TYPE>
- void Vector<TYPE>::NewBinding(const Vector<TYPE> &v)
- // Unbinds this vector from the data it shares, and
- // then binds it to the data shared by v.
- {
- // Check for already sharing the same data
- if (rep == v.rep) return;
- Unbind();
- Bind(v);
- }
-
- template<class TYPE>
- int Vector<TYPE>::Alloc(unsigned n)
- // Allocates a block of n elements for this vector.
- // If n == 0 or allocation fails, we bind to the null rep.
- // ASSUMES TYPE has a default constructor.
- // NOTE: This vector better not be bound at this time!
- // Returns 0 if we've bound to null_rep, else 1.
- {
- // You might not think we need this if statement.
- // Couldn't we do the new() even if n = 0? The
- // answer is no, things get all fouled up, cause
- // multiple reps that are actually null get created
- // but we want only one, and it should be static.
- if (n) {
- rep = new(n) VecRep<TYPE>(n);
- }
- else {
- rep = &VecRep<TYPE>::null_rep;
- rep->refcnt++;
- }
- start = rep->data;
- if (rep != &VecRep<TYPE>::null_rep) {
- len = n;
- stride = 1;
- return 1;
- }
- else {
- len = 0;
- stride = 1;
- return 0;
- }
- }
-
- template<class TYPE>
- Vector<TYPE>::Vector(unsigned n, const TYPE *s)
- // Constructor to allocate space for a n element vector,
- // and, if s != 0, to copy low-level C array into it.
- // If n == 0 or allocation fails, we bind to null rep,
- // and do no copying.
- {
- if (Alloc(n) && s) CopyN(s, n);
- }
-
- template<class TYPE>
- Vector<TYPE>::Vector(const Vector<TYPE> &v)
- // Copy constructor that shares all of the vector v.
- {
- Bind(v);
- len = v.len;
- stride = v.stride;
- start = v.start;
- }
-
- template<class TYPE>
- Vector<TYPE>::Vector(const Vector<TYPE> &v, SliceType styp,
- unsigned n, unsigned str, unsigned ofs)
- // Constructor used to share or copy a slice of an existing
- // vector. If styp = SHARED, then the new vector of
- // length n shares its data with the old vector with the
- // desired stride and offset. Otherwise, a copy is made
- // with a length of n, stride of 1, and offset of 0.
- // If n == 0, it means use v.len for the length.
- // If copying and allocation fails, no copy takes place.
- {
- len = (n) ? n : v.len;
- #ifndef NO_RANGE_CHECK
- // NOTE: This range check code here not shown in book!
- // Keep offset in range, and compute number of
- // elements available, given offset.
- unsigned vlen = v.len;
- if (ofs >= vlen) ofs = vlen ? (vlen-1) : 0;
- unsigned elemavl = vlen - ofs;
- // Keep new stride in range, determine desired length
- // and keep it in range too. Note that elemavl is
- // rounded up so that it covers whole strides.
- if (str == 0) str = 1;
- if (str > elemavl) str = elemavl;
- elemavl += str - (elemavl % str); // Round up to whole strides
- if (len * str > elemavl) len = elemavl / str;
- #endif
- if (styp == SHARED) {
- // Share existing data in v, accumulating offset
- // and stride as needed. Note how stride and
- // starting offset are computed in units of the
- // elements of the real underlying vector.
- Bind(v);
- start = v.start + ofs * v.stride;
- stride = str * v.stride;
- }
- else {
- // Allocate data, then copy the desired slice of the
- // source vector into the destination vector.
- // Note clever recursive call to constructor.
- if (Alloc(len)) Copy(Vector<TYPE>(v, SHARED, len, str, ofs));
- }
- }
-
- #ifndef NO_RANGE_CHECK
-
- template<class TYPE>
- unsigned Vector<TYPE>::CheckIndx(unsigned i) const
- // Check for index being in bounds. If not in
- // bounds, call the error handler.
- {
- if (i >= len) i = HandleRangeErr(i, len);
- return i;
- }
-
- #endif
-
- template<class TYPE>
- void Vector<TYPE>::CopyN(const TYPE *src, unsigned n)
- // Copies as much data as possible from src
- // into this vector, truncating if need be.
- {
- unsigned tlen = len;
- if (tlen > n) tlen = n;
- VecPtr<TYPE> dest(start, stride);
- for (unsigned i=0; i<tlen; i++) {
- *dest = src[i];
- dest++;
- }
- len = tlen; // We have a new logical length!
- }
-
- template<class TYPE>
- void Vector<TYPE>::Copy(const Vector<TYPE> &v)
- // Copies as much data as possible from v into this
- // vector, truncating if need be.
- {
- unsigned tlen = len;
- unsigned vlen = v.len;
- if (tlen > vlen) tlen = vlen;
- VecPtr<const TYPE> src(v.start, v.stride);
- VecPtr<TYPE> dest(start, stride);
- for (unsigned i=0; i<tlen; i++) {
- *dest = *src;
- src++;
- dest++;
- }
- len = tlen; // We have a new logical length!
- }
-
-
- template<class TYPE>
- Vector<TYPE> Vector<TYPE>::Clone() const
- // Return a clone of this vector. This clone will
- // be unique, (with vector rep refcnt = 1), and
- // will have a stride of 1.
- // Note: If allocation fails, a null vector is returned.
- {
- Vector<TYPE> temp(len);
- temp.Copy(*this);
- return temp;
- }
-
- template<class TYPE>
- int Vector<TYPE>::EnsureUnique()
- // Ensures that this vector uniquely owns its vector
- // rep, (ie. the reference count is 1).
- // Might have to copy vector rep data to ensure this.
- // Returns 1 if can make unique, 0 if can't (allocation
- // for copy failed.)
- {
- if (!IsUnique()) { // Need to copy to make unique
- Vector<TYPE> &c = Clone(); // Attempt to copy
- if (c.IsNull()) return 0; // Couldn't copy
- Share(c); // Share with copy
- }
- return 1;
- }
-
-
- template<class TYPE>
- void Vector<TYPE>::Share(const Vector<TYPE> &v)
- // Shares with the elements in vector v.
- {
- NewBinding(v);
- len = v.len;
- stride = v.stride;
- start = v.start;
- }
-
- template<class TYPE>
- void Vector<TYPE>::SetElements(const TYPE &x)
- // Sets every element of this vector to x.
- {
- VecPtr<TYPE> cursor(start, stride);
- for (unsigned i = 0; i<len; i++) {
- *cursor = x;
- cursor++;
- }
- }
-