summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpipe/pq.h71
1 files changed, 49 insertions, 22 deletions
diff --git a/libpipe/pq.h b/libpipe/pq.h
index 963c9e90..abd193f8 100644
--- a/libpipe/pq.h
+++ b/libpipe/pq.h
@@ -23,6 +23,7 @@
#include <errno.h>
#include <stddef.h> /* for size_t */
+#include <string.h>
#include <mach/mach.h>
struct packet
@@ -119,22 +120,51 @@ int packet_extend (struct packet *packet, size_t new_len);
returned. */
error_t packet_realloc (struct packet *packet, size_t new_len);
+/* Try to make space in PACKET for AMOUNT more bytes without growing the
+ buffer, returning true if we could do it. */
+extern inline int
+packet_fit (struct packet *packet, size_t amount)
+{
+ char *buf = packet->buf, *end = packet->buf_end;
+ size_t buf_len = packet->buf_len;
+ size_t left = buf + buf_len - end; /* Free space at the end of the buffer. */
+
+ if (amount > left)
+ {
+ char *start = packet->buf_start;
+ size_t cur_len = end - start; /* Amount of data currently in the buf. */
+
+ if (buf_len - cur_len >= amount
+ && cur_len < PACKET_SIZE_LARGE && cur_len < (buf_len >> 2))
+ /* If we could fit the data in by moving what's already in the
+ buffer, and there's not too much there, and it represents less
+ than 25% of the buffer size, then move the data instead of growing
+ the buffer. */
+ {
+ bcopy (start, buf, cur_len);
+ packet->buf_start = buf;
+ packet->buf_end = buf + cur_len;
+ }
+ else
+ return 0; /* We failed... */
+ }
+
+ return 1;
+}
+
/* Make sure that PACKET has room for at least AMOUNT more bytes, or return
the reason why not. */
extern inline error_t
packet_ensure (struct packet *packet, size_t amount)
{
- size_t new_len;
- size_t left = packet->buf + packet->buf_len - packet->buf_end;
-
- if (amount < left)
- return 0;
-
- new_len = packet_new_size (packet, amount);
- if (packet_extend (packet, new_len))
- return 0;
- else
- return packet_realloc (packet, new_len);
+ if (! packet_fit (packet, amount))
+ /* We must make the buffer bigger. */
+ {
+ size_t new_len = packet_new_size (packet, amount);
+ if (! packet_extend (packet, new_len))
+ return packet_realloc (packet, new_len);
+ }
+ return 0;
}
/* Make sure that PACKET has room for at least AMOUNT more bytes, *only* if
@@ -144,17 +174,14 @@ packet_ensure (struct packet *packet, size_t amount)
extern inline int
packet_ensure_efficiently (struct packet *packet, size_t amount)
{
- size_t new_len;
- size_t left = packet->buf + packet->buf_len - packet->buf_end;
-
- if (amount < left)
- return 1;
-
- new_len = packet_new_size (packet, amount);
- if (packet_extend (packet, new_len))
- return 1;
- if ((packet->buf_end - packet->buf_start) < PACKET_SIZE_LARGE)
- return packet_realloc (packet, new_len) == 0;
+ if (! packet_fit (packet, amount))
+ {
+ size_t new_len = packet_new_size (packet, amount);
+ if (packet_extend (packet, new_len))
+ return 1;
+ if ((packet->buf_end - packet->buf_start) < PACKET_SIZE_LARGE)
+ return packet_realloc (packet, new_len) == 0;
+ }
return 0;
}