]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: buffer - Add buffer_replace().
authorStephan Bosch <stephan.bosch@dovecot.fi>
Thu, 14 Mar 2019 22:55:00 +0000 (23:55 +0100)
committerMartti Rannanjärvi <martti.rannanjarvi@open-xchange.com>
Tue, 11 Jun 2019 10:48:50 +0000 (13:48 +0300)
src/lib/buffer.c
src/lib/buffer.h
src/lib/test-buffer.c

index dc04f91025bec430fbabcde16d40fdbefe3d8f52..0e0f621253a7ab43b7795532c2d0510175caedd5 100644 (file)
@@ -234,6 +234,40 @@ void buffer_delete(buffer_t *_buf, size_t pos, size_t size)
        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;
index 601d1b43bea308dc2caf31a0c4d8977336ecf86d..4c15599020d3ecfb8980b0086be804fa06e56fcd 100644 (file)
@@ -59,6 +59,11 @@ void buffer_insert(buffer_t *buf, size_t pos,
    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);
index 4fc72ea0f5ae211985fa9e472fd1d8a6ebe07ae2..7fadcc26ece9b1646fe94bede232412da2ca8987 100644 (file)
@@ -10,7 +10,7 @@ static void test_buffer_random(void)
        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 @@ static void test_buffer_random(void)
                        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 @@ static void test_buffer_random(void)
                        }
                        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 @@ static void test_buffer_random(void)
                        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 @@ static void test_buffer_truncate_bits(void)
        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();
 }