git » fp-git.git » master » tree

[master] / PR / src / lib / layers / list.c

/*  Princed V3 - Prince of Persia Level Editor for PC Version
    Copyright (C) 2003 Princed Development Team

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    The authors of this program may be contacted at http://forum.princed.com.ar
*/

/*
list.c: Princed Resources : Order-optimized list implementation
������
 Copyright 2005 Princed Development Team
  Created: 04 Jun 2005

  Author: Enrique Calot <ecalot.cod@princed.com.ar>
  Version: 1.00 (2005-Jun-04)

 Note:
  DO NOT remove this copyright notice
*/

/* Defines */
#include "list.h"
#include <stdlib.h>
#include <string.h> /* memcpy */

tList list_create(int dataSize,int dataCmp(const void*,const void*),void dataFree(void* a)) {
	tList r;
	r.size=dataSize;
	r.cmp=dataCmp;
	r.free=dataFree;
	r.cursor=NULL;
	r.first=NULL;
	return r;
}

void list_insert(tList *list,const void* data) {
	/* I will assume sequential access is very common,
	 * so it is very possible that data is the next element.
	 * I will check that and if not I'll start a sequential search */
	tListNode *node;
	node=(tListNode*)malloc(sizeof(tListNode));
	node->data=malloc(list->size);
	memcpy(node->data,data,list->size);

	if (!list->first) {
		/* insert first */
		list->first=node;
		node->next=NULL;
	} else {
		/* if the data was lower, start searching from the beginning */
		if (list->cmp(list->cursor->data/*>*/,data)==GT) list->cursor=list->first;
		/* in case the first record is higher than the data, we will insert the data as the first */
		if ((list->cursor==list->first) && (list->cmp(list->first->data/*>=*/,data)!=LT)) {
			node->next=list->first;
			list->first=node;
		} else {
			/* search until we find the first higher record or the end of the list */
			while ((list->cursor->next) && (list->cmp(list->cursor->next->data/*>*/,data)!=GT))
				list->cursor=list->cursor->next;

			node->next=list->cursor->next;
			list->cursor->next=node;
		}
	}

	list->cursor=node;
}

void list_drop(tList *list) {
	tListNode* aux;
	list->cursor=list->first;
	while (list->cursor) {
		aux=list->cursor->next;
		if (list->free) list->free(list->cursor->data);
		free(list->cursor->data);
		free(list->cursor);
		list->cursor=aux;
	}
	list->first=NULL;
}

void list_nextCursor(tList* list) {
	if (list->cursor) list->cursor=list->cursor->next;
}

void list_firstCursor(tList* list) {
	list->cursor=list->first;
}

int list_moveCursor(tList* list,const void* data) {
	if (!list->first) {
		return 0; /* false */
	} else {
		/* if the data was lower, start searching from the beginning */
		if ((!list->cursor)||(list->cmp(list->cursor->data/*>*/,data)==GT)) list->cursor=list->first;
		/* in case the first record is higher than the data, we will move the cursor to the first and return 0 */
		if ((list->cursor==list->first) && (list->cmp(list->first->data/*>=*/,data)!=LT)) {
			return list->cmp(list->first->data/*==*/,data)==EQ;
		} else {
			/* search until we find the first higher record or the end of the list */
			while ((list->cursor->next) && (list->cmp(list->cursor->next->data/*>*/,data)!=GT))
				list->cursor=list->cursor->next;
			/* if the prior to the first higher record is equal to data, we've found it, if not 0 will be returned;
			 * of course the cursor will be set to the prior to the first higher record in both cases */
			return (list->cmp(list->cursor->data/*>*/,data)==EQ);
		}
	}
}

void* list_getCursor(tList* list) {
	if (!list->cursor) return NULL;
	return list->cursor->data;
}

void list_reorder(tList* list,int dataCmp(const void*,const void*)) {
	/* This algorithm is O(1/2 * n^2) but as we know the element order is not fully altered
	 * thanks to the insertion optimization, the algorithm order decreases a lot, making
	 * it better even than a qsort.
	 */
	tList newList;
	tListNode* aux;

	/* create a new list with the new dataCmp function */
	newList.size=list->size;
	newList.cmp=dataCmp;
	newList.free=list->free;
	newList.cursor=NULL;
	newList.first=NULL;

	/* copy and drop the old list */
	list->cursor=list->first;
	while (list->cursor) {
		aux=list->cursor->next;

		list_insert(&newList,list->cursor->data);

		free(list->cursor->data);
		free(list->cursor);
		list->cursor=aux;
	}

	/* overwrite the deprecated old list with the new one */
	*list=newList;

	/* move the cursor to the first place to re initialize the new list */
	list_firstCursor(list);
}