|
/***************************************************************************
|
|
begin : Wed Sep 12 2012
|
|
copyright : (C) 2012 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Lesser General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2.1 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library 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 *
|
|
* Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this library; if not, write to the Free Software *
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
|
|
* MA 02111-1307 USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#define DISABLE_DEBUGLOG
|
|
|
|
|
|
#include "pointerlist_p.h"
|
|
#include <gwenhywfar/debug.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
|
|
|
|
GWEN_POINTERLIST_TABLE *GWEN_PointerListTable_new(void) {
|
|
GWEN_POINTERLIST_TABLE *idt;
|
|
|
|
GWEN_NEW_OBJECT(GWEN_POINTERLIST_TABLE, idt);
|
|
idt->refCount=1;
|
|
|
|
idt->freeEntries=GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
return idt;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerListTable_free(GWEN_POINTERLIST_TABLE *idt) {
|
|
if (idt) {
|
|
assert(idt->refCount);
|
|
if (--(idt->refCount)==0) {
|
|
GWEN_FREE_OBJECT(idt);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static inline int GWEN_PointerListTable_AddPtr(GWEN_POINTERLIST_TABLE *idt, void *ptr) {
|
|
unsigned int i;
|
|
|
|
for (i=0; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]==0) {
|
|
idt->entries[i]=ptr;
|
|
idt->freeEntries--;
|
|
return 0;
|
|
}
|
|
} /* for */
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
static inline int GWEN_PointerListTable_AppendPtr(GWEN_POINTERLIST_TABLE *idt, void *ptr) {
|
|
if (idt->freeEntries) {
|
|
unsigned int i;
|
|
|
|
i=GWEN_POINTERLIST_TABLE_MAXENTRIES-idt->freeEntries;
|
|
idt->entries[i]=ptr;
|
|
idt->freeEntries--;
|
|
return 0;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
static inline int GWEN_PointerListTable_HasPtr(const GWEN_POINTERLIST_TABLE *idt, void *ptr) {
|
|
unsigned int i;
|
|
|
|
for (i=0; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]==ptr) {
|
|
return 1;
|
|
}
|
|
} /* for */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static inline int GWEN_PointerListTable_DelPtr(GWEN_POINTERLIST_TABLE *idt, void *ptr) {
|
|
unsigned int i;
|
|
|
|
for (i=0; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]==ptr) {
|
|
idt->entries[i]=0;
|
|
idt->freeEntries++;
|
|
return 0;
|
|
}
|
|
} /* for */
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
static inline int GWEN_PointerListTable_IsEmpty(const GWEN_POINTERLIST_TABLE *idt) {
|
|
return GWEN_POINTERLIST_TABLE_MAXENTRIES==idt->freeEntries;
|
|
}
|
|
|
|
|
|
|
|
static inline int GWEN_PointerListTable_IsFull(const GWEN_POINTERLIST_TABLE *idt) {
|
|
return idt->freeEntries==0;
|
|
}
|
|
|
|
|
|
#if 0
|
|
static inline unsigned int GWEN_PointerListTable_GetCount(const GWEN_POINTERLIST_TABLE *idt) {
|
|
return GWEN_POINTERLIST_TABLE_MAXENTRIES-idt->freeEntries;
|
|
}
|
|
|
|
|
|
|
|
static inline void *GWEN_PointerListTable_GetFirstPtr(const GWEN_POINTERLIST_TABLE *idt, uint64_t *tabIdx) {
|
|
unsigned int i;
|
|
|
|
for (i=0; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]!=0) {
|
|
*tabIdx=i;
|
|
return idt->entries[i];
|
|
}
|
|
} /* for */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
static inline void *GWEN_PointerListTable_GetNextPtr(const GWEN_POINTERLIST_TABLE *idt, uint64_t *tabIdx) {
|
|
unsigned int i;
|
|
|
|
for (i=(*tabIdx)+1; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]!=0) {
|
|
*tabIdx=i;
|
|
return idt->entries[i];
|
|
}
|
|
} /* for */
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
GWEN_POINTERLIST *GWEN_PointerList_new(void) {
|
|
GWEN_POINTERLIST *idl;
|
|
|
|
GWEN_NEW_OBJECT(GWEN_POINTERLIST, idl);
|
|
idl->refCount=1;
|
|
idl->tableStep=GWEN_POINTERLIST_DEFAULT_STEP;
|
|
return idl;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerList_Attach(GWEN_POINTERLIST *idl) {
|
|
assert(idl);
|
|
assert(idl->refCount);
|
|
idl->refCount++;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerList_free(GWEN_POINTERLIST *idl) {
|
|
if (idl) {
|
|
assert(idl->refCount);
|
|
if (idl->refCount==1) {
|
|
GWEN_PointerList_Clear(idl);
|
|
idl->refCount=0;
|
|
GWEN_FREE_OBJECT(idl);
|
|
}
|
|
else
|
|
idl->refCount--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerList_AddTable(GWEN_POINTERLIST *idl, GWEN_POINTERLIST_TABLE *idt) {
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
|
|
assert(idl);
|
|
|
|
tablePtr=idl->pIdTablePointers;
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
if (*tablePtr==NULL)
|
|
break;
|
|
} /* while */
|
|
|
|
if (idx>=idl->idTableCount) {
|
|
uint32_t newCount;
|
|
GWEN_POINTERLIST_TABLE **newPtr;
|
|
|
|
/* resize */
|
|
newCount=idl->idTableCount+idl->tableStep;
|
|
newPtr=(GWEN_POINTERLIST_TABLE **)realloc(idl->pIdTablePointers, sizeof(GWEN_POINTERLIST_TABLE*)*newCount);
|
|
assert(newPtr);
|
|
/* init new pointers */
|
|
memset((void*)(newPtr+idl->idTableCount),
|
|
0,
|
|
sizeof(GWEN_POINTERLIST_TABLE*)*(newCount-idl->idTableCount));
|
|
idl->pIdTablePointers=newPtr;
|
|
idl->pIdTablePointers[idl->idTableCount]=idt;
|
|
idl->lastTableIdx=idl->idTableCount;
|
|
idl->idTableCount=newCount;
|
|
}
|
|
else {
|
|
idl->pIdTablePointers[idx]=idt;
|
|
idl->lastTableIdx=idx;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int GWEN_PointerList_AddPtr(GWEN_POINTERLIST *idl, void *ptr) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
|
|
assert(idl);
|
|
|
|
if (idl->pIdTablePointers==NULL) {
|
|
/* create an initial pointer table which can take up to tableStep pointers */
|
|
idl->pIdTablePointers=(GWEN_POINTERLIST_TABLE **) malloc(sizeof(GWEN_POINTERLIST_TABLE*)*(idl->tableStep));
|
|
assert(idl->pIdTablePointers);
|
|
memset(idl->pIdTablePointers, 0, sizeof(GWEN_POINTERLIST*)*(idl->tableStep));
|
|
idl->idTableCount=idl->tableStep;
|
|
}
|
|
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt && !GWEN_PointerListTable_IsFull(idt))
|
|
break;
|
|
} /* while */
|
|
|
|
if (idx>=idl->idTableCount) {
|
|
idt=GWEN_PointerListTable_new();
|
|
GWEN_PointerList_AddTable(idl, idt);
|
|
}
|
|
|
|
GWEN_PointerListTable_AddPtr(idt, ptr);
|
|
idl->entryCount++;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_PointerList_DelPtr(GWEN_POINTERLIST *idl, void *ptr) {
|
|
if (idl->pIdTablePointers) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt && !GWEN_PointerListTable_DelPtr(idt, ptr)) {
|
|
/* found a table which had this id */
|
|
GWEN_PointerList_Clean(idl);
|
|
idl->entryCount--;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_PointerList_HasPtr(const GWEN_POINTERLIST *idl, void *ptr) {
|
|
if (idl->pIdTablePointers) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt && GWEN_PointerListTable_HasPtr(idt, ptr))
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerList_Clean(GWEN_POINTERLIST *idl) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt && GWEN_PointerListTable_IsEmpty(idt)) {
|
|
GWEN_PointerListTable_free(idt);
|
|
*tablePtr=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerList_Clear(GWEN_POINTERLIST *idl) {
|
|
if (idl->pIdTablePointers) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt) {
|
|
GWEN_PointerListTable_free(idt);
|
|
*tablePtr=NULL;
|
|
}
|
|
}
|
|
free(idl->pIdTablePointers);
|
|
idl->pIdTablePointers=NULL;
|
|
}
|
|
idl->entryCount=0;
|
|
idl->nextIdx=0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_POINTERLIST *GWEN_PointerList_dup(const GWEN_POINTERLIST *idl) {
|
|
GWEN_POINTERLIST *nidl;
|
|
int idx;
|
|
|
|
nidl=GWEN_PointerList_new();
|
|
nidl->tableStep=idl->tableStep;
|
|
|
|
nidl->idTableCount=idl->idTableCount;
|
|
nidl->entryCount=idl->entryCount;
|
|
if (idl->pIdTablePointers) {
|
|
for (idx=0; idx<idl->idTableCount; idx++) {
|
|
GWEN_POINTERLIST_TABLE *idt;
|
|
|
|
idt=idl->pIdTablePointers[idx];
|
|
if (idt && !GWEN_PointerListTable_IsEmpty(idt)) {
|
|
GWEN_POINTERLIST_TABLE *nidt;
|
|
|
|
nidt=GWEN_PointerListTable_new();
|
|
memmove(nidt->entries, idt->entries, GWEN_POINTERLIST_TABLE_MAXENTRIES*sizeof(void*));
|
|
nidt->freeEntries=idt->freeEntries;
|
|
GWEN_PointerList_AddTable(nidl, nidt);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nidl;
|
|
}
|
|
|
|
|
|
|
|
uint64_t GWEN_PointerList_GetEntryCount(const GWEN_POINTERLIST *idl) {
|
|
assert(idl);
|
|
assert(idl->refCount);
|
|
|
|
return idl->entryCount;
|
|
}
|
|
|
|
|
|
|
|
void *GWEN_PointerList_GetFirstPtr(const GWEN_POINTERLIST *idl, uint64_t *pos) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idx;
|
|
int idIndex=0;
|
|
|
|
*pos=0;
|
|
for (idx=0, tablePtr=idl->pIdTablePointers; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt && !GWEN_PointerListTable_IsEmpty(idt)) {
|
|
int i;
|
|
void *ptr;
|
|
|
|
for (i=0; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]!=0) {
|
|
ptr=idt->entries[i];
|
|
*pos=idIndex+i+1;
|
|
return ptr;
|
|
}
|
|
}
|
|
}
|
|
idIndex+=GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
void *GWEN_PointerList_GetNextPtr(const GWEN_POINTERLIST *idl, uint64_t *pos) {
|
|
if (*pos) {
|
|
GWEN_POINTERLIST_TABLE *idt;
|
|
uint64_t tableNum=*pos / GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
uint64_t tableIdx=*pos % GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
GWEN_POINTERLIST_TABLE **tablePtr;
|
|
int idIndex=0;
|
|
int idx;
|
|
|
|
if (tableNum>idl->idTableCount) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Table number out of range");
|
|
*pos=0;
|
|
return 0;
|
|
}
|
|
|
|
idIndex=(tableNum*GWEN_POINTERLIST_TABLE_MAXENTRIES);
|
|
for (idx=tableNum, tablePtr=idl->pIdTablePointers+tableNum; idx<idl->idTableCount; idx++, tablePtr++) {
|
|
idt=*tablePtr;
|
|
if (idt && !GWEN_PointerListTable_IsEmpty(idt)) {
|
|
int i;
|
|
void *ptr;
|
|
|
|
if (idx==tableNum) {
|
|
for (i=tableIdx; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]!=0) {
|
|
ptr=idt->entries[i];
|
|
*pos=idIndex+i+1;
|
|
return ptr;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (i=0; i<GWEN_POINTERLIST_TABLE_MAXENTRIES; i++) {
|
|
if (idt->entries[i]!=0) {
|
|
ptr=idt->entries[i];
|
|
*pos=idIndex+i+1;
|
|
return ptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
idIndex+=GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
}
|
|
*pos=0;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
GWEN_POINTERLIST_ITERATOR *GWEN_PointerList_Iterator_new(GWEN_POINTERLIST *idl) {
|
|
GWEN_POINTERLIST_ITERATOR *it;
|
|
|
|
assert(idl);
|
|
GWEN_NEW_OBJECT(GWEN_POINTERLIST_ITERATOR, it);
|
|
|
|
GWEN_PointerList_Attach(idl);
|
|
it->list=idl;
|
|
|
|
return it;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_PointerList_Iterator_free(GWEN_POINTERLIST_ITERATOR *it) {
|
|
if (it) {
|
|
GWEN_PointerList_free(it->list);
|
|
GWEN_FREE_OBJECT(it);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void *GWEN_PointerList_Iterator_GetFirstId(GWEN_POINTERLIST_ITERATOR *it) {
|
|
return GWEN_PointerList_GetFirstPtr(it->list, &(it->nextIndex));
|
|
}
|
|
|
|
|
|
|
|
void *GWEN_PointerList_Iterator_GetNextId(GWEN_POINTERLIST_ITERATOR *it) {
|
|
return GWEN_PointerList_GetNextPtr(it->list, &(it->nextIndex));
|
|
}
|
|
|
|
|
|
|
|
int GWEN_PointerList_AppendPtr(GWEN_POINTERLIST *idl, void *ptr) {
|
|
GWEN_POINTERLIST_TABLE *idt=NULL;
|
|
|
|
assert(idl);
|
|
|
|
if (idl->pIdTablePointers==NULL) {
|
|
/* create an initial pointer table which can take up to tableStep pointers */
|
|
idl->pIdTablePointers=(GWEN_POINTERLIST_TABLE **) malloc(sizeof(GWEN_POINTERLIST_TABLE*)*(idl->tableStep));
|
|
assert(idl->pIdTablePointers);
|
|
memset(idl->pIdTablePointers, 0, sizeof(GWEN_POINTERLIST_TABLE*)*(idl->tableStep));
|
|
idl->idTableCount=idl->tableStep;
|
|
}
|
|
|
|
idt=idl->pIdTablePointers[idl->lastTableIdx];
|
|
if (idt==NULL || GWEN_PointerListTable_IsFull(idt)) {
|
|
idt=GWEN_PointerListTable_new();
|
|
GWEN_PointerList_AddTable(idl, idt);
|
|
}
|
|
|
|
GWEN_PointerListTable_AppendPtr(idt, ptr);
|
|
idl->entryCount++;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void *GWEN_PointerList_GetPtrAt(const GWEN_POINTERLIST *idl, uint64_t idx) {
|
|
GWEN_POINTERLIST_TABLE *idt;
|
|
uint64_t tableNum=idx / GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
uint64_t tableIdx=idx % GWEN_POINTERLIST_TABLE_MAXENTRIES;
|
|
|
|
assert(idl);
|
|
if (tableNum>idl->idTableCount) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Table index out of range");
|
|
return 0;
|
|
}
|
|
|
|
idt=idl->pIdTablePointers[tableNum];
|
|
if (idt==NULL) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Table index points to an empty table");
|
|
return 0;
|
|
}
|
|
|
|
return idt->entries[tableIdx];
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|