mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-11-26 11:49:19 +00:00
805 lines
21 KiB
C
805 lines
21 KiB
C
/*
|
|
* Apple // emulator for *ix
|
|
*
|
|
* This software package is subject to the GNU General Public License
|
|
* version 3 or later (your choice) as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Copyright 2013-2015 Aaron Culliney
|
|
*
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "playqueue.h"
|
|
|
|
typedef struct PQListNode_s {
|
|
struct PQListNode_s *next;
|
|
struct PQListNode_s *prev;
|
|
PlayNode_s node;
|
|
} PQListNode_s;
|
|
|
|
typedef struct PQList_s {
|
|
PQListNode_s *availNodes; // ->next only LL
|
|
PQListNode_s *queuedNodes; // double LL
|
|
PQListNode_s *queuedHead;
|
|
} PQList_s;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static inline bool _iterate_list_and_find_node(INOUT PQListNode_s **listNodePtr, long nodeId) {
|
|
while (*listNodePtr) {
|
|
if ((*listNodePtr)->node.nodeId == nodeId) {
|
|
return true;
|
|
}
|
|
*listNodePtr = (*listNodePtr)->next;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static long playq_enqueue(PlayQueue_s *_this, INOUT PlayNode_s *node) {
|
|
long err = 0;
|
|
|
|
do {
|
|
PQList_s *list = (PQList_s *)(_this->_internal);
|
|
|
|
// detach a node from the available pool
|
|
PQListNode_s *listNode = list->availNodes;
|
|
if (!listNode) {
|
|
ERRLOG("Cannot enqueue: no slots available");
|
|
err = -1;
|
|
break;
|
|
}
|
|
list->availNodes = listNode->next;
|
|
|
|
// exchange data
|
|
listNode->node.numBytes = node->numBytes;
|
|
listNode->node.bytes = node->bytes;
|
|
node->nodeId = listNode->node.nodeId;
|
|
|
|
// enqueue node
|
|
listNode->next = list->queuedNodes;
|
|
listNode->prev = NULL;
|
|
if (list->queuedNodes) {
|
|
list->queuedNodes->prev = listNode;
|
|
}
|
|
list->queuedNodes = listNode;
|
|
|
|
// reset head
|
|
if (listNode->next == NULL) {
|
|
list->queuedHead = listNode;
|
|
}
|
|
} while (0);
|
|
|
|
return err;
|
|
}
|
|
|
|
static long playq_dequeue(PlayQueue_s *_this, OUTPARM PlayNode_s *node) {
|
|
PQList_s *list = (PQList_s *)(_this->_internal);
|
|
if (node) {
|
|
*node = (PlayNode_s){ 0 };
|
|
}
|
|
|
|
bool found = (list->queuedHead != NULL);
|
|
if (found) {
|
|
PQListNode_s *listNode = list->queuedHead;
|
|
|
|
// detach from queued
|
|
list->queuedHead = list->queuedHead->prev;
|
|
if (list->queuedHead) {
|
|
list->queuedHead->next = NULL;
|
|
} else {
|
|
list->queuedNodes = NULL;
|
|
}
|
|
|
|
// copy data
|
|
if (node) {
|
|
*node = listNode->node;
|
|
}
|
|
|
|
// attach to available pool
|
|
listNode->prev = NULL;
|
|
listNode->next = list->availNodes;
|
|
list->availNodes = listNode;
|
|
|
|
/*listNode->node.nodeId = 0;IMMUTABLE*/
|
|
listNode->node.numBytes = 0;
|
|
listNode->node.bytes = NULL;
|
|
} else {
|
|
assert(list->queuedNodes == NULL);
|
|
}
|
|
|
|
return found ? 0 : -1;
|
|
}
|
|
|
|
static long playq_remove(PlayQueue_s *_this, INOUT PlayNode_s *node) {
|
|
|
|
PQList_s *list = (PQList_s *)(_this->_internal);
|
|
PQListNode_s *listNode = list->queuedNodes;
|
|
|
|
bool found = _iterate_list_and_find_node(&listNode, node->nodeId);
|
|
if (found) {
|
|
|
|
// reset head
|
|
if (listNode->next == NULL) {
|
|
list->queuedHead = listNode->prev;
|
|
}
|
|
|
|
// detach listNode from queued list ...
|
|
if (listNode->prev) {
|
|
listNode->prev->next = listNode->next;
|
|
if (listNode->next) {
|
|
listNode->next->prev = listNode->prev;
|
|
}
|
|
} else {
|
|
list->queuedNodes = listNode->next;
|
|
if (listNode->next) {
|
|
listNode->next->prev = NULL;
|
|
}
|
|
}
|
|
|
|
*node = listNode->node; // copy data
|
|
|
|
listNode->next = list->availNodes;
|
|
listNode->prev = NULL;
|
|
list->availNodes = listNode;
|
|
|
|
/*listNode->node.nodeId = 0;IMMUTABLE*/
|
|
listNode->node.numBytes = 0;
|
|
listNode->node.bytes = NULL;
|
|
}
|
|
|
|
return found ? 0 : -1;
|
|
}
|
|
|
|
static void playq_drain(PlayQueue_s *_this) {
|
|
long err = 0;
|
|
do {
|
|
err = _this->Dequeue(_this, NULL);
|
|
} while (err == 0);
|
|
}
|
|
|
|
static long playq_getHead(PlayQueue_s *_this, OUTPARM PlayNode_s *node) {
|
|
long err = 0;
|
|
|
|
PQList_s *list = (PQList_s *)(_this->_internal);
|
|
if (list->queuedHead) {
|
|
*node = list->queuedHead->node;
|
|
} else {
|
|
*node = (PlayNode_s){ 0 };
|
|
err = -1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static long playq_get(PlayQueue_s *_this, OUTPARM PlayNode_s *node) {
|
|
long err = 0;
|
|
|
|
PQList_s *list = (PQList_s *)(_this->_internal);
|
|
PQListNode_s *listNode = list->queuedNodes;
|
|
|
|
_iterate_list_and_find_node(&listNode, node->nodeId);
|
|
if (listNode) {
|
|
*node = listNode->node;
|
|
} else {
|
|
*node = (PlayNode_s){ 0 };
|
|
err = -1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static bool playq_canEnqueue(PlayQueue_s *_this) {
|
|
PQList_s *list = (PQList_s *)(_this->_internal);
|
|
return (list->availNodes != NULL);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void playq_destroyPlayQueue(INOUT PlayQueue_s **queue) {
|
|
|
|
if (!(*queue)) {
|
|
return;
|
|
}
|
|
|
|
if ((*queue)->Drain) {
|
|
(*queue)->Drain(*queue);
|
|
}
|
|
|
|
PQList_s *list = (PQList_s *)((*queue)->_internal);
|
|
if (list) {
|
|
PQListNode_s *node = list->availNodes;
|
|
while (node) {
|
|
PQListNode_s *p = node;
|
|
node = node->next;
|
|
FREE(p);
|
|
}
|
|
}
|
|
|
|
FREE(list);
|
|
FREE(*queue);
|
|
}
|
|
|
|
PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffers) {
|
|
PlayQueue_s *playq = NULL;
|
|
|
|
assert(numBuffers <= MAX_PLAYQ_BUFFERS);
|
|
|
|
do {
|
|
playq = CALLOC(1, sizeof(PlayQueue_s));
|
|
if (!playq) {
|
|
ERRLOG("no memory");
|
|
break;
|
|
}
|
|
|
|
PQList_s *list = CALLOC(1, sizeof(PQList_s));
|
|
playq->_internal = list;
|
|
if (!list) {
|
|
ERRLOG("no memory");
|
|
break;
|
|
}
|
|
|
|
bool allocSuccess = true;
|
|
for (unsigned long i=0; i<numBuffers; i++) {
|
|
PQListNode_s *listNode = CALLOC(1, sizeof(PQListNode_s));
|
|
LOG("CREATING PlayNode_s node ID: %ld", nodeIdPtr[i]);
|
|
listNode->node.nodeId = nodeIdPtr[i];
|
|
if (!listNode) {
|
|
ERRLOG("no memory");
|
|
allocSuccess = false;
|
|
break;
|
|
}
|
|
listNode->next = list->availNodes;
|
|
list->availNodes = listNode;
|
|
}
|
|
if (!allocSuccess) {
|
|
break;
|
|
}
|
|
|
|
playq->Enqueue = &playq_enqueue;
|
|
playq->Dequeue = &playq_dequeue;
|
|
playq->Remove = &playq_remove;
|
|
playq->Drain = &playq_drain;
|
|
playq->GetHead = &playq_getHead;
|
|
playq->Get = &playq_get;
|
|
playq->CanEnqueue = &playq_canEnqueue;
|
|
|
|
return playq;
|
|
} while (0);
|
|
|
|
if (playq) {
|
|
playq_destroyPlayQueue(&playq);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define SELF_TEST 0
|
|
#if SELF_TEST
|
|
bool do_logging = true;
|
|
FILE *error_log = NULL;
|
|
|
|
static void _test_creation(void) {
|
|
LOG("begin test");
|
|
const unsigned long maxNodes = 8;
|
|
long nodeIds[maxNodes];
|
|
for (unsigned long i=0; i<maxNodes; i++) {
|
|
nodeIds[i] = i+42;
|
|
}
|
|
PlayQueue_s *pq = playq_createPlayQueue(nodeIds, maxNodes);
|
|
assert(pq != NULL);
|
|
playq_destroyPlayQueue(&pq);
|
|
assert(pq == NULL);
|
|
}
|
|
|
|
static void _test_internal_list_creation_integrity(void) {
|
|
LOG("begin test");
|
|
const unsigned long maxNodes = 8;
|
|
long nodeIds[maxNodes];
|
|
for (unsigned long i=0; i<maxNodes; i++) {
|
|
nodeIds[i] = i+42;
|
|
}
|
|
PlayQueue_s *pq = playq_createPlayQueue(nodeIds, maxNodes);
|
|
assert(pq != NULL);
|
|
assert(pq->_internal != NULL);
|
|
|
|
PQList_s *list = (PQList_s *)(pq->_internal);
|
|
|
|
assert(list->availNodes);
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->queuedHead == NULL);
|
|
|
|
PQListNode_s *listNode = list->availNodes;
|
|
unsigned int count = 0;
|
|
while (listNode) {
|
|
listNode = listNode->next;
|
|
++count;
|
|
}
|
|
assert (count == maxNodes);
|
|
|
|
playq_destroyPlayQueue(&pq);
|
|
assert(pq == NULL);
|
|
}
|
|
|
|
static void _test_enqueue_dequeue(void) {
|
|
LOG("begin test");
|
|
const unsigned long maxNodes = 4;
|
|
long nodeIds[maxNodes];
|
|
for (unsigned long i=0; i<maxNodes; i++) {
|
|
nodeIds[i] = i+42;
|
|
}
|
|
PlayQueue_s *pq = playq_createPlayQueue(nodeIds, maxNodes);
|
|
assert(pq != NULL);
|
|
|
|
uint8_t *bytesPtr = (uint8_t *)&bytesPtr;
|
|
unsigned long numBytes = 42;
|
|
|
|
PQList_s *list = (PQList_s *)(pq->_internal);
|
|
|
|
assert(list->availNodes);
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->queuedHead == NULL);
|
|
|
|
long err = 0;
|
|
|
|
PlayNode_s node0 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node0);
|
|
assert(err == 0);
|
|
|
|
assert(list->queuedNodes);
|
|
assert(list->queuedHead);
|
|
|
|
PlayNode_s node1 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node1);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node2 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node2);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node3 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node3);
|
|
assert(err == 0);
|
|
|
|
assert(list->availNodes == NULL);
|
|
|
|
// test over-enqueue
|
|
|
|
PlayNode_s node4 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node4);
|
|
assert(err != 0 && "this should fail");
|
|
|
|
// check internal list integrity forward
|
|
|
|
PQListNode_s *listNode = list->queuedNodes;
|
|
assert(listNode->node.nodeId == node3.nodeId);
|
|
assert(listNode->node.numBytes == node3.numBytes);
|
|
assert(listNode->node.bytes == node3.bytes);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->node.nodeId == node2.nodeId);
|
|
assert(listNode->node.numBytes == node2.numBytes);
|
|
assert(listNode->node.bytes == node2.bytes);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->node.nodeId == node1.nodeId);
|
|
assert(listNode->node.numBytes == node1.numBytes);
|
|
assert(listNode->node.bytes == node1.bytes);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode == list->queuedHead);
|
|
assert(listNode->next == NULL);
|
|
|
|
assert(listNode->node.nodeId == node0.nodeId);
|
|
assert(listNode->node.numBytes == node0.numBytes);
|
|
assert(listNode->node.bytes == node0.bytes);
|
|
|
|
// check internal list integrity backward
|
|
|
|
listNode = listNode->prev;
|
|
PQListNode_s *prevHead1 = listNode;
|
|
assert(listNode->node.nodeId == node1.nodeId);
|
|
assert(listNode->node.numBytes == node1.numBytes);
|
|
assert(listNode->node.bytes == node1.bytes);
|
|
|
|
listNode = listNode->prev;
|
|
PQListNode_s *prevHead2 = listNode;
|
|
assert(listNode->node.nodeId == node2.nodeId);
|
|
assert(listNode->node.numBytes == node2.numBytes);
|
|
assert(listNode->node.bytes == node2.bytes);
|
|
|
|
listNode = listNode->prev;
|
|
PQListNode_s *prevHead3 = listNode;
|
|
assert(listNode->node.nodeId == node3.nodeId);
|
|
assert(listNode->node.numBytes == node3.numBytes);
|
|
assert(listNode->node.bytes == node3.bytes);
|
|
|
|
assert(listNode == list->queuedNodes);
|
|
assert(prevHead3 == list->queuedNodes);
|
|
assert(listNode->prev == NULL);
|
|
|
|
// test one dequeue
|
|
|
|
PlayNode_s dqNode = { 0 };
|
|
err = pq->Dequeue(pq, &dqNode);
|
|
assert(err == 0);
|
|
assert(dqNode.nodeId == node0.nodeId);
|
|
assert(dqNode.numBytes == node0.numBytes);
|
|
assert(dqNode.bytes == node0.bytes);
|
|
assert(list->queuedHead == prevHead1);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes->next == NULL);
|
|
|
|
// test successful re-enqueue of node4
|
|
|
|
err = pq->Enqueue(pq, &node4);
|
|
assert(err == 0);
|
|
assert(list->availNodes == NULL);
|
|
assert(list->queuedHead == prevHead1);
|
|
assert(list->queuedNodes != prevHead3);
|
|
|
|
// test dequeue all the things ...
|
|
|
|
err = pq->Dequeue(pq, &dqNode);
|
|
assert(err == 0);
|
|
assert(dqNode.nodeId == node1.nodeId);
|
|
assert(dqNode.numBytes == node1.numBytes);
|
|
assert(dqNode.bytes == node1.bytes);
|
|
assert(list->queuedHead == prevHead2);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes->next == NULL);
|
|
|
|
err = pq->Dequeue(pq, &dqNode);
|
|
assert(err == 0);
|
|
assert(dqNode.nodeId == node2.nodeId);
|
|
assert(dqNode.numBytes == node2.numBytes);
|
|
assert(dqNode.bytes == node2.bytes);
|
|
assert(list->queuedHead == prevHead3);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes->next != NULL);
|
|
assert(list->availNodes->next->next == NULL);
|
|
|
|
err = pq->Dequeue(pq, &dqNode);
|
|
assert(err == 0);
|
|
assert(dqNode.nodeId == node3.nodeId);
|
|
assert(dqNode.numBytes == node3.numBytes);
|
|
assert(dqNode.bytes == node3.bytes);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes->next != NULL);
|
|
assert(list->availNodes->next->next != NULL);
|
|
assert(list->availNodes->next->next->next == NULL);
|
|
|
|
err = pq->Dequeue(pq, &dqNode);
|
|
assert(err == 0);
|
|
assert(dqNode.nodeId == node4.nodeId);
|
|
assert(dqNode.numBytes == node4.numBytes);
|
|
assert(dqNode.bytes == node4.bytes);
|
|
assert(list->queuedHead == NULL);
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes->next != NULL);
|
|
assert(list->availNodes->next->next != NULL);
|
|
assert(list->availNodes->next->next->next != NULL);
|
|
assert(list->availNodes->next->next->next->next == NULL);
|
|
|
|
// test over-dequeue
|
|
err = pq->Dequeue(pq, &dqNode);
|
|
assert (err != 0 && "cannot dequeue with nothing there");
|
|
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->queuedHead == NULL);
|
|
|
|
// cleanup
|
|
|
|
playq_destroyPlayQueue(&pq);
|
|
assert(pq == NULL);
|
|
}
|
|
|
|
static void _test_remove_head_of_queue(void) {
|
|
LOG("begin test");
|
|
const unsigned long maxNodes = 4;
|
|
long nodeIds[maxNodes];
|
|
for (unsigned long i=0; i<maxNodes; i++) {
|
|
nodeIds[i] = i+42;
|
|
}
|
|
PlayQueue_s *pq = playq_createPlayQueue(nodeIds, maxNodes);
|
|
assert(pq != NULL);
|
|
|
|
uint8_t *bytesPtr = (uint8_t *)&bytesPtr;
|
|
unsigned long numBytes = 42;
|
|
long err = 0;
|
|
|
|
PQList_s *list = (PQList_s *)(pq->_internal);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->queuedHead == NULL);
|
|
|
|
PlayNode_s node0 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node0);
|
|
assert(err == 0);
|
|
|
|
assert(list->queuedNodes != NULL);
|
|
assert(list->queuedHead != NULL);
|
|
PQListNode_s *listHead0 = list->queuedHead;
|
|
|
|
PlayNode_s node1 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node1);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node2 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node2);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node3 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node3);
|
|
assert(err == 0);
|
|
|
|
assert(list->queuedHead == listHead0);
|
|
|
|
// dequeue head node using remove
|
|
|
|
assert(list->availNodes == NULL);
|
|
|
|
PlayNode_s dqNode = {
|
|
.nodeId = node0.nodeId,
|
|
};
|
|
err = pq->Remove(pq, &dqNode);
|
|
assert(dqNode.nodeId == node0.nodeId);
|
|
assert(dqNode.numBytes == node0.numBytes);
|
|
assert(dqNode.bytes == node0.bytes);
|
|
|
|
// check integrity of inner list
|
|
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes == listHead0);
|
|
assert(list->availNodes->next == NULL);
|
|
assert(list->availNodes->prev == NULL);
|
|
assert(list->queuedNodes != NULL);
|
|
assert(list->queuedHead != NULL);
|
|
|
|
PQListNode_s *listNode = list->queuedNodes;
|
|
assert(listNode->prev == NULL);
|
|
assert(listNode->next->prev == listNode);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->next->prev == listNode);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->next == NULL);
|
|
assert(list->queuedHead == listNode);
|
|
|
|
// cleanup
|
|
|
|
playq_destroyPlayQueue(&pq);
|
|
assert(pq == NULL);
|
|
}
|
|
|
|
static void _test_remove_tail_of_queue(void) {
|
|
LOG("begin test");
|
|
const unsigned long maxNodes = 4;
|
|
long nodeIds[maxNodes];
|
|
for (unsigned long i=0; i<maxNodes; i++) {
|
|
nodeIds[i] = i+42;
|
|
}
|
|
PlayQueue_s *pq = playq_createPlayQueue(nodeIds, maxNodes);
|
|
assert(pq != NULL);
|
|
|
|
uint8_t *bytesPtr = (uint8_t *)&bytesPtr;
|
|
unsigned long numBytes = 42;
|
|
long err = 0;
|
|
|
|
PQList_s *list = (PQList_s *)(pq->_internal);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->queuedHead == NULL);
|
|
|
|
PlayNode_s node0 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node0);
|
|
assert(err == 0);
|
|
|
|
assert(list->queuedNodes != NULL);
|
|
assert(list->queuedHead != NULL);
|
|
PQListNode_s *listHead0 = list->queuedHead;
|
|
|
|
PlayNode_s node1 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node1);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node2 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node2);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node3 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node3);
|
|
assert(err == 0);
|
|
PQListNode_s *listHead3 = list->queuedNodes;
|
|
|
|
assert(list->queuedHead == listHead0);
|
|
|
|
// dequeue head node using remove
|
|
|
|
assert(list->availNodes == NULL);
|
|
|
|
PlayNode_s dqNode = {
|
|
.nodeId = node3.nodeId,
|
|
};
|
|
err = pq->Remove(pq, &dqNode);
|
|
assert(dqNode.nodeId == node3.nodeId);
|
|
assert(dqNode.numBytes == node3.numBytes);
|
|
assert(dqNode.bytes == node3.bytes);
|
|
|
|
// check integrity of inner list
|
|
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes == listHead3);
|
|
assert(list->availNodes->prev == NULL);
|
|
assert(list->availNodes->next == NULL);
|
|
assert(list->queuedNodes != NULL);
|
|
assert(list->queuedHead != NULL);
|
|
assert(list->queuedHead == listHead0);
|
|
|
|
PQListNode_s *listNode = list->queuedNodes;
|
|
assert(listNode->prev == NULL);
|
|
assert(listNode->next->prev == listNode);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->next->prev == listNode);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->next == NULL);
|
|
assert(list->queuedHead == listNode);
|
|
|
|
// cleanup
|
|
|
|
playq_destroyPlayQueue(&pq);
|
|
assert(pq == NULL);
|
|
}
|
|
|
|
static void _test_remove_middle_of_queue(void) {
|
|
LOG("begin test");
|
|
const unsigned long maxNodes = 4;
|
|
long nodeIds[maxNodes];
|
|
for (unsigned long i=0; i<maxNodes; i++) {
|
|
nodeIds[i] = i+42;
|
|
}
|
|
PlayQueue_s *pq = playq_createPlayQueue(nodeIds, maxNodes);
|
|
assert(pq != NULL);
|
|
|
|
uint8_t *bytesPtr = (uint8_t *)&bytesPtr;
|
|
unsigned long numBytes = 42;
|
|
long err = 0;
|
|
|
|
PQList_s *list = (PQList_s *)(pq->_internal);
|
|
assert(list->availNodes != NULL);
|
|
assert(list->queuedNodes == NULL);
|
|
assert(list->queuedHead == NULL);
|
|
|
|
PlayNode_s node0 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node0);
|
|
assert(err == 0);
|
|
|
|
assert(list->queuedNodes != NULL);
|
|
assert(list->queuedHead != NULL);
|
|
PQListNode_s *listHead0 = list->queuedHead;
|
|
|
|
PlayNode_s node1 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node1);
|
|
assert(err == 0);
|
|
|
|
PlayNode_s node2 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node2);
|
|
assert(err == 0);
|
|
PQListNode_s *listHead2 = list->queuedNodes;
|
|
|
|
PlayNode_s node3 = {
|
|
.numBytes = numBytes++,
|
|
.bytes = bytesPtr++,
|
|
};
|
|
err = pq->Enqueue(pq, &node3);
|
|
assert(err == 0);
|
|
|
|
assert(list->queuedHead == listHead0);
|
|
|
|
// dequeue head node using remove
|
|
|
|
assert(list->availNodes == NULL);
|
|
|
|
PlayNode_s dqNode = {
|
|
.nodeId = node2.nodeId,
|
|
};
|
|
err = pq->Remove(pq, &dqNode);
|
|
assert(dqNode.nodeId == node2.nodeId);
|
|
assert(dqNode.numBytes == node2.numBytes);
|
|
assert(dqNode.bytes == node2.bytes);
|
|
|
|
// check integrity of inner list
|
|
|
|
assert(list->availNodes != NULL);
|
|
assert(list->availNodes == listHead2);
|
|
assert(list->availNodes->prev == NULL);
|
|
assert(list->availNodes->next == NULL);
|
|
assert(list->queuedNodes != NULL);
|
|
assert(list->queuedHead != NULL);
|
|
assert(list->queuedHead == listHead0);
|
|
|
|
PQListNode_s *listNode = list->queuedNodes;
|
|
assert(listNode->prev == NULL);
|
|
assert(listNode->next->prev == listNode);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->next->prev == listNode);
|
|
|
|
listNode = listNode->next;
|
|
assert(listNode->next == NULL);
|
|
assert(list->queuedHead == listNode);
|
|
|
|
// cleanup
|
|
|
|
playq_destroyPlayQueue(&pq);
|
|
assert(pq == NULL);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
#warning use Valgrind to check proper memory management
|
|
error_log = stdout;
|
|
LOG("beginning tests");
|
|
_test_creation();
|
|
_test_internal_list_creation_integrity();
|
|
_test_enqueue_dequeue();
|
|
_test_remove_head_of_queue();
|
|
_test_remove_tail_of_queue();
|
|
_test_remove_middle_of_queue();
|
|
LOG("all tests successful");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|