mirror of
https://github.com/gnustep/libs-performance.git
synced 2025-02-14 15:41:22 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@32439 72102866-910b-0410-8b05-ffd578937521
371 lines
7.8 KiB
Objective-C
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;
|
|
}
|