Skip to content

Commit

Permalink
Moar Bugfixes! Mostly around Maps/Lists
Browse files Browse the repository at this point in the history
  • Loading branch information
ColumPaget committed Feb 12, 2018
1 parent 475bdda commit 52d0e55
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 29 deletions.
2 changes: 2 additions & 0 deletions DataParser.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const char *ParserJSONItems(int ParserType, const char *Doc, ListNode *Parent, i
{
case '[':
ptr=ParserAddNewStructure(ParserType, ptr, Parent, ITEM_ARRAY, Name, IndentLevel+1);
Name=CopyStr(Name,"");
break;

case ']':
Expand All @@ -71,6 +72,7 @@ const char *ParserJSONItems(int ParserType, const char *Doc, ListNode *Parent, i

case '{':
ptr=ParserAddNewStructure(ParserType, ptr, Parent, ITEM_ENTITY, Name, IndentLevel+1);
Name=CopyStr(Name,"");
break;

case '}':
Expand Down
78 changes: 52 additions & 26 deletions List.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@
#include "List.h"
#include "Time.h"

unsigned long ListSize(ListNode *Node)
{
ListNode *Head;

Head=ListGetHead(Node);
if (Head && Head->Stats) return(Head->Stats->Hits);
return(0);
}


void MapDumpSizes(ListNode *Head)
{
int i;
ListNode *Chain;

for (i=0; i < MapChainCount(Head); i++)
{
printf("%d %d\n",i,ListSize(MapGetNthChain(Head, i)));
Chain=MapGetNthChain(Head, i);
printf("%d %d %d\n",i,Chain,ListSize(Chain));
}
}

Expand Down Expand Up @@ -40,11 +52,13 @@ ListNode *MapCreate(int Buckets, int Flags)
Node=ListCreate();
Node->Flags |= LIST_FLAG_MAP_HEAD | Flags;
Node->ItemType=Buckets;

//we allocate one more than we will use, so the last one acts as a terminator
Node->Item=calloc(Buckets+1, sizeof(ListNode));
SubNode=(ListNode *) Node->Item;
for (i=0; i < Buckets; i++)
{
SubNode->Head=SubNode;
SubNode->Head=Node;
SubNode->Prev=SubNode;
SubNode->Flags |= LIST_FLAG_MAP_CHAIN | Flags;
SubNode->Stats=(ListStats *) calloc(1,sizeof(ListStats));
Expand Down Expand Up @@ -121,6 +135,11 @@ ListNode *MapGetChain(ListNode *Map, const char *Key)



/*
Number of items is stored in the 'Stats->Hits' value of the head listnode. For normal nodes this would be
a counter of how many times the node has been accessed with 'ListFindNamedItem etc,
but the head node is never directly accessed this way, so we store the count of list items in this instead
*/

void ListSetNoOfItems(ListNode *LastItem, unsigned long val)
{
Expand All @@ -138,24 +157,38 @@ unsigned long ListIncrNoOfItems(ListNode *List)
{
ListNode *Head;

//avoid a function call by not calling ListGetHead
if (List->Flags & LIST_FLAG_MAP_CHAIN) List->Stats->Hits++;

Head=List->Head;
if (Head->Flags & LIST_FLAG_MAP_CHAIN)
{
Head->Stats->Hits++;

if (List->Next==NULL) Head->Prev=List; /* The head Item has its Prev as being the last item! */
//get map head, rather than chain head
Head=Head->Head;
}
Head->Stats->Hits++;

return(Head->Stats->Hits);
}



unsigned long ListDecrNoOfItems(ListNode *List)
{
ListNode *Head;

//avoid a function call by not calling ListGetHead
if (List->Flags & LIST_FLAG_MAP_CHAIN) List->Stats->Hits--;
Head=List->Head;
if (Head->Flags & LIST_FLAG_MAP_CHAIN)
{
Head->Stats->Hits--;
//get map head, rather than chain head
Head=Head->Head;
}

Head->Stats->Hits--;

if (List->Next==NULL) Head->Prev=List->Prev; /* The head Item has its Prev as being the last item! */
if (Head->Stats->Hits > 0) Head->Stats->Hits--;
return(Head->Stats->Hits);
}

Expand All @@ -172,8 +205,7 @@ void ListThreadNode(ListNode *Prev, ListNode *Node)
Prev->Next=Node;
Node->Next=Next;

//avoid a function call by not calling ListGetHead
Head=Prev->Head;
Head=ListGetHead(Prev);
Node->Head=Head;

// Next might be NULL! If it is, then our new node is last
Expand All @@ -188,13 +220,13 @@ void ListUnThreadNode(ListNode *Node)
{
ListNode *Head, *Prev, *Next;

ListDecrNoOfItems(Node);
Prev=Node->Prev;
Next=Node->Next;
if (Prev !=NULL) Prev->Next=Next;
if (Next !=NULL) Next->Prev=Prev;

//avoid a function call by not calling ListGetHead
Head=Node->Head;
Head=ListGetHead(Node);
if (Head)
{
//prev node of head points to LAST item in list
Expand All @@ -207,9 +239,9 @@ void ListUnThreadNode(ListNode *Node)
if (Head->Side==Node) Head->Side=NULL;
if (Head->Next==Node) Head->Next=Next;
if (Head->Prev==Node) Head->Prev=Prev;
ListDecrNoOfItems(Node);
}

//make our unthreaded node a singleton
Node->Head=NULL;
Node->Prev=NULL;
Node->Next=NULL;
Expand Down Expand Up @@ -319,13 +351,7 @@ ListNode *ListAddTypedItem(ListNode *ListStart, uint16_t Type, const char *Name,
{
ListNode *Curr;

if (ListStart->Flags & LIST_FLAG_MAP_HEAD)
{
//There's no real way for MapGetChain to fail, so we update stats
//here
if (ListStart->Stats) ListStart->Stats->Hits++;
ListStart=MapGetChain(ListStart, Name);
}
if (ListStart->Flags & LIST_FLAG_MAP_HEAD) ListStart=MapGetChain(ListStart, Name);

Curr=ListGetLast(ListStart);
if (Curr==NULL) return(Curr);
Expand Down Expand Up @@ -364,22 +390,21 @@ ListNode *ListFindNamedItemInsert(ListNode *Root, const char *Name)
else result=strcasecmp(Next->Tag,Name);

if (result==0) return(Next);
//if result < 0 then it means the cached item is ahead of our insert point, so we might as well jump to it
else if (result < 0) Curr=Next;
//if result < 0 AND ITS AN ORDERED LIST then it means the cached item is ahead of our insert point, so we might as well jump to it
else if ((Root->Flags & LIST_FLAG_ORDERED) && (result < 0)) Curr=Next;
}


//Check last item in list
Prev=Head->Prev;
if (Prev && (Prev != Head) && Prev->Tag)
{
if (Head->Flags & LIST_FLAG_CASE) result=strcmp(Prev->Tag,Name);
else result=strcasecmp(Prev->Tag,Name);

if (result == 0) return(Prev);
if ((Head->Flags & LIST_FLAG_ORDERED) && (result < 1)) return(Prev);
}


Prev=Head;
while (Curr)
{
Expand Down Expand Up @@ -501,14 +526,14 @@ ListNode *MapGetNext(ListNode *CurrItem)
return(CurrItem->Next);
}

//'Head' here points to a BUCKET HEADER. These are marked with this flag, except the last one
//so we know when we've reached the end
if (CurrItem->Flags & LIST_FLAG_MAP_HEAD)
{
CurrItem=(ListNode *) CurrItem->Item;
if (CurrItem->Next) return(CurrItem->Next);
}

//'Head' here points to a BUCKET HEADER. These are marked with this flag, except the last one
//so we know when we've reached the end
Head=ListGetHead(CurrItem);
while (Head->Flags & LIST_FLAG_MAP_CHAIN)
{
Expand Down Expand Up @@ -539,7 +564,8 @@ ListNode *ListGetLast(ListNode *CurrItem)
Head=ListGetHead(CurrItem);
if (! Head) return(CurrItem);
/* the dummy header has a 'Prev' entry that points to the last item! */
return(Head->Prev);
if (Head->Prev) return(Head->Prev);
return(Head);
}


Expand Down
9 changes: 6 additions & 3 deletions List.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,17 @@ typedef struct
unsigned long Hits;
} ListStats;


//attempt to order items in likely use order, this *might* help the L1 cache
//is 32 bytes, so should fit in one cache line
typedef struct lnode
{
struct lnode *Next;
struct lnode *Prev;
char *Tag;
//in map heads ItemType is used to hold the number of buckets
uint16_t ItemType;
uint16_t Flags;
//in map heads ItemType is used to hold the number of buckets
struct lnode *Head;
void *Item;
struct lnode *Side;
Expand All @@ -69,10 +70,11 @@ typedef struct lnode
//this allows 'ListCreate' to be called with flags or without
#define ListCreate(F) (ListInit(F + 0))

#define MapChainGetHead(Node) (((Node)->Flags & LIST_FLAG_MAP_CHAIN) ? (Node) : Node->Head)

//if L isn't NULL then return L->Head, it's fine if L->Head is null
#define ListGetHead(Node) ((Node) ? (Node)->Head : NULL)
#define ListGetHead(Node) ((Node) ? MapChainGetHead(Node) : NULL)

#define ListSize(node) (((node) && (node)->Head && (node)->Head->Stats) ? (node)->Head->Stats->Hits : 0)
#define ListNodeGetHits(node) ((node)->Stats ? (node)->Stats->Hits : 0)
#define ListNodeGetTime(node) ((node)->Stats ? (node)->Stats->Time : 0)

Expand Down Expand Up @@ -104,6 +106,7 @@ extern "C" {
typedef void (*LIST_ITEM_DESTROY_FUNC)(void *);
typedef void *(*LIST_ITEM_CLONE_FUNC)(void *);

unsigned long ListSize(ListNode *Node);

//Dump stats on hash distribution in a map
void MapDumpSizes(ListNode *Head);
Expand Down

0 comments on commit 52d0e55

Please sign in to comment.