00001 
00002 
00003 #ifndef _BCP_BUFFER_H
00004 #define _BCP_BUFFER_H
00005 
00006 #include <memory>
00007 #include <vector>
00008 
00009 
00010 
00011 #include "BCP_error.hpp"
00012 #include "BCP_string.hpp"
00013 #include "BCP_message_tag.hpp"
00014 #include "BCP_message.hpp"
00015 #include "BCP_vector.hpp"
00016 
00039 class BCP_buffer{
00040 public:
00041    
00042 
00043 
00044 
00045 
00046 
00047 
00069    BCP_message_tag _msgtag;
00072    BCP_proc_id*    _sender;
00074    size_t _pos;
00076    size_t _max_size;
00079    size_t _size;
00081    char*  _data;
00084 public:
00085    
00089    inline BCP_message_tag msgtag() const { return _msgtag; }
00092    inline const BCP_proc_id* sender() const { return _sender; }
00094    inline int                size() const { return _size; }
00096    inline const char*        data() const { return _data; }
00098    
00099 
00104    inline void set_position(const int pos) throw(BCP_fatal_error) {
00105      if (pos < 0 || pos >= size())
00106        throw BCP_fatal_error("Incorrest buffer position setting.\n");
00107      _pos = pos;
00108    }
00110    inline void set_msgtag(const BCP_message_tag tag) { _msgtag = tag; }
00111 
00113   void set_content(const char* data, const size_t size,
00114                    BCP_proc_id* sender, BCP_message_tag msgtag) {
00115     _sender = sender;
00116     _msgtag = msgtag;
00117     if (_max_size < size) {
00118       delete[] _data;
00119       _data = new char[size];
00120       _max_size = size;
00121     }
00122     _pos = 0;
00123     _size = size;
00124     if (_size)
00125       memcpy(_data, data, size * sizeof(char));
00126    }
00127      
00128     
00130    BCP_buffer& operator=(const BCP_buffer& buf) {
00131       _msgtag = buf._msgtag;
00132       _sender = buf._sender ? buf._sender->clone() : 0;
00133       _pos = buf._pos;
00134       if (_max_size < buf._max_size) {
00135          delete[] _data;
00136          _data = new char[buf._max_size];
00137          _max_size = buf._max_size;
00138       }
00139       _size = buf._size;
00140       if (_size)
00141          memcpy(_data, buf._data, _size * sizeof(char));
00142       return *this;
00143    }
00147    inline void make_fit(const int add_size){
00148       if (_max_size < _size + add_size){
00149          _max_size = 2 * (_size + add_size + 0x1000);
00150          char *new_data = new char[_max_size];
00151          if (_size)
00152             memcpy(new_data, _data, _size);
00153          delete[] _data;
00154          _data = new_data;
00155       }
00156    }
00159    inline void clear(){
00160       _msgtag = BCP_Msg_NoMessage;
00161       _size = 0;
00162       _pos = 0;
00163       delete _sender; _sender = 0;
00164    }
00165 
00168    template <class T> BCP_buffer& pack(const T& value) {
00169      make_fit( sizeof(T) );
00170      memcpy(_data + _size, &value, sizeof(T));
00171      _size += sizeof(T);
00172      return *this;
00173    }
00174 
00177    template <class T> BCP_buffer& unpack(T& value){
00178 #ifdef PARANOID
00179      if (_pos + sizeof(T) > _size)
00180        throw BCP_fatal_error("Reading over the end of buffer.\n");
00181 #endif
00182      memcpy(&value, _data + _pos, sizeof(T));
00183      _pos += sizeof(T);
00184      return *this;
00185    }
00186 
00188    template <class T> BCP_buffer& pack(const T* const values,
00189                                        const int length){
00190      make_fit( sizeof(int) + sizeof(T) * length );
00191      memcpy(_data + _size, &length, sizeof(int));
00192      _size += sizeof(int);
00193      if (length > 0){
00194        memcpy(_data + _size, values, sizeof(T) * length);
00195        _size += sizeof(T) * length;
00196      }
00197      return *this;
00198    }
00199 
00213    template <class T> BCP_buffer& unpack(T*& values, int& length,
00214                                          bool allocate = true)
00215      throw(BCP_fatal_error) {
00216      if (allocate) {
00217 #ifdef PARANOID
00218        if (_pos + sizeof(int) > _size)
00219          throw BCP_fatal_error("Reading over the end of buffer.\n");
00220 #endif
00221        memcpy(&length, _data + _pos, sizeof(int));
00222        _pos += sizeof(int);
00223        if (length > 0){
00224 #ifdef PARANOID
00225          if (_pos + sizeof(T)*length > _size)
00226            throw BCP_fatal_error("Reading over the end of buffer.\n");
00227 #endif
00228          values = new T[length];
00229          memcpy(values, _data + _pos, sizeof(T)*length);
00230          _pos += sizeof(T) * length;
00231        }
00232        
00233      } else { 
00234 
00235        int l;
00236 #ifdef PARANOID
00237        if (_pos + sizeof(int) > _size)
00238          throw BCP_fatal_error("Reading over the end of buffer.\n");
00239 #endif
00240        memcpy(&l, _data + _pos, sizeof(int));
00241        _pos += sizeof(int);
00242        if (l != length)
00243          throw BCP_fatal_error("BCP_buffer::unpack() : bad array lentgh.\n");
00244        if (length > 0){
00245 #ifdef PARANOID
00246          if (_pos + sizeof(T)*length > _size)
00247            throw BCP_fatal_error("Reading over the end of buffer.\n");
00248 #endif
00249          memcpy(values, _data + _pos, sizeof(T)*length);
00250          _pos += sizeof(T) * length;
00251        }
00252        
00253      }
00254      
00255      return *this;
00256    }
00257 
00259    BCP_buffer& pack(const BCP_string& value){
00260       
00261       int len = value.length();
00262       make_fit( sizeof(int) + len );
00263       memcpy(_data + _size, &len, sizeof(int));
00264       _size += sizeof(int);
00265       if (len > 0){
00266          memcpy(_data + _size, value.c_str(), len);
00267          _size += len;
00268       }
00269       return *this;
00270    }
00272    BCP_buffer& pack(BCP_string& value){
00273       
00274       int len = value.length();
00275       make_fit( sizeof(int) + len );
00276       memcpy(_data + _size, &len, sizeof(int));
00277       _size += sizeof(int);
00278       if (len > 0){
00279          memcpy(_data + _size, value.c_str(), len);
00280          _size += len;
00281       }
00282       return *this;
00283    }
00285    BCP_buffer& unpack(BCP_string& value){
00286       int len;
00287       unpack(len);
00288       value.assign(_data + _pos, len);
00289       _pos += len;
00290       return *this;
00291    }
00292 
00293    
00295    template <class T> BCP_buffer& pack(const BCP_vec<T>& vec) {
00296      int objnum = vec.size();
00297      int new_bytes = objnum * sizeof(T);
00298      make_fit( sizeof(int) + new_bytes );
00299      memcpy(_data + _size, &objnum, sizeof(int));
00300      _size += sizeof(int);
00301      if (objnum > 0){
00302        memcpy(_data + _size, vec.begin(), new_bytes);
00303        _size += new_bytes;
00304      }
00305      return *this;
00306    }
00307 
00309    template <class T> BCP_buffer& pack(const std::vector<T>& vec) {
00310      int objnum = vec.size();
00311      int new_bytes = objnum * sizeof(T);
00312      make_fit( sizeof(int) + new_bytes );
00313      memcpy(_data + _size, &objnum, sizeof(int));
00314      _size += sizeof(int);
00315      if (objnum > 0){
00316        memcpy(_data + _size, &vec[0], new_bytes);
00317        _size += new_bytes;
00318      }
00319      return *this;
00320    }
00321 
00323    template <class T> BCP_buffer& unpack(BCP_vec<T>& vec) {
00324      int objnum;
00325 #ifdef PARANOID
00326      if (_pos + sizeof(int) > _size)
00327        throw BCP_fatal_error("Reading over the end of buffer.\n");
00328 #endif
00329      memcpy(&objnum, _data + _pos, sizeof(int));
00330      _pos += sizeof(int);
00331      vec.clear();
00332      if (objnum > 0){
00333 #ifdef PARANOID
00334        if (_pos + sizeof(T)*objnum > _size)
00335          throw BCP_fatal_error("Reading over the end of buffer.\n");
00336 #endif
00337        vec.reserve(objnum);
00338        vec.insert(vec.end(), _data + _pos, objnum);
00339        _pos += objnum * sizeof(T);
00340      }
00341      return *this;
00342    }
00343 
00345    template <class T> BCP_buffer& unpack(std::vector<T>& vec) {
00346      int objnum;
00347 #ifdef PARANOID
00348      if (_pos + sizeof(int) > _size)
00349        throw BCP_fatal_error("Reading over the end of buffer.\n");
00350 #endif
00351      memcpy(&objnum, _data + _pos, sizeof(int));
00352      _pos += sizeof(int);
00353      vec.clear();
00354      if (objnum > 0){
00355 #ifdef PARANOID
00356        if (_pos + sizeof(T)*objnum > _size)
00357          throw BCP_fatal_error("Reading over the end of buffer.\n");
00358 #endif
00359        vec.insert(vec.end(), objnum, T());
00360        memcpy(&vec[0], _data + _pos, objnum * sizeof(T));
00361        _pos += objnum * sizeof(T);
00362      }
00363      return *this;
00364    }
00365 
00372    BCP_buffer() : _msgtag(BCP_Msg_NoMessage), _sender(0), _pos(0),
00373       _max_size(0x4000), _size(0), _data(new char[_max_size]) {}
00375    BCP_buffer(const BCP_buffer& buf) :
00376       _msgtag(BCP_Msg_NoMessage), _sender(0), _pos(0),
00377       _max_size(0), _size(0), _data(0){
00378          operator=(buf);
00379    }
00382    ~BCP_buffer() {
00383       delete _sender;   _sender = 0;
00384       delete[] _data;
00385    }
00387 };
00388 
00389 #endif