libs-performance/GSIndexedSkipList.m
Richard Frith-MacDonald 75fb416fc7 fix includes/imports
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@32439 72102866-910b-0410-8b05-ffd578937521
2011-03-03 10:51:46 +00:00

371 lines
7.8 KiB
Objective-C

/**
Copyright (C) 2006 Free Software Foundation, Inc.
Written by: Matt Rice <ratmice@yahoo.com>
Date: 2006
This file is part of the Performance Library.
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 3 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 USA.
*/
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#import "GSIndexedSkipList.h"
/* This no longer seems to be needed/correct
#if defined(__MINGW32__)
#include <cstdlib.h> // declares rand()
#endif
*/
#define PrettyErr(x) do { fprintf(stderr, "%s:%i: %s\n",__FILE__, __LINE__, x); exit(EXIT_FAILURE); } while (0)
GSISLNode GSISLNil;
GSISLNode GSISLNewNodeOfLevel(int l, NSZone *zone)
{
GSISLNode ret = (GSISLNode) NSZoneMalloc(zone, sizeof(struct GSISLNode_t)
+ ((l) * sizeof(struct GSISLForward_t)));
if (ret == NULL)
{
PrettyErr(strerror(errno));
}
do
{
ret->forward[l].delta = 0;
} while (--l >= 0);
return ret;
}
void GSISLInitialize()
{
if (GSISLNil != NULL) return;
GSISLNil = GSISLNewNodeOfLevel(0, NSDefaultMallocZone());
GSISLNil->forward[0].delta = UINT_MAX;
GSISLNil->value = nil;
GSISLNil->forward[0].next = NULL;
}
GSISList GSISLInitList(NSZone *zone)
{
GSISList l;
int i;
l = (GSISList)NSZoneMalloc(zone, sizeof(struct GSIndexedSkipList));
if (l == NULL)
{
PrettyErr(strerror(errno));
}
l->zone = zone;
l->level = 0;
l->count = 0;
l->header = GSISLNewNodeOfLevel(GSISLMaxNumberOfLevels, l->zone);
l->header->value = nil;
for (i=0; i < GSISLMaxNumberOfLevels; i++)
{
l->header->forward[0].delta = 0;
l->header->forward[0].next = GSISLNil;
#if GSISL_CACHE_OPT
l->indexCache[i] = 0;
l->nodeCache[i] = l->header;
#endif
}
return(l);
}
void GSISLFreeList(GSISList l)
{
GSISLNode p,q;
p = l->header;
do
{
q = p->forward[0].next;
NSZoneFree(l->zone,p);
p = q;
} while (p != GSISLNil);
NSZoneFree(l->zone, l);
};
int GSISLRandomLevel()
{
int level = 0;
static int p = RAND_MAX / 4;
while (rand() < p && level < GSISLMaxLevel)
{
level++;
}
return level;
}
void GSISLInsertItemAtIndex(GSISList l, GSISLValueType value,
unsigned index)
{
int k, i;
GSISLNode update[GSISLMaxNumberOfLevels];
unsigned updateIndexes[GSISLMaxNumberOfLevels];
GSISLNode p,q;
unsigned depth;
depth = 0;
k = l->level;
#if GSISL_CACHE_OPT
if (l->indexCache[k] < index)
{
p = l->nodeCache[k];
depth = l->indexCache[k];
}
else
{
p = l->header;
}
#else
p = l->header;
#endif
do
{
while (q = p->forward[k].next,
q != GSISLNil && depth + p->forward[k].delta < index + 1)
{
depth += p->forward[k].delta;
p = q;
}
updateIndexes[k] = depth;
update[k] = p;
} while(--k >= 0);
k = GSISLRandomLevel();
q = GSISLNewNodeOfLevel(k, l->zone);
if (k > l->level)
{
/* we are creating a new level that looks like
* header ---> new node ---> tail
*/
k = l->level;
l->level++;
#if GSISL_CACHE_OPT
l->nodeCache[l->level] = l->header;
l->indexCache[l->level] = 0;
#endif
l->header->forward[l->level].delta = index + 1;
l->header->forward[l->level].next = q;
q->forward[l->level].delta = 0;
q->forward[l->level].next = GSISLNil;
}
else
{
/* if there are higher nodes than this nodes level.
increment the deltas in the update, as we are inserting
a node inbetween their starting point and their ending
*/
for (i = k + 1; i <= l->level; i++)
{
if (update[i]->forward[i].delta != 0)
update[i]->forward[i].delta++;
#if GSISL_CACHE_OPT
l->nodeCache[i] = update[i];
l->indexCache[i] = updateIndexes[i];
#endif
}
}
q->value = value;
do
{
/* update from the nodes highest level down to level 0
* on all the levels already existing in the list
*/
p = update[k];
if (p->forward[k].delta)
q->forward[k].delta = updateIndexes[k] + p->forward[k].delta - depth;
p->forward[k].delta = depth + 1 - updateIndexes[k];
q->forward[k].next = p->forward[k].next;
p->forward[k].next = q;
#if GSISL_CACHE_OPT
l->indexCache[k] = updateIndexes[k];
l->nodeCache[k] = update[k];
#endif
} while(--k >= 0);
l->count++;
}
GSISLValueType GSISLRemoveItemAtIndex(GSISList l, unsigned index)
{
int k,m;
GSISLNode update[GSISLMaxNumberOfLevels];
unsigned updateIndexes[GSISLMaxNumberOfLevels];
GSISLNode p,q;
unsigned depth = 0;
GSISLValueType ret;
k = m = l->level;
#if GSISL_CACHE_OPT
if (l->indexCache[k] < index)
{
p = l->nodeCache[k];
depth = l->indexCache[k];
}
else
{
p = l->header;
}
#else
p = l->header;
#endif
do
{
while (q = p->forward[k].next,
q != GSISLNil && depth + p->forward[k].delta < index + 1)
{
depth += p->forward[k].delta;
p = q;
}
update[k] = p;
updateIndexes[k] = depth;
} while(--k >= 0);
for (k = 0; k <= m; k++)
{
p = update[k];
#if GSISL_CACHE_OPT
l->indexCache[k] = updateIndexes[k];
l->nodeCache[k] = update[k];
#endif
if (p->forward[k].next == q)
{
p->forward[k].delta
= (q->forward[k].next == GSISLNil) ? 0
: p->forward[k].delta + q->forward[k].delta - 1;
p->forward[k].next = q->forward[k].next;
}
else if (p->forward[k].next != GSISLNil)
{
p->forward[k].delta--;
}
else
{
p->forward[k].delta = 0;
}
}
ret = q->value;
NSZoneFree(l->zone,q);
/* if header points to nil, decrement the list level */
while (l->header->forward[m].next == GSISLNil && m > 0 )
{
l->header->forward[m].delta = 0;
m--;
}
l->level = m;
l->count--;
return ret;
}
GSISLValueType GSISLItemAtIndex(GSISList l, unsigned index)
{
int k;
unsigned depth = 0;
GSISLNode p,q;
k = l->level;
#if GSISL_CACHE_OPT
if (l->indexCache[k] < index)
{
p = l->nodeCache[k];
depth = l->indexCache[k];
}
else
{
p = l->header;
}
#else
p = l->header;
#endif
do
{
while (q = p->forward[k].next,
q != GSISLNil && depth + p->forward[k].delta < index + 1)
{
depth += p->forward[k].delta;
p = q;
}
#if GSISL_CACHE_OPT
l->nodeCache[k] = p;
l->indexCache[k] = depth;
#endif
} while(--k >= 0);
return(q->value);
}
GSISLValueType
GSISLReplaceItemAtIndex(GSISList l, GSISLValueType newVal, unsigned index)
{
int k;
unsigned depth = 0;
GSISLNode p,q;
GSISLValueType ret;
k = l->level;
#if GSISL_CACHE_OPT
if (l->indexCache[k] < index)
{
p = l->nodeCache[k];
depth = l->indexCache[k];
}
else
{
p = l->header;
}
#else
p = l->header;
#endif
do
{
while (q = p->forward[k].next,
q != GSISLNil && depth + p->forward[k].delta < index + 1)
{
depth += p->forward[k].delta;
p = q;
}
#if GSISL_CACHE_OPT
l->indexCache[k] = depth;
l->nodeCache[k] = p;
#endif
} while(--k >= 0);
ret = q->value;
q->value = newVal;
return ret;
}