1
0
Эх сурвалжийг харах

Added SDL_ReserveSpaceInDataQueue() to make space without copying data.

Ryan C. Gordon 8 жил өмнө
parent
commit
2e2572a4f1
2 өөрчлөгдсөн 103 нэмэгдсэн , 34 устгасан
  1. 88 34
      src/SDL_dataqueue.c
  2. 15 0
      src/SDL_dataqueue.h

+ 88 - 34
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: */
 

+ 15 - 0
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: */