From 2e2572a4f1f161e556ff3d2d7c81acd45137767a Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 27 Dec 2016 23:48:43 -0500 Subject: [PATCH] Added SDL_ReserveSpaceInDataQueue() to make space without copying data. --- src/SDL_dataqueue.c | 122 ++++++++++++++++++++++++++++++++------------ src/SDL_dataqueue.h | 15 ++++++ 2 files changed, 103 insertions(+), 34 deletions(-) diff --git a/src/SDL_dataqueue.c b/src/SDL_dataqueue.c index 4fc614293a372..db1adaad8e719 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 d7d2697e9c7a9..a5e3e1c60e237 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: */