summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan C. Gordon <icculus@icculus.org>2016-12-27 23:48:43 -0500
committerRyan C. Gordon <icculus@icculus.org>2016-12-27 23:48:43 -0500
commit6be6d96f6b9a75864402f91ef32c9652ff7e04be (patch)
treee6b8720acac3d79769d70313f758980ea1e978d4
parent9658c96d58b3260360df4de1da5e582d59ded2ec (diff)
downloadsdl-6be6d96f6b9a75864402f91ef32c9652ff7e04be.tar.gz
Added SDL_ReserveSpaceInDataQueue() to make space without copying data.
-rw-r--r--src/SDL_dataqueue.c122
-rw-r--r--src/SDL_dataqueue.h15
2 files changed, 103 insertions, 34 deletions
diff --git a/src/SDL_dataqueue.c b/src/SDL_dataqueue.c
index 4fc614293..db1adaad8 100644
--- a/src/SDL_dataqueue.c
+++ b/src/SDL_dataqueue.c
@@ -137,6 +137,40 @@ SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
SDL_FreeDataQueueList(packet); /* free extra packets */
}
+static SDL_DataQueuePacket *
+AllocateDataQueuePacket(SDL_DataQueue *queue)
+{
+ SDL_DataQueuePacket *packet;
+
+ SDL_assert(queue != NULL);
+
+ packet = queue->pool;
+ if (packet != NULL) {
+ /* we have one available in the pool. */
+ queue->pool = packet->next;
+ } else {
+ /* Have to allocate a new one! */
+ packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + queue->packet_size);
+ if (packet == NULL) {
+ return NULL;
+ }
+ }
+
+ packet->datalen = 0;
+ packet->startpos = 0;
+ packet->next = NULL;
+
+ SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
+ if (queue->tail == NULL) {
+ queue->head = packet;
+ } else {
+ queue->tail->next = packet;
+ }
+ queue->tail = packet;
+ return packet;
+}
+
+
int
SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
{
@@ -161,42 +195,23 @@ SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
SDL_assert(!packet || (packet->datalen <= packet_size));
if (!packet || (packet->datalen >= packet_size)) {
/* tail packet missing or completely full; we need a new packet. */
- packet = queue->pool;
- if (packet != NULL) {
- /* we have one available in the pool. */
- queue->pool = packet->next;
- } else {
- /* Have to allocate a new one! */
- packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packet_size);
- if (packet == NULL) {
- /* uhoh, reset so we've queued nothing new, free what we can. */
- if (!origtail) {
- packet = queue->head; /* whole queue. */
- } else {
- packet = origtail->next; /* what we added to existing queue. */
- origtail->next = NULL;
- origtail->datalen = origlen;
- }
- queue->head = orighead;
- queue->tail = origtail;
- queue->pool = NULL;
-
- SDL_FreeDataQueueList(packet); /* give back what we can. */
-
- return SDL_OutOfMemory();
+ packet = AllocateDataQueuePacket(queue);
+ if (!packet) {
+ /* uhoh, reset so we've queued nothing new, free what we can. */
+ if (!origtail) {
+ packet = queue->head; /* whole queue. */
+ } else {
+ packet = origtail->next; /* what we added to existing queue. */
+ origtail->next = NULL;
+ origtail->datalen = origlen;
}
+ queue->head = orighead;
+ queue->tail = origtail;
+ queue->pool = NULL;
+
+ SDL_FreeDataQueueList(packet); /* give back what we can. */
+ return SDL_OutOfMemory();
}
- packet->datalen = 0;
- packet->startpos = 0;
- packet->next = NULL;
-
- SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
- if (queue->tail == NULL) {
- queue->head = packet;
- } else {
- queue->tail->next = packet;
- }
- queue->tail = packet;
}
datalen = SDL_min(len, packet_size - packet->datalen);
@@ -256,5 +271,44 @@ SDL_CountDataQueue(SDL_DataQueue *queue)
return queue ? queue->queued_bytes : 0;
}
+void *
+SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len)
+{
+ SDL_DataQueuePacket *packet;
+
+ if (!queue) {
+ SDL_InvalidParamError("queue");
+ return NULL;
+ } else if (len == 0) {
+ SDL_InvalidParamError("len");
+ return NULL;
+ } else if (len > queue->packet_size) {
+ SDL_SetError("len is larger than packet size");
+ return NULL;
+ }
+
+ packet = queue->head;
+ if (packet) {
+ const size_t avail = queue->packet_size - packet->datalen;
+ if (len <= avail) { /* we can use the space at end of this packet. */
+ void *retval = packet->data + packet->datalen;
+ packet->datalen += len;
+ queue->queued_bytes += len;
+ return retval;
+ }
+ }
+
+ /* Need a fresh packet. */
+ packet = AllocateDataQueuePacket(queue);
+ if (!packet) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ packet->datalen = len;
+ queue->queued_bytes += len;
+ return packet->data;
+}
+
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/SDL_dataqueue.h b/src/SDL_dataqueue.h
index d7d2697e9..a5e3e1c60 100644
--- a/src/SDL_dataqueue.h
+++ b/src/SDL_dataqueue.h
@@ -33,6 +33,21 @@ int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *data, const size_t le
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
size_t SDL_CountDataQueue(SDL_DataQueue *queue);
+/* this sets a section of the data queue aside (possibly allocating memory for it)
+ as if it's been written to, but returns a pointer to that space. You may write
+ to this space until a read would consume it. Writes (and other calls to this
+ function) will safely append their data after this reserved space and can
+ be in flight at the same time. There is no thread safety.
+ If there isn't an existing block of memory that can contain the reserved
+ space, one will be allocated for it. You can not (currently) allocate
+ a space larger than the packetlen requested in SDL_NewDataQueue.
+ Returned buffer is uninitialized.
+ This lets you avoid an extra copy in some cases, but it's safer to use
+ SDL_WriteToDataQueue() unless you know what you're doing.
+ Returns pointer to buffer of at least (len) bytes, NULL on error.
+*/
+void *SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len);
+
#endif /* SDL_dataqueue_h_ */
/* vi: set ts=4 sw=4 expandtab: */