diff options
author | chai <chaifix@163.com> | 2019-05-11 22:54:56 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-05-11 22:54:56 +0800 |
commit | 9645be0af1b1d5cb0ad5892d5464e1b23c51b550 (patch) | |
tree | 129c716bed8e93312421c3adb2f8e7c4f811602d /source/3rd-party/SDL2/src/SDL_dataqueue.c |
Diffstat (limited to 'source/3rd-party/SDL2/src/SDL_dataqueue.c')
-rw-r--r-- | source/3rd-party/SDL2/src/SDL_dataqueue.c | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/SDL_dataqueue.c b/source/3rd-party/SDL2/src/SDL_dataqueue.c new file mode 100644 index 0000000..97916f4 --- /dev/null +++ b/source/3rd-party/SDL2/src/SDL_dataqueue.c @@ -0,0 +1,339 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "./SDL_internal.h" +#include "SDL.h" +#include "./SDL_dataqueue.h" +#include "SDL_assert.h" + +typedef struct SDL_DataQueuePacket +{ + size_t datalen; /* bytes currently in use in this packet. */ + size_t startpos; /* bytes currently consumed in this packet. */ + struct SDL_DataQueuePacket *next; /* next item in linked list. */ + Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]; /* packet data */ +} SDL_DataQueuePacket; + +struct SDL_DataQueue +{ + SDL_DataQueuePacket *head; /* device fed from here. */ + SDL_DataQueuePacket *tail; /* queue fills to here. */ + SDL_DataQueuePacket *pool; /* these are unused packets. */ + size_t packet_size; /* size of new packets */ + size_t queued_bytes; /* number of bytes of data in the queue. */ +}; + +static void +SDL_FreeDataQueueList(SDL_DataQueuePacket *packet) +{ + while (packet) { + SDL_DataQueuePacket *next = packet->next; + SDL_free(packet); + packet = next; + } +} + + +/* this all expects that you managed thread safety elsewhere. */ + +SDL_DataQueue * +SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack) +{ + SDL_DataQueue *queue = (SDL_DataQueue *) SDL_malloc(sizeof (SDL_DataQueue)); + + if (!queue) { + SDL_OutOfMemory(); + return NULL; + } else { + const size_t packetlen = _packetlen ? _packetlen : 1024; + const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen; + size_t i; + + SDL_zerop(queue); + queue->packet_size = packetlen; + + for (i = 0; i < wantpackets; i++) { + SDL_DataQueuePacket *packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packetlen); + if (packet) { /* don't care if this fails, we'll deal later. */ + packet->datalen = 0; + packet->startpos = 0; + packet->next = queue->pool; + queue->pool = packet; + } + } + } + + return queue; +} + +void +SDL_FreeDataQueue(SDL_DataQueue *queue) +{ + if (queue) { + SDL_FreeDataQueueList(queue->head); + SDL_FreeDataQueueList(queue->pool); + SDL_free(queue); + } +} + +void +SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack) +{ + const size_t packet_size = queue ? queue->packet_size : 1; + const size_t slackpackets = (slack + (packet_size-1)) / packet_size; + SDL_DataQueuePacket *packet; + SDL_DataQueuePacket *prev = NULL; + size_t i; + + if (!queue) { + return; + } + + packet = queue->head; + + /* merge the available pool and the current queue into one list. */ + if (packet) { + queue->tail->next = queue->pool; + } else { + packet = queue->pool; + } + + /* Remove the queued packets from the device. */ + queue->tail = NULL; + queue->head = NULL; + queue->queued_bytes = 0; + queue->pool = packet; + + /* Optionally keep some slack in the pool to reduce malloc pressure. */ + for (i = 0; packet && (i < slackpackets); i++) { + prev = packet; + packet = packet->next; + } + + if (prev) { + prev->next = NULL; + } else { + queue->pool = NULL; + } + + 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) +{ + size_t len = _len; + const Uint8 *data = (const Uint8 *) _data; + const size_t packet_size = queue ? queue->packet_size : 0; + SDL_DataQueuePacket *orighead; + SDL_DataQueuePacket *origtail; + size_t origlen; + size_t datalen; + + if (!queue) { + return SDL_InvalidParamError("queue"); + } + + orighead = queue->head; + origtail = queue->tail; + origlen = origtail ? origtail->datalen : 0; + + while (len > 0) { + SDL_DataQueuePacket *packet = queue->tail; + 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 = 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(); + } + } + + datalen = SDL_min(len, packet_size - packet->datalen); + SDL_memcpy(packet->data + packet->datalen, data, datalen); + data += datalen; + len -= datalen; + packet->datalen += datalen; + queue->queued_bytes += datalen; + } + + return 0; +} + +size_t +SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len) +{ + size_t len = _len; + Uint8 *buf = (Uint8 *) _buf; + Uint8 *ptr = buf; + SDL_DataQueuePacket *packet; + + if (!queue) { + return 0; + } + + for (packet = queue->head; len && packet; packet = packet->next) { + const size_t avail = packet->datalen - packet->startpos; + const size_t cpy = SDL_min(len, avail); + SDL_assert(queue->queued_bytes >= avail); + + SDL_memcpy(ptr, packet->data + packet->startpos, cpy); + ptr += cpy; + len -= cpy; + } + + return (size_t) (ptr - buf); +} + +size_t +SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len) +{ + size_t len = _len; + Uint8 *buf = (Uint8 *) _buf; + Uint8 *ptr = buf; + SDL_DataQueuePacket *packet; + + if (!queue) { + return 0; + } + + while ((len > 0) && ((packet = queue->head) != NULL)) { + const size_t avail = packet->datalen - packet->startpos; + const size_t cpy = SDL_min(len, avail); + SDL_assert(queue->queued_bytes >= avail); + + SDL_memcpy(ptr, packet->data + packet->startpos, cpy); + packet->startpos += cpy; + ptr += cpy; + queue->queued_bytes -= cpy; + len -= cpy; + + if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */ + queue->head = packet->next; + SDL_assert((packet->next != NULL) || (packet == queue->tail)); + packet->next = queue->pool; + queue->pool = packet; + } + } + + SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0)); + + if (queue->head == NULL) { + queue->tail = NULL; /* in case we drained the queue entirely. */ + } + + return (size_t) (ptr - buf); +} + +size_t +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: */ + |