tags:

views:

385

answers:

4

Given (in C++)

char * byte_sequence;
size_t byte_sequence_length;
char * buffer;
size_t N;

Assuming byte_sequence and byte_sequence_length are initialized to some arbitrary length sequence of bytes (and its length), and buffer is initialized to point to N * byte_sequence_length bytes, what would be the easiest way to replicate the byte_sequence into buffer N times? Is there anything in STL/BOOST that already does something like this?

For example, if the sequence were "abcd", and N was 3, then buffer would end up containing "abcdabcdabcd".

+6  A: 

Repeating the buffer while avoiding pointer arithmetic:

You can use std::vector < char > or std::string to make things easier for you. Both of these containers can hold binary data too.

This solution has the nice properties that:

  • You don't need to worry about memory access violations
  • You don't need to worry about getting the size of your buffer correct
  • You can append sequences at any time to your buffer without manual re-allocations

.

//Note this works even for binary data.
void appendSequenceToMyBuffer(std::string &sBuffer
       , const char *byte_sequence
       , int byte_sequence_length
       , int N)
{
  for(int i = 0; i < N; ++i)
      sBuffer.append(byte_sequence, byte_sequence_length);
}

//Note: buffer == sBuffer.c_str()


Alternate: For binary data using memcpy:

buffer = new char[byte_sequence_length*N];
for (int i=0; i < N; ++i)
  memcpy(buffer+i*byte_sequence_length, byte_sequence, byte_sequence_length); 
//...
delete[] buffer;


Alternate: For null terminated string data using strcpy:

buffer = new char[byte_sequence_length*N+1];
int byte_sequence_length = strlen(byte_sequence);
for (int i=0; i < N; ++i)
  strcpy(buffer+i*byte_sequence_length, byte_sequence, byte_sequence_length); 
//...
delete[] buffer;


Alternate: If you are filling the buffer with a single value:

buffer = new char[N];
memset(buffer, byte_value, N);
//...
delete[] buffer;
Brian R. Bondy
One comment on the first solution - if you call sBuffer.reserve(byte_sequence_length*N) before running the appends you can prevent multiple re-allocations.
Eclipse
+11  A: 

I would probably just go with this:

for (int i=0; i < N; ++i)
    memcpy(buffer + i * byte_sequence_length, byte_sequence, byte_sequence_length);

This assumes you are dealing with binary data and are keeping track of the length, not using '\0' termination.

If you want these to be c-strings you'll have to allocate an extra byte and add in the '\0' a the end. Given a c-string and an integer, you'd want to do it like this:

char *RepeatN(char *source, size_t n)
{
    assert(n >= 0 && source != NULL);            
    size_t length = strlen(source) - 1;
    char *buffer = new char[length*n + 1];
    for (int i=0; i < n; ++i)
        memcpy(buffer + i * length, source, length);
    buffer[n * length] = '\0';
}
Eclipse
+4  A: 

You can use the STL algorithm Generate:

MSDN: Generate

mwigdahl
+2  A: 

If N is known to be a power of 2, you can copy from the first part of your buffer to subsequent parts, increasing the amount copied each time:

assert((N > 0) && ((N & (N-1)) == 0));
memcpy(buffer, byte_sequence, byte_sequence_length);
for (size_t i = 1;  i < N;  i *= 2)
    memcpy(buffer + i * byte_sequence_length, buffer, i * byte_sequence_length);

Edit: It is trivial to extend this to work when N is not a power of 2. Here's an improved version, which removes all constraints on N and also replaces the odd for statement with a while.

if (N > 0)
    memcpy(buffer, byte_sequence, byte_sequence_length);
size_t copied = 1;
while (copied < N)
{
    size_t tocopy = min(copied, N - copied);
    memcpy(buffer + copied * byte_sequence_length, buffer, tocopy * byte_sequence_length);
    copied += tocopy;
}
Mark Ransom