blob: 336ad5aa1c18fe8c9b3caff61686705bc89d91f4 [file] [log] [blame]
/*---------------------------------------------------------------------------*
* linklist_impl.c *
* *
* Copyright 2007, 2008 Nuance Communciations, Inc. *
* *
* Licensed under the Apache License, Version 2.0 (the 'License'); *
* you may not use this file except in compliance with the License. *
* *
* You may obtain a copy of the License at *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an 'AS IS' BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*---------------------------------------------------------------------------*/
#include <stdlib.h>
#include "pmemory.h"
#include "plog.h"
#include "linklist.h"
extern void *lts_alloc(int num, int size);
/* very simple static memory allocation:
1. pool of linked list nodes - from static allocated array
2. each node is marked "used" when allocated; marked "unused" when deallocated
3. since the stress linked lists deal with single words, an array will suffice.
*/
#ifdef USE_STATIC_SLTS
#define NUM_ALLOC_NODES 30 /* Max 30 syllables per word */
typedef struct LNodeAllocElement
{
LNode node;
short usedflag;
} LNodeAllocElement;
static LNodeAllocElement g_LNodeAllocArray[NUM_ALLOC_NODES];
void ClearLNodeArray()
{
int i;
LNode *n;
for(i=0; i<NUM_ALLOC_NODES; i++){
g_LNodeAllocArray[i].usedflag = 0;
n = &(g_LNodeAllocArray[i].node);
n->data = 0;
n->next = n->prev = 0;
}
}
static LNode *AllocNode()
{
int i;
/* return first unused element */
for(i=0; i<NUM_ALLOC_NODES; i++){
if(g_LNodeAllocArray[i].usedflag == 0){
g_LNodeAllocArray[i].usedflag = 1;
/* zero out the node first*/
(g_LNodeAllocArray[i].node).data = NULL;
(g_LNodeAllocArray[i].node).prev = NULL;
(g_LNodeAllocArray[i].node).next = NULL;
return &(g_LNodeAllocArray[i].node);
}
}
/* ran out of nodes */
return NULL;
}
static void FreeNode(LNode *n)
{
int i;
long addr;
/* compare addresses of pointers */
for(i=0; i<NUM_ALLOC_NODES; i++){
addr = (long) (&(g_LNodeAllocArray[i].node));
if(addr == (long)n){
g_LNodeAllocArray[i].usedflag = 0;
return;
}
}
/* not found. don't do anything */
return;
}
#else /* !USE_STATIC_SLTS */
static LNode *AllocNode()
{
return (LNode *)lts_alloc(1, sizeof(LNode));
}
static void FreeNode(LNode *n)
{
FREE(n);
}
#endif
/* Inserts after current element
At return, current element will be point to newly created node
handle static allocation later - possibly using a pool of nodes?
For now, dynamically allocate a new list node with the data
*/
LListResult Insert(LList *list, void *data)
{
LNode *newnode = AllocNode();
if(newnode == NULL){
return LListResourceAllocError;
}
newnode->data = data;
if(list->head == NULL){
/* if list is empty, assign to head */
list->head = newnode;
(list->head)->next = NULL;
(list->head)->prev = NULL;
/* update curr to newly inserted node */
list->curr = list->head;
list->tail = list->head;
return LListSuccess;
}
/* curr not specified, insert from the end */
if(list->curr == NULL){
list->curr = list->tail;
}
/* in cases with single node, default to insert at end */
if(list->curr == list->tail){
/* insert at the end */
newnode->prev = list->curr;
newnode->next = NULL;
(list->curr)->next = newnode;
/* update both curr and end */
list->curr = newnode;
list->tail = newnode;
return LListSuccess;
}else if(list->curr == list->head){
/* insert at head */
newnode->next = list->head;
newnode->prev = NULL;
(list->head)->prev = newnode;
/* update curr to newly inserted node */
list->curr = list->head;
list->head = newnode;
return LListSuccess;
}else{
/* insert somewhere in middle */
newnode->prev = list->curr;
newnode->next = (list->curr)->next;
(list->curr)->next = newnode;
(newnode->next)->prev = newnode;
/* update curr to newly inserted node */
list->curr = newnode;
return LListSuccess;
}
}
/* Deletes at current element
At return, current element will point to previous node
handle static deallocation later - possibly using a pool of nodes?
For now, dynamically free a new list node
*/
LListResult Delete(LList *list)
{
LNode *curr;
if(list->head == NULL){
return LListEmpty;
}
/* start deleting from the end if curr not specified */
if(list->curr == NULL){
list->curr = list->tail;
}
curr = list->curr;
if(curr == list->head){
/* delete from the head */
list->head = curr->next;
if(list->head != NULL){
(list->head)->prev = NULL;
}
FreeNode(curr);
list->curr = list->head;
return LListSuccess;
}else if(curr == list->tail){
/* delete from the end */
list->tail = curr->prev;
if(list->tail != NULL){
(list->tail)->next = NULL;
}
FreeNode(curr);
list->curr = list->tail;
return LListSuccess;
}else{
/* delete somewhere in the middle */
list->curr = curr->next;
/* still check, just in case*/
if(curr->next != NULL){
(curr->next)->prev = curr->prev;
}
if(curr->prev != NULL){
(curr->prev)->next = curr->next;
}
FreeNode(curr);
return LListSuccess;
}
}