changeset 23008:d7ad84cec527

lib: buffer - Add buffer_replace().
author Stephan Bosch <stephan.bosch@dovecot.fi>
date Thu, 14 Mar 2019 23:55:00 +0100
parents 36e01285b5b8
children 7f2568b494ac
files src/lib/buffer.c src/lib/buffer.h src/lib/test-buffer.c
diffstat 3 files changed, 98 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/buffer.c	Mon Mar 18 00:52:37 2019 +0100
+++ b/src/lib/buffer.c	Thu Mar 14 23:55:00 2019 +0100
@@ -234,6 +234,40 @@
 	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;
--- a/src/lib/buffer.h	Mon Mar 18 00:52:37 2019 +0100
+++ b/src/lib/buffer.h	Thu Mar 14 23:55:00 2019 +0100
@@ -59,6 +59,11 @@
    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);
--- a/src/lib/test-buffer.c	Mon Mar 18 00:52:37 2019 +0100
+++ b/src/lib/test-buffer.c	Thu Mar 14 23:55:00 2019 +0100
@@ -10,7 +10,7 @@
 	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;
 
@@ -29,7 +29,7 @@
 			i_assert(buf->used < BUF_TEST_SIZE);
 		}
 
-		test = rand() % 6;
+		test = rand() % 7;
 		zero = rand() % 10 == 0;
 		switch (test) {
 		case 0:
@@ -95,6 +95,31 @@
 			}
 			break;
 		case 4:
+			pos = rand() % (BUF_TEST_SIZE - 1);
+			size = rand() % (BUF_TEST_SIZE - pos);
+			size2 = rand() % (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 = rand() % (shadowbuf_size-1); /* dest */
@@ -106,7 +131,7 @@
 			if (pos > pos2 && pos + size > shadowbuf_size)
 				shadowbuf_size = pos + size;
 			break;
-		case 5:
+		case 6:
 			pos = rand() % (BUF_TEST_SIZE-1);
 			size = rand() % (BUF_TEST_SIZE - pos);
 			p = buffer_get_space_unsafe(buf, pos, size);
@@ -271,10 +296,41 @@
 	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();
 }