Boost logo

Boost :

From: Paul Vanlint (paul_at_[hidden])
Date: 2003-06-20 10:11:15


So there seems to be some interest at least from a couple of people.

To further clarify what I have, here is a piece of code using my msg buffer
class to do a few different things and also, a snippet of the public part of
my class definition.

At one point there were functions which allowed data to be directly read
from and written to a TCP socket, however that relied on another custom
class which I did not write, so I have removed it.

It also uses a custom logging mechanism which I did write, but it is
probably best if I remove that and simply write the error messages to cerr

#include <iostream>

#include "msg_buffer.h"

using namespace std;

int
main()
{
  Msg_buffer tmp;

  char* sample_str1 = "01234567890123456789012345678901234567890123456789";
  char* sample_str2 = "Test1";
  char* sample_str3 = "Test2";
  char* sample_str4 = "Test3";
  int sample_int1 = 257;
  char sample_char1 = '!';

  // Writing data directly into the buffer structure,
  // e.g. how it may be done from a socket
  // In this case, we are simulating an incoming
  // stream giving 1 byte at a time
  size_t total_len = strlen(sample_str1)+1;
  char* str_ptr = sample_str1;
  size_t chunk_size = 1;
  char* buff_ptr;
  do
    {
      size_t len = tmp.get_write_chunk(&buff_ptr, chunk_size);
      memcpy(buff_ptr, str_ptr, len);
      total_len -= len;
      str_ptr += len;
    } while (total_len > 0);

  // Add data into buffer using structured data functions
  tmp.put_msg_params("s", sample_str1);

  unsigned int reserved_id = tmp.reserve_space(sizeof(unsigned int));
  size_t written = tmp.put_msg_params("sdcss", sample_str2,
                     sample_int1, sample_char1,
                     sample_str3, sample_str4);

  // Back fill the reserved space
  tmp.fill_reserved(reserved_id, "u", written);

  // At this point, data buffer should have folloiwng data in order:
  char* str1;
  char* str1b;
  unsigned int uint1;
  char* str2;
  int int1;
  char char1;
  char* str3;
  char* str4;

  // Read data from buffer.
  // Note that for strings, we are simply getting a pointer to the
  // Buffer instead of copying out for performance reasons
  if (false == tmp.get_msg_params("ssusdcss", &str1, &str1b, &uint1,
                                  &str2, &int1, &char1, &str3, &str4))
    { cout << "Error in get_msg_params()\n"; }
  else
    {
      cout << "Retrieved:"
           << "\n str1 = \"" << str1
           << "\"\n str1b = \"" << str1b
           << "\n uint1 = " << uint1
           << "\"\n str2 = \"" << str2
           << "\"\n int1 = " << int1
           << "\n char1 = '" << char1
           << "'\n str3 = \"" << str3
           << "\"\n str4 = \"" << str4 << "\"\n";
    }
}

Will display:

Retrieved:
  str1 = "01234567890123456789012345678901234567890123456789"
  str1b = "01234567890123456789012345678901234567890123456789
  uint1 = 23"
  str2 = "Test1"
  int1 = 257
  char1 = '!'
  str3 = "Test2"
  str4 = "Test3"

class Msg_buffer
{
public:
  Msg_buffer();
  ~Msg_buffer();

  bool has_data();
  size_t get_total_data_len();
  size_t get_chunk_count();

  // This function resets pointers back to the beginning of the buffers
  // and does any housekeeping that is required.
  // After running reset_buffer(), the object may be treated as brand new.
  // It is suggested that the same buffer be reused to reduce overhead of
  // memory allocation.
  // Any previously allocated memory will be assumed to be freed at this
  // point even though we may actually keep it allocated for efficiency.
  bool reset_buffer();

// Read functions
  // Gets next char in buffer without incrementing read ptr
  bool peek(char& ch);

  // Read a formatted parameter list from the message buffer
  bool get_msg_params(char const* fmt, ...);

  // Read raw data from message buffer into buff_ptr
  bool get(unsigned int len, char const** buff_ptr);

// Write functions
  // This is used if we need to mark a point in the message that will be
  // filled in later, such as length fields which go at the front.
  // It returns a handle to the reserved space, not a pointer
  // A return handle of 0 means error
  unsigned int reserve_space(size_t len);

  // This allows us to fill a previously reserved space.
  // The reserved_id is the handle returned by reserve_space
  bool fill_reserved(unsigned int reserved_id, char const* fmt, ...);

  // This allows us to write a formatted parameter list into the message
  // buffer
  // Returns the number of bytes written, -1 means error
  ssize_t put_msg_params(char const* fmt, ...);

  ssize_t put(char ch);
  ssize_t put(char const* str_ptr);
  ssize_t put(ssize_t len, char const* data_ptr);
  ssize_t put(int value);
  ssize_t put(unsigned int value);
  ssize_t put(unsigned long value);

  // These would be used by TCP functions to access buffer chunks
  // directly. Note that successive calls to this function will return
  // successive chunks in the chain.
  // If request_len is zero, then it returns the rest of the buffer
  // For get_read_chunk, it only returns chunks and chunk pieces up to
  // the current write position
  // For get_write_chunk, if not enough buffer space is available,
  // then what is available is returned. If no space is available in an
  // existing chunk then a new chunk is allocated.
  // Returns the actual length of the buffer returned, 0 means error
  size_t get_read_chunk(char** buff_ptr, size_t request_len);
  size_t get_write_chunk(char** buff_ptr, size_t request_len);

  // This will write all data out to a file, including length, and
  // appending a CRC
  ssize_t file_write(int file_id);
  ssize_t file_write(int file_id, size_t max_len);

  // Read data in from a file
  bool file_read(int file_id, bool& done, int& msglen);

  // Jump around the buffer using bookmarks
  unsigned int get_read_bookmark();
  bool set_read_bookmark(unsigned int bookmark,
    unsigned int incremental_offset = 0);

};


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk