vec_t.cpp

00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 /*<std-header orig-src='shore'>
00025 
00026  $Id: vec_t.cpp,v 1.76 2010/12/08 17:37:34 nhall Exp $
00027 
00028 SHORE -- Scalable Heterogeneous Object REpository
00029 
00030 Copyright (c) 1994-99 Computer Sciences Department, University of
00031                       Wisconsin -- Madison
00032 All Rights Reserved.
00033 
00034 Permission to use, copy, modify and distribute this software and its
00035 documentation is hereby granted, provided that both the copyright
00036 notice and this permission notice appear in all copies of the
00037 software, derivative works or modified versions, and any portions
00038 thereof, and that both notices appear in supporting documentation.
00039 
00040 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00041 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00042 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00043 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00044 
00045 This software was developed with support by the Advanced Research
00046 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00047 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00048 Further funding for this work was provided by DARPA through
00049 Rome Research Laboratory Contract No. F30602-97-2-0247.
00050 
00051 */
00052 
00053 #include "w_defines.h"
00054 
00055 /*  -- do not edit anything above this line --   </std-header>*/
00056 
00057 #ifdef __GNUC__
00058 #pragma implementation "vec_t.h"
00059 #endif
00060 
00061 #define VEC_T_C
00062 #include <cstdlib>
00063 #include <cstring>
00064 #include <w_stream.h>
00065 #include <w_base.h>
00066 #include <w_minmax.h>
00067 #include "basics.h"
00068 #include "vec_t.h"
00069 #include "umemcmp.h"
00070 
00071 
00072 #ifdef EXPLICIT_TEMPLATE
00073 // these templates are not used by vec_t, but are so common that
00074 // we instantiate them here
00075 template class w_auto_delete_array_t<cvec_t>;
00076 template class w_auto_delete_array_t<vec_t>;
00077 #endif
00078 
00079 
00080 /**\cond skip */
00081 cvec_t                cvec_t::pos_inf;
00082 cvec_t                cvec_t::neg_inf;
00083 CADDR_T               cvec_t::zero_location=(CADDR_T)&(cvec_t::neg_inf);
00084 vec_t&                vec_t::pos_inf = *(vec_t*) &cvec_t::pos_inf;
00085 vec_t&                vec_t::neg_inf = *(vec_t*) &cvec_t::neg_inf;
00086 
00087 cvec_t::cvec_t(const cvec_t& /*v*/)
00088 {
00089     cerr << "cvec_t: disabled member called" << endl;
00090     cerr << "failed at \"" << __FILE__ << ":" << __LINE__ 
00091          << "\"" << endl;
00092     abort();
00093 }
00094 
00095 cvec_t::~cvec_t()
00096 {
00097     if (_is_large()) {
00098         free(_base);
00099     }
00100 }
00101 
00102 void cvec_t::split(size_t l1, cvec_t& v1, cvec_t& v2) const
00103 {
00104     size_t min = 0;
00105     int i;
00106     for (i = 0; i < _cnt; i++)  {
00107         if (l1 > 0)  {
00108             min = (_base[i].len > l1) ? l1 : _base[i].len;
00109             v1.put(_base[i].ptr, min);
00110             l1 -= min; 
00111         }
00112         if (l1 <= 0) break;
00113     }
00114     
00115     for ( ; i < _cnt; i++)  {
00116         v2.put(_base[i].ptr + min, _base[i].len - min);
00117         min = 0;
00118     }
00119 }
00120 
00121 cvec_t& cvec_t::put(const cvec_t& v, size_t start, size_t num_bytes)
00122 {
00123     int i;
00124     size_t start_byte, start_elem, total;
00125 
00126     if (v.size() < start+num_bytes) {
00127         w_assert3(v.size() >= start+num_bytes );
00128     }
00129 
00130     // find start in v
00131     for (i = 0, total = 0; i < v._cnt && total <= start; i++) {
00132         total += v._base[i].len;
00133     }
00134    
00135     // check for possible overflow
00136     if (_cnt+v._cnt > max_small) {
00137         _grow(_cnt+v._cnt);
00138     }
00139 
00140     start_elem = i-1;
00141     // first byte in the starting array element
00142     start_byte = start - (total - v._base[start_elem].len);
00143 
00144     // fill in the new vector
00145     _base[_cnt].ptr = v._base[start_elem].ptr+start_byte;
00146     _base[_cnt].len = v._base[start_elem].len-start_byte;
00147     _cnt++;
00148     w_assert3(_cnt <= _max_cnt()); 
00149     for (i = 1, total = _base[_cnt-1].len; total < num_bytes; i++) {
00150         _base[_cnt].ptr = v._base[start_elem+i].ptr;
00151         _base[_cnt].len = v._base[start_elem+i].len;
00152         total += _base[_cnt++].len;
00153         w_assert3(_cnt <= _max_cnt()); 
00154     }
00155     _base[_cnt - 1].len -= total-num_bytes;
00156 
00157     _size += num_bytes;
00158     w_assert3(check_size());
00159     return *this;
00160 }
00161 
00162 cvec_t& cvec_t::put(const void* p, size_t l)  
00163 {
00164     if (_cnt+1 > max_small) {
00165         _grow(_cnt+1);
00166     }
00167 
00168     // to make zvecs work:
00169     _base[_cnt].ptr = (unsigned char*)p; 
00170     _base[_cnt].len = l;
00171     if(l>0) {
00172         _cnt++;
00173            w_assert3(_cnt <= _max_cnt()); 
00174         _size += l;
00175     }
00176     return *this;
00177 }
00178 
00179 bool cvec_t::check_size() const
00180 {
00181     w_assert1(_size == recalc_size());
00182     return true;
00183 }
00184 
00185 size_t cvec_t::recalc_size() const 
00186 {
00187     // w_assert1(! is_pos_inf() && ! is_neg_inf() );
00188     size_t l;
00189     int i;
00190     for (i = 0, l = 0; i < _cnt; l += _base[i++].len) ;
00191     return l;
00192 }
00193 
00194 // Scatter:
00195 // write data from void *p into the area described by this vector.
00196 // Copy no more than "limit" bytes. 
00197 // Does NOT update the vector so caller must keep track
00198 // of the limit to know what is good and what isn't.
00199 // It is a const function because it does not update *this
00200 // even though it does update that which *this describes.
00201 const vec_t& vec_t::copy_from(
00202     const void* p,
00203     size_t limit,
00204     size_t offset)                 const// offset in the vector
00205 {
00206     w_assert1(! is_pos_inf() && ! is_neg_inf() && !is_null() );
00207     w_assert1( _base[0].ptr != zero_location );
00208 
00209     char* s = (char*) p;
00210     for (int i = 0; (i < _cnt) && (limit>0); i++) {
00211         if ( offset < _base[i].len ) {
00212             size_t elemlen = ((_base[i].len - offset > limit)?
00213                                  limit : (_base[i].len - offset)) ;
00214             memcpy((char*)_base[i].ptr + offset, s, elemlen); 
00215             w_assert3(limit >= elemlen);
00216             limit -= elemlen;
00217             s += elemlen;
00218         } 
00219         if (_base[i].len > offset) {
00220             offset = 0;
00221         } else {
00222             offset -= _base[i].len;
00223         }
00224     }
00225     return *this;
00226 }
00227 
00228 // copies from vec to p;  returns # bytes copied
00229 size_t cvec_t::copy_to(void* p, size_t limit) const 
00230 {
00231     w_assert1(! is_pos_inf() && ! is_neg_inf() );
00232     char* s = (char*) p;
00233     for (int i = 0; i < _cnt && limit > 0; i++) {
00234         size_t n = limit > _base[i].len ? _base[i].len : limit;
00235         if(_base[i].ptr == zero_location) {
00236             memset(s, '\0', n);
00237         } else {
00238             memcpy(s, _base[i].ptr, n);
00239         }
00240         w_assert3(limit >= n);
00241         limit -= n;
00242         s += n;
00243     }
00244     return s - (char*)p;
00245 }
00246 
00247 // copies from s to this
00248 vec_t& vec_t::copy_from(const cvec_t& s) 
00249 {
00250     bool        zeroing=false;
00251     int         j = 0;
00252     char*         p = (char*) _base[j].ptr;
00253     size_t         l = _base[j].len;
00254 
00255     w_assert1(size() >= s.size());
00256     w_assert1(_base[0].ptr != zero_location);
00257     
00258     for (int i = 0; i < s._cnt; i++)  {
00259         const unsigned char* pp = s._base[i].ptr;
00260         if(pp == zero_location) zeroing = true;
00261         size_t left = s._base[i].len;
00262         while (l <= left && j < _cnt)  {
00263             if( zeroing) {
00264                 memset(p, '\0', l);
00265             } else {
00266                 memcpy(p, pp, l);
00267             }
00268             pp += l;
00269             left -= l;
00270             j++;
00271             if (j >= _cnt) break;  // out of while loop
00272             l = _base[j].len;
00273             p = (char*) _base[j].ptr;
00274         }
00275         if (left)  {
00276             if( zeroing) {
00277                 memset(p, '\0', left);
00278             } else {
00279                 memcpy(p, pp, left);
00280             }
00281             pp += left;
00282             w_assert3(l >= left);
00283             l -= left;
00284         }
00285     }
00286     return *this;
00287 }
00288 
00289 vec_t& vec_t::copy_from(const cvec_t& ss, size_t offset, size_t limit, size_t myoffset)
00290 {
00291     bool        zeroing=false;
00292     vec_t s;
00293     s.put(ss, offset, limit);
00294 
00295     w_assert1(size() >= s.size());
00296     w_assert1(_base[0].ptr != zero_location);
00297 
00298     size_t ssz = s.size(), dsz = size();
00299     if (offset > ssz)                 offset = ssz;
00300     if (limit > ssz - offset)   limit = ssz - offset;
00301     if (myoffset > dsz)                offset = dsz;
00302 
00303     int j;
00304     for (j = 0; j < _cnt; j++)  {
00305         if (myoffset > _base[j].len)
00306             myoffset -= _base[j].len;
00307         else  
00308             break;
00309     }
00310     char* p = ((char*)_base[j].ptr) + myoffset;
00311     size_t l = _base[j].len - myoffset;
00312 
00313     w_assert1(dsz <= limit);
00314 
00315     size_t done;
00316     int i;
00317     for (i = 0, done = 0; i < s._cnt && done < limit; i++)  {
00318         const unsigned char* pp = s._base[i].ptr;
00319         if(pp == zero_location) zeroing = true;
00320         size_t left = s._base[i].len;
00321         if (limit - done < left)  left = limit - done;
00322         while (l < left)  {
00323             if(zeroing) {
00324                 memset(p, '\0', l);
00325             } else {
00326                 memcpy(p, pp, l);
00327             }
00328             done += l, pp += l;
00329             left -= l;
00330             j++;
00331             if (j >= _cnt) break;  // out of while loop
00332             l = _base[j].len;
00333             p = (char*) _base[j].ptr;
00334         }
00335         if (left)  {
00336             if(zeroing) {
00337                 memset(p, '\0', left);
00338             } else {
00339                 memcpy(p, pp, left);
00340             }
00341             pp += left;
00342             l -= left;
00343             done += left;
00344         }
00345     }
00346     return *this;
00347 }
00348 
00349 cvec_t& cvec_t::put(const cvec_t& v)
00350 {
00351     w_assert1(! is_pos_inf() && ! is_neg_inf());
00352     if (_cnt+v._cnt > max_small) {
00353         _grow(_cnt+v._cnt);
00354     }
00355     for (int i = 0; i < v._cnt; i++)  {
00356         _base[_cnt + i].ptr = v._base[i].ptr;
00357         _base[_cnt + i].len = v._base[i].len;
00358     }
00359     _cnt += v._cnt;
00360     w_assert3(_cnt <= _max_cnt()); 
00361     _size += v._size;
00362 
00363     w_assert3(check_size());
00364     return *this;
00365 }
00366 
00367 int cvec_t::cmp(const void* s, size_t l) const
00368 {
00369     if (is_pos_inf()) return 1;
00370     if (is_neg_inf()) return -1;
00371     if (is_null()) {
00372         if(l==0) return 0;
00373         // l > 0 means this < l
00374         return -1;
00375     }
00376 
00377     size_t acc = 0;
00378     for (int i = 0; i < _cnt && acc < l; i++)  {
00379         int d = umemcmp(_base[i].ptr, ((char*)s) + acc,
00380                        _base[i].len < l - acc ? _base[i].len : l - acc);
00381         if (d) return d;
00382         acc += _base[i].len;
00383     }
00384     return acc - l;        // longer wins
00385 }
00386 
00387 int cvec_t::cmp(const cvec_t& v, size_t* common_size) const
00388 {
00389     // w_assert1(! (is_pos_inf() && v.is_pos_inf()));
00390     // w_assert1(! (is_neg_inf() && v.is_neg_inf()));
00391 
00392     // it is ok to compare +infinity with itself or -infinity with itself
00393     if (&v == this) {        // same address
00394         if (common_size) *common_size = v.size();
00395         return 0; 
00396     }
00397 
00398     // Common size is not set when one of operands is infinity or null
00399     if (is_null() && !v.is_null())  return -1;
00400     if (is_neg_inf() || v.is_pos_inf())  return -1;
00401     if (is_pos_inf() || v.is_neg_inf())  return 1;
00402 
00403         
00404     // Return value : 0 if equal; common_size not set
00405     //              : <0 if this < v
00406     //                 or v is longer than this, but equal in
00407     //                 length of this
00408     //              : >0 if this > v
00409     //                       or this is longer than v, but equal in 
00410     //                 length of v
00411 
00412     int result = 0;
00413 
00414     // l1, i1, j1 refer to this
00415     // l2, i2, j2 refer to v
00416 
00417     size_t l1 = size();
00418     size_t l2 = v.size();
00419     int i1 = 0;
00420     int i2 = 0;
00421     size_t j1 = 0, j2 = 0;
00422     
00423     while (l1 && l2)  {
00424         w_assert3(i1 < _cnt);
00425         w_assert3(i2 < v._cnt);
00426         size_t min = _base[i1].len - j1;
00427         if (v._base[i2].len - j2 < min)  min = v._base[i2].len - j2;
00428 
00429         w_assert3(min > 0);
00430         result = umemcmp(&_base[i1].ptr[j1], &v._base[i2].ptr[j2], min);
00431         if (result) break;
00432         
00433         if ((j1 += min) >= _base[i1].len)        { j1 = 0; ++i1; }
00434         if ((j2 += min) >= v._base[i2].len)        { j2 = 0; ++i2; }
00435 
00436         l1 -= min, l2 -= min;
00437     }
00438 
00439     if (result)  {
00440         if (common_size)  {
00441             while (_base[i1].ptr[j1] == v._base[i2].ptr[j2])  {
00442                 ++j1, ++j2;
00443                 --l1;
00444             }
00445             *common_size = (l1 < size() ? size() - l1 : 0);
00446         }
00447     } else {
00448         result = l1 - l2; // longer wins
00449         if (result && common_size)  {
00450             // common_size is min(size(), v.size());
00451             if (l1 == 0) {
00452                 *common_size = size();
00453             } else {
00454                 w_assert3(l2 == 0);
00455                 *common_size = v.size();
00456             }
00457             w_assert3(*common_size == MIN(size(), v.size()));
00458         }
00459     }
00460     return result;
00461 }
00462 
00463 int cvec_t::checksum() const 
00464 {
00465     int sum = 0;
00466     w_assert1(! is_pos_inf() && ! is_neg_inf());
00467     for (int i = 0; i < _cnt; i++) {
00468         for(size_t j=0; j<_base[i].len; j++) sum += ((char*)_base[i].ptr)[j];
00469     }
00470     return sum;
00471 }
00472 
00473 void cvec_t::calc_kvl(w_base_t::uint4_t& rh) const
00474 {
00475     if (size() <= sizeof(w_base_t::uint4_t))  {
00476         rh = 0;
00477         copy_to(&rh, size());
00478     } else {
00479         w_base_t::uint4_t h = 0;
00480         for (int i = 0; i < _cnt; i++)  {
00481             const unsigned char* s = _base[i].ptr;
00482             for (size_t j = 0; j < _base[i].len; j++)  {
00483                 if (h & 0xf8000000)  
00484                 {
00485                     h = (h & ~0xf8000000) + (h >> 27);
00486                 }
00487                 h = (h << 5) + *s++;
00488             }
00489         }
00490         rh = h;
00491     }
00492 }
00493 
00494 void cvec_t::_grow(int total_cnt)
00495 {
00496     w_assert3(total_cnt > max_small);
00497     w_assert3(_cnt <= _max_cnt()); 
00498 
00499     int prev_max = _max_cnt();
00500   
00501     if (total_cnt > prev_max) {
00502         // overflow will occur
00503 
00504         int grow_to = MAX(prev_max*2, total_cnt);
00505         vec_pair_t* tmp = NULL;
00506 
00507         if (_is_large()) {
00508             tmp = (vec_pair_t*) realloc((char*)_base, grow_to * sizeof(*_base));
00509             if (!tmp) W_FATAL(fcOUTOFMEMORY);
00510         } else {
00511             tmp = (vec_pair_t*) malloc(grow_to * sizeof(*_base));
00512             if (!tmp) W_FATAL(fcOUTOFMEMORY);
00513             for (int i = 0; i < prev_max; i++) {
00514                 tmp[i] = _base[i];
00515             }
00516         }
00517         _pair[0].len = grow_to;
00518         _base = tmp;
00519     }
00520 }
00521 
00522 #include <cctype>
00523 
00524 ostream& operator<<(ostream& o, const cvec_t& v)
00525 {
00526     char        *p;
00527     u_char         c, oldc;
00528     int                repeated;
00529     int                nparts = v.count();
00530     int                i = 0;
00531     size_t        j = 0;
00532     size_t        l = 0;
00533 
00534     o << "{ ";
00535     for(i=0; i< nparts; i++) {
00536         // l = len(i);
00537         l = (i < v._cnt) ? v._base[i].len : 0;
00538 
00539         // p = (char *)v.ptr(i);
00540         p = (i < v._cnt) ? (char *)v._base[i].ptr : (char *)NULL; 
00541 
00542         o << "{" << l << " " << "\"" ;
00543 
00544         repeated=0;
00545         oldc = '\0';
00546         for(j=0; j<l; j++,p++) {
00547             c = *p;
00548             if(c == oldc) {
00549                 repeated++;
00550             } else {
00551                 if(repeated>0) {
00552                     o << "<" <<repeated << " times>";
00553                     repeated = 0;
00554                 }
00555                 if( c == '"' ) {
00556                     o << "\\\"" ;
00557                 } else if( isprint(c) ) {
00558                     if( isascii(c) ) {
00559                         o << c ;
00560                     } else {
00561                         // high bit set: print its octal value
00562                         o << "\\0" << oct << c << dec ;
00563                     }
00564                 } else if(c=='\0') {
00565                     o << "\\0" ;
00566                 } else {
00567                     o << "\\0" << oct << (unsigned int)c << dec ;
00568                 }
00569             }
00570             oldc = c;
00571         }
00572         if(repeated>0) {
00573             o << "<" <<repeated << " times>";
00574             repeated = 0;
00575         }
00576         o <<"\" }";
00577         w_assert3(j==l);
00578         w_assert3(j==v._base[i].len);
00579     }
00580     o <<"}";
00581     return o;
00582 }
00583 
00584 istream& operator>>(istream& is, cvec_t& v)
00585 {
00586     char        c=' ';
00587     size_t      len=0;
00588     int         err = 0;
00589     char        *temp = 0;
00590     const char leftbracket='{';
00591     const char rightbracket='}';
00592 
00593     is.clear();
00594     v.reset();
00595 
00596     enum        {
00597         starting=0,
00598         getting_nparts, got_nparts,
00599         getting_pair, got_len,got_string,
00600         done
00601     } state;
00602 
00603     state = starting;
00604     while(state != done) {
00605         is >> ws; // swallow whitespace
00606         c = is.peek();
00607         /*
00608         cerr << __LINE__ << ":" 
00609             << "state=" << state
00610             << " peek=" << (char)is.peek() 
00611             << " pos=" << is.tellg()
00612             << " len=" << len
00613             << " err=" << err
00614             <<endl;
00615         */
00616 
00617         if(is.eof()) {
00618             err ++;
00619         } else {
00620             switch(state) {
00621             case done:
00622                 break;
00623 
00624             case starting:
00625                 if(c==leftbracket) {
00626                     is >> c;
00627                     state = getting_nparts;
00628                 } else err ++;
00629                 break;
00630 
00631             case getting_nparts:
00632                 is >> ws; // swallow whitespace
00633                 if(is.bad()) { err ++; }
00634                 else state = got_nparts;
00635                 break;
00636 
00637             case got_nparts:
00638                 is >> ws; // swallow whitespace
00639                 if(is.peek() == leftbracket) {
00640                     state = getting_pair;
00641                 } else {
00642                     err ++;
00643                 }
00644                 break;
00645 
00646             case getting_pair:
00647                 is >> ws; 
00648                 is >> c;
00649                 if( c == leftbracket ) {
00650                     is >> ws; // swallow whitespace
00651                     is >> len; // extract a len
00652                     if(is.bad()) { 
00653                         err ++;
00654                     } else state = got_len;
00655                 } else if( c== rightbracket ) {
00656                     state = done;
00657                 } else {
00658                     err ++;
00659                 } 
00660                 break;
00661 
00662             case got_len:
00663                 if(c == '"') {
00664                     (void) is.get();
00665 
00666                     char *t;
00667                     // NOTE: delegates responsibility for
00668                     // delete[]-ing temp to the caller/holder of the vec
00669                     temp = new char[len];
00670                     size_t j = 0;
00671                     for(t=temp; j<len; j++, t++) {
00672                         is >> *t;
00673                     }
00674                     state = got_string;
00675                     c = is.peek();
00676                 }
00677                 if(c != '"') {
00678                     err++;
00679                 } else {
00680                     (void) is.get();
00681                 }
00682                 break;
00683 
00684             case got_string:
00685                 is >> c; // swallow 1 char
00686                 if(c != rightbracket ) {
00687                     err ++;
00688                 } else {
00689                     v.put(temp, len);
00690                     // NOTE: delegates responsibility for
00691                     // delete[]-ing temp to the caller/holder of the vec
00692                     temp = 0;
00693                     len = 0;
00694                     state = getting_pair;
00695                 }
00696                 break;
00697 
00698             }
00699             /*
00700             cerr << __LINE__ << ":" 
00701                 << "state=" << state
00702                 << " peek=" << (char)is.peek() 
00703                 << " pos=" << is.tellg()
00704                 << " len=" << len
00705                 << " err=" << err
00706                 <<endl;
00707             */
00708         }
00709         if(err >0) {
00710 #if defined(__SUNPRO_CC)
00711             // XXX kludgy version of set, but it works
00712             is.clear(is.rdstate() | ios::badbit);
00713 #elif defined(__GNUC__)
00714 #if W_GCC_THIS_VER >= W_GCC_VER(3,0)
00715             /* XXX gcc-3.2 */
00716             is.setstate(ios::badbit);
00717 #else
00718             is.set(ios::badbit);
00719 #endif
00720 #else
00721             is.set(ios::badbit);
00722 #endif
00723 
00724             state = done;
00725             err = is.tellg();
00726             //cerr << "error at byte #" << err <<endl;
00727         }
00728     }
00729     return is;
00730 }
00731 
00732 /**\endcond skip */

Generated on Thu Dec 9 08:42:26 2010 for Shore Storage Manager by  doxygen 1.4.7