Skip to content

Commit

Permalink
Added SDL_ReserveSpaceInDataQueue() to make space without copying data.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Dec 28, 2016
1 parent 18d9b23 commit 2e2572a
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 34 deletions.
122 changes: 88 additions & 34 deletions src/SDL_dataqueue.c
Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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: */

15 changes: 15 additions & 0 deletions src/SDL_dataqueue.h
Expand Up @@ -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: */
Expand Down

0 comments on commit 2e2572a

Please sign in to comment.