buffer_set_used_size(_buf, pos + end_size);
}
+void buffer_replace(buffer_t *_buf, size_t pos, size_t size,
+ const void *data, size_t data_size)
+{
+ struct real_buffer *buf = (struct real_buffer *)_buf;
+ size_t end_size;
+
+ if (pos >= buf->used) {
+ buffer_write(_buf, pos, data, data_size);
+ return;
+ }
+ end_size = buf->used - pos;
+
+ if (size < end_size) {
+ end_size -= size;
+ if (data_size == 0) {
+ /* delete from between */
+ memmove(buf->w_buffer + pos,
+ buf->w_buffer + pos + size, end_size);
+ } else {
+ /* insert */
+ buffer_copy(_buf, pos + data_size, _buf, pos + size,
+ (size_t)-1);
+ memcpy(buf->w_buffer + pos, data, data_size);
+ }
+ } else {
+ /* overwrite the end */
+ end_size = 0;
+ buffer_write(_buf, pos, data, data_size);
+ }
+
+ buffer_set_used_size(_buf, pos + data_size + end_size);
+}
+
+
void buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size)
{
struct real_buffer *buf = (struct real_buffer *)_buf;
deleted block may cross the current buffer size boundary, which is ignored.
*/
void buffer_delete(buffer_t *buf, size_t pos, size_t size);
+/* Replace the data in the buffer with the indicated size at position pos with
+ the provided data. This is a more optimized version of
+ buffer_delete(buf, pos, size); buffer_insert(buf, pos, data, data_size); */
+void buffer_replace(buffer_t *buf, size_t pos, size_t size,
+ const void *data, size_t data_size);
/* Fill buffer with zero bytes. */
void buffer_write_zero(buffer_t *buf, size_t pos, size_t data_size);
buffer_t *buf;
unsigned char *p, testdata[BUF_TEST_SIZE], shadowbuf[BUF_TEST_SIZE];
unsigned int i, shadowbuf_size;
- size_t pos, pos2, size;
+ size_t pos, pos2, size, size2;
int test = -1;
bool zero;
i_assert(buf->used < BUF_TEST_SIZE);
}
- test = i_rand_limit(6);
+ test = i_rand_limit(7);
zero = i_rand_limit(10) == 0;
switch (test) {
case 0:
}
break;
case 4:
+ pos = i_rand_limit(BUF_TEST_SIZE - 1);
+ size = i_rand_limit(BUF_TEST_SIZE - pos);
+ size2 = i_rand_limit(BUF_TEST_SIZE -
+ I_MAX(buf->used, pos));
+ buffer_replace(buf, pos, size, testdata, size2);
+ if (pos < shadowbuf_size) {
+ if (pos + size > shadowbuf_size)
+ size = shadowbuf_size - pos;
+ memmove(shadowbuf + pos,
+ shadowbuf + pos + size,
+ BUF_TEST_SIZE - (pos + size));
+
+ shadowbuf_size -= size;
+ memset(shadowbuf + shadowbuf_size, 0,
+ BUF_TEST_SIZE - shadowbuf_size);
+ }
+ memmove(shadowbuf + pos + size2,
+ shadowbuf + pos,
+ BUF_TEST_SIZE - (pos + size2));
+ memcpy(shadowbuf + pos, testdata, size2);
+ if (pos < shadowbuf_size)
+ shadowbuf_size += size2;
+ else
+ shadowbuf_size = pos + size2;
+ break;
+ case 5:
if (shadowbuf_size <= 1)
break;
pos = i_rand_limit(shadowbuf_size - 1); /* dest */
if (pos > pos2 && pos + size > shadowbuf_size)
shadowbuf_size = pos + size;
break;
- case 5:
+ case 6:
pos = i_rand_limit(BUF_TEST_SIZE - 1);
size = i_rand_limit(BUF_TEST_SIZE - pos);
p = buffer_get_space_unsafe(buf, pos, size);
test_end();
}
+static void test_buffer_replace(void)
+{
+ const char orig_input[] = "123456789";
+ const char data[] = "abcdefghij";
+ buffer_t *buf, *buf2;
+ unsigned int init_size, pos, size, data_size;
+
+ test_begin("buffer_replace()");
+ for (init_size = 0; init_size <= sizeof(orig_input)-1; init_size++) {
+ for (pos = 0; pos < sizeof(orig_input)+1; pos++) {
+ for (size = 0; size < sizeof(orig_input)+1; size++) {
+ for (data_size = 0; data_size <= sizeof(data)-1; data_size++) T_BEGIN {
+ buf = buffer_create_dynamic(pool_datastack_create(), 4);
+ buf2 = buffer_create_dynamic(pool_datastack_create(), 4);
+ buffer_append(buf, orig_input, init_size);
+ buffer_append(buf2, orig_input, init_size);
+
+ buffer_replace(buf, pos, size, data, data_size);
+ buffer_delete(buf2, pos, size);
+ buffer_insert(buf2, pos, data, data_size);
+ test_assert(buf->used == buf2->used &&
+ memcmp(buf->data, buf2->data, buf->used) == 0);
+ } T_END;
+ }
+ }
+ }
+
+ test_end();
+}
+
void test_buffer(void)
{
test_buffer_random();
test_buffer_write();
test_buffer_set_used_size();
test_buffer_truncate_bits();
+ test_buffer_replace();
}