Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

bytes_seq.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Fri Apr 22 13:17:30 EDT 2005 by irina.furman@intel.com 
00020 //      modified on Tue Mar 22 14:47:05 EST 2005 by ken@xorian.net         
00021 //      modified on Wed Jul 31 13:28:49 EDT 2002 by kcschalk@shr.intel.com 
00022 //      modified on Tue Feb  8 11:55:15 PST 2000 by mann  
00023 //      modified on Thu Jun 27 18:00:28 PDT 1996 by heydon
00024 //      modified on Wed Mar  8 23:34:42 PST 1995 by levin
00025 
00026 //  *********************************
00027 //  *  Implementation of bytes_seq  *
00028 //  *********************************
00029 
00030 #include "bytes_seq.H"
00031 
00032 typedef char *chars;
00033 typedef bytes_seq_impl::rep rep;
00034 
00035 //  **************
00036 //  *  Utilities  *
00037 //  ***************
00038 
00039 inline int round_up(int v, int m) { return ((v + m - 1)/m)*m; }
00040 
00041 rep *bytes_seq_impl::allocate_buffer(int len_hint, int bytes)
00042 {
00043   // Allocate a buffer with room for "len_hint" byte-str's and "bytes"
00044   // characters of string bodies, ensuring that the buffer is aligned
00045   // for pointer storage.
00046   int size = bytes_seq::min_size(len_hint) + round_up(bytes, sizeof(chars));
00047   char* buffer = (char*) NEW_PTRFREE_ARRAY(chars, size/sizeof(chars));
00048   rep *p = (rep *) buffer;
00049   p->h.storage = grow;
00050   p->h.len = 0;
00051   p->h.bodies = p->h.limit = &buffer[size];
00052   return p;
00053 }
00054 
00055 void bytes_seq_impl::expand(bytes_seq_impl::rep *&p,
00056                             int len_hint,
00057                             int min_body_add)
00058 {
00059   if (p->h.storage == manual)
00060     throw(bytes_seq::failure("Buffer has insufficient space."));
00061   // Expand storage.  If len_hint is non-negative, it specifies a new length
00062   // hint.  If min_body_add is non-negative, the string space either will be
00063   // doubled (compared to the presently used amount), or increased in size
00064   // by min_body_add, whichever produces a larger resulting buffer.
00065   int new_len = len_hint < 0 ? p->h.len : len_hint;
00066   int body_space =
00067     min_body_add >= 0 ? max(2*(p->h.limit - p->h.bodies), min_body_add) : 0;
00068   rep *new_p = allocate_buffer(new_len, body_space);
00069 
00070   new_p->h.storage = p->h.storage;
00071   new_p->h.bodies = new_p->h.limit - body_space;
00072 
00073   // Copy string bodies (if any) as a unit
00074   memcpy(new_p->h.bodies, p->h.bodies, body_space);
00075 
00076   // Copy byte_str's one at at time, relocating if necessary.  This code
00077   // isn't portable according to the ARM, but should work on any machine
00078   // with a flat memory architecture.
00079   byte_str *seq = &p->base;
00080   byte_str *new_seq = &new_p->base;
00081   int offset = new_p->h.bodies - p->h.bodies;
00082   for (int i = 0; i < p->h.len; i++) {
00083     assert(seq[i].p >= p->h.bodies && seq[i].p < p->h.limit);
00084     new_seq[i].p = seq[i].p + offset;
00085     new_seq[i].l = seq[i].l;
00086   }
00087   new_p->h.len = p->h.len;
00088 
00089   delete[] (chars *)p;
00090   p = new_p;
00091 
00092 }
00093 
00094 
00095 //  **********************************
00096 //  *  Constructors and Destructors  *
00097 //  **********************************
00098 
00099 bytes_seq::bytes_seq(int len_hint, int bytes)
00100 {
00101   if (len_hint == 0 && bytes == 0)
00102     // Defer allocation until needed.  The first allocation might
00103     // be via SRPC::recv_bytes_seq, which can allocate precisely the
00104     // right amount.
00105     p = NULL;
00106   else p = bytes_seq_impl::allocate_buffer(len_hint, bytes);
00107 }
00108 
00109 bytes_seq::bytes_seq(void **buffer, int bytes) throw (bytes_seq::failure)
00110 {
00111   p = (rep *)buffer;
00112   p->h.storage = bytes_seq_impl::manual;
00113   p->h.len = 0;
00114   p->h.bodies = p->h.limit = (char *)buffer + bytes;
00115 }
00116 
00117 bytes_seq::~bytes_seq()
00118 {
00119   if (p == NULL || p->h.storage == bytes_seq_impl::manual) return;
00120   delete[] (chars *)p;
00121 }
00122 
00123 /* static */ int bytes_seq::min_size(int len)
00124 {
00125   // This calculation allows for the possibility that padding will be
00126   // inserted between 'h' and 'base'.  It does this by computing the
00127   // size of 'rep', which includes (in effect) a single-element sequence
00128   // (i.e., base), then adding additional space for len-1 additional
00129   // sequence elements (each a 'byte_str').
00130   return
00131     round_up(sizeof(bytes_seq_impl::rep) + (len-1)*(sizeof(byte_str)),
00132             sizeof(chars));
00133 }
00134 
00135 
00136 //  ***************************
00137 //  *  Sequence modification  *
00138 //  ***************************
00139 
00140 void bytes_seq::append(const byte_str &b) throw(bytes_seq::failure)
00141 {
00142   if (p == NULL) p = bytes_seq_impl::allocate_buffer();
00143   int bytes_for_body = b.l;
00144   byte_str *seq = &p->base;    // base of pointer vector
00145   char *s_copy = p->h.bodies - bytes_for_body;
00146 
00147   // The following pointer comparison is portable, per ARM 5.9, since
00148   // both point into the same array (or one beyond its end).
00149   if (&seq[p->h.len+1].p > (chars *)s_copy) {
00150     // No space in buffer for string body and pointer.  Expand first.
00151     bytes_seq_impl::expand(p, 1+2*p->h.len, bytes_for_body);
00152     // Recompute pointers affected by 'expand'
00153     seq = &p->base;
00154     s_copy = p->h.bodies - bytes_for_body;
00155   }
00156   // Now there must be room, regardless of whether we expanded or not.
00157   assert(&seq[p->h.len+1].p <=  (chars *)s_copy);
00158 
00159   strcpy(s_copy, b.p);
00160   seq[p->h.len].p = p->h.bodies = s_copy;
00161   seq[p->h.len].l = bytes_for_body;
00162   p->h.len++;
00163 }

Generated on Mon May 8 00:48:56 2006 for Vesta by  doxygen 1.4.2