Added SDL_ReserveSpaceInDataQueue() to make space without copying data.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 27 Dec 2016 23:48:43 -0500
changeset 107438ccdeceaae6d
parent 10742 3034ea08d805
child 10744 f42f107a6035
Added SDL_ReserveSpaceInDataQueue() to make space without copying data.
src/SDL_dataqueue.c
src/SDL_dataqueue.h
     1.1 --- a/src/SDL_dataqueue.c	Mon Jan 02 10:30:32 2017 -0800
     1.2 +++ b/src/SDL_dataqueue.c	Tue Dec 27 23:48:43 2016 -0500
     1.3 @@ -137,6 +137,40 @@
     1.4      SDL_FreeDataQueueList(packet);  /* free extra packets */
     1.5  }
     1.6  
     1.7 +static SDL_DataQueuePacket *
     1.8 +AllocateDataQueuePacket(SDL_DataQueue *queue)
     1.9 +{
    1.10 +    SDL_DataQueuePacket *packet;
    1.11 +
    1.12 +    SDL_assert(queue != NULL);
    1.13 +
    1.14 +    packet = queue->pool;
    1.15 +    if (packet != NULL) {
    1.16 +        /* we have one available in the pool. */
    1.17 +        queue->pool = packet->next;
    1.18 +    } else {
    1.19 +        /* Have to allocate a new one! */
    1.20 +        packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + queue->packet_size);
    1.21 +        if (packet == NULL) {
    1.22 +            return NULL;
    1.23 +        }
    1.24 +    }
    1.25 +
    1.26 +    packet->datalen = 0;
    1.27 +    packet->startpos = 0;
    1.28 +    packet->next = NULL;
    1.29 +                
    1.30 +    SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
    1.31 +    if (queue->tail == NULL) {
    1.32 +        queue->head = packet;
    1.33 +    } else {
    1.34 +        queue->tail->next = packet;
    1.35 +    }
    1.36 +    queue->tail = packet;
    1.37 +    return packet;
    1.38 +}
    1.39 +
    1.40 +
    1.41  int
    1.42  SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
    1.43  {
    1.44 @@ -161,42 +195,23 @@
    1.45          SDL_assert(!packet || (packet->datalen <= packet_size));
    1.46          if (!packet || (packet->datalen >= packet_size)) {
    1.47              /* tail packet missing or completely full; we need a new packet. */
    1.48 -            packet = queue->pool;
    1.49 -            if (packet != NULL) {
    1.50 -                /* we have one available in the pool. */
    1.51 -                queue->pool = packet->next;
    1.52 -            } else {
    1.53 -                /* Have to allocate a new one! */
    1.54 -                packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packet_size);
    1.55 -                if (packet == NULL) {
    1.56 -                    /* uhoh, reset so we've queued nothing new, free what we can. */
    1.57 -                    if (!origtail) {
    1.58 -                        packet = queue->head;  /* whole queue. */
    1.59 -                    } else {
    1.60 -                        packet = origtail->next;  /* what we added to existing queue. */
    1.61 -                        origtail->next = NULL;
    1.62 -                        origtail->datalen = origlen;
    1.63 -                    }
    1.64 -                    queue->head = orighead;
    1.65 -                    queue->tail = origtail;
    1.66 -                    queue->pool = NULL;
    1.67 +            packet = AllocateDataQueuePacket(queue);
    1.68 +            if (!packet) {
    1.69 +                /* uhoh, reset so we've queued nothing new, free what we can. */
    1.70 +                if (!origtail) {
    1.71 +                    packet = queue->head;  /* whole queue. */
    1.72 +                } else {
    1.73 +                    packet = origtail->next;  /* what we added to existing queue. */
    1.74 +                    origtail->next = NULL;
    1.75 +                    origtail->datalen = origlen;
    1.76 +                }
    1.77 +                queue->head = orighead;
    1.78 +                queue->tail = origtail;
    1.79 +                queue->pool = NULL;
    1.80  
    1.81 -                    SDL_FreeDataQueueList(packet);  /* give back what we can. */
    1.82 -
    1.83 -                    return SDL_OutOfMemory();
    1.84 -                }
    1.85 +                SDL_FreeDataQueueList(packet);  /* give back what we can. */
    1.86 +                return SDL_OutOfMemory();
    1.87              }
    1.88 -            packet->datalen = 0;
    1.89 -            packet->startpos = 0;
    1.90 -            packet->next = NULL;
    1.91 -                
    1.92 -            SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
    1.93 -            if (queue->tail == NULL) {
    1.94 -                queue->head = packet;
    1.95 -            } else {
    1.96 -                queue->tail->next = packet;
    1.97 -            }
    1.98 -            queue->tail = packet;
    1.99          }
   1.100  
   1.101          datalen = SDL_min(len, packet_size - packet->datalen);
   1.102 @@ -256,5 +271,44 @@
   1.103      return queue ? queue->queued_bytes : 0;
   1.104  }
   1.105  
   1.106 +void *
   1.107 +SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len)
   1.108 +{
   1.109 +    SDL_DataQueuePacket *packet;
   1.110 +
   1.111 +    if (!queue) {
   1.112 +        SDL_InvalidParamError("queue");
   1.113 +        return NULL;
   1.114 +    } else if (len == 0) {
   1.115 +        SDL_InvalidParamError("len");
   1.116 +        return NULL;
   1.117 +    } else if (len > queue->packet_size) {
   1.118 +        SDL_SetError("len is larger than packet size");
   1.119 +        return NULL;
   1.120 +    }
   1.121 +
   1.122 +    packet = queue->head;
   1.123 +    if (packet) {
   1.124 +        const size_t avail = queue->packet_size - packet->datalen;
   1.125 +        if (len <= avail) {  /* we can use the space at end of this packet. */
   1.126 +            void *retval = packet->data + packet->datalen;
   1.127 +            packet->datalen += len;
   1.128 +            queue->queued_bytes += len;
   1.129 +            return retval;
   1.130 +        }
   1.131 +    }
   1.132 +
   1.133 +    /* Need a fresh packet. */
   1.134 +    packet = AllocateDataQueuePacket(queue);
   1.135 +    if (!packet) {
   1.136 +        SDL_OutOfMemory();
   1.137 +        return NULL;
   1.138 +    }
   1.139 +
   1.140 +    packet->datalen = len;
   1.141 +    queue->queued_bytes += len;
   1.142 +    return packet->data;
   1.143 +}
   1.144 +
   1.145  /* vi: set ts=4 sw=4 expandtab: */
   1.146  
     2.1 --- a/src/SDL_dataqueue.h	Mon Jan 02 10:30:32 2017 -0800
     2.2 +++ b/src/SDL_dataqueue.h	Tue Dec 27 23:48:43 2016 -0500
     2.3 @@ -33,6 +33,21 @@
     2.4  size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
     2.5  size_t SDL_CountDataQueue(SDL_DataQueue *queue);
     2.6  
     2.7 +/* this sets a section of the data queue aside (possibly allocating memory for it)
     2.8 +   as if it's been written to, but returns a pointer to that space. You may write
     2.9 +   to this space until a read would consume it. Writes (and other calls to this
    2.10 +   function) will safely append their data after this reserved space and can
    2.11 +   be in flight at the same time. There is no thread safety.
    2.12 +   If there isn't an existing block of memory that can contain the reserved
    2.13 +   space, one will be allocated for it. You can not (currently) allocate
    2.14 +   a space larger than the packetlen requested in SDL_NewDataQueue.
    2.15 +   Returned buffer is uninitialized.
    2.16 +   This lets you avoid an extra copy in some cases, but it's safer to use
    2.17 +   SDL_WriteToDataQueue() unless you know what you're doing.
    2.18 +   Returns pointer to buffer of at least (len) bytes, NULL on error.
    2.19 +*/
    2.20 +void *SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len);
    2.21 +
    2.22  #endif /* SDL_dataqueue_h_ */
    2.23  
    2.24  /* vi: set ts=4 sw=4 expandtab: */