#pragma prototyped
#include "ivlib.h"
typedef struct Itvl_s Itvl_t;
typedef struct Nest_s Nest_t;
struct Itvl_s
{
Dtlink_t link;
unsigned char* lo;
unsigned char* hi;
void* data;
};
struct Nest_s
{
Dtdisc_t dc;
Ivfree_f freef;
Dt_t* dt;
Iv_t* flat;
Iv_t* iv;
Ivdisc_t disc;
int changed;
};
static void*
nestmake(Dt_t* dt, void* p, Dtdisc_t* disc)
{
Itvl_t* op = (Itvl_t*)p;
Itvl_t* np;
int size = ((Nest_t*)disc)->iv->size;
if (!(np = newof(0, Itvl_t, 1, 2 * size)))
return 0;
fvcpy(size, np->lo = (unsigned char*)(np + 1), op->lo);
fvcpy(size, np->hi = np->lo + size, op->hi);
np->data = op->data;
return np;
}
static void
nestfree(Dt_t* dt, void* obj, Dtdisc_t* disc)
{
if (((Nest_t*)disc)->freef && ((Itvl_t*)obj)->data)
((Nest_t*)disc)->freef(((Nest_t*)disc)->iv, ((Itvl_t*)obj)->data);
free(obj);
}
static int
nestcmp(Dt_t* dt, void* o1, void* o2, Dtdisc_t* disc)
{
Itvl_t* i1;
Itvl_t* i2;
int size = ((Nest_t*)disc)->iv->size;
int l;
int h;
if ((i1 = (Itvl_t*)o1) == (i2 = (Itvl_t*)o2))
return 0;
if (fvcmp(size, i1->hi, i2->lo) < 0)
return -1;
if (fvcmp(size, i1->lo, i2->hi) > 0)
return 1;
h = fvcmp(size, i1->hi, i2->hi);
l = fvcmp(size, i1->lo, i2->lo);
if (l < 0)
{
if (h >= 0)
return -1;
else
return 0;
}
else if (l == 0)
{
if (h < 0)
return 1;
else if (h == 0)
return 0;
else
return -1;
}
else
{
if (h <= 0)
return 1;
else
return 0;
}
}
static int nestset(Iv_t* iv, unsigned char* lo, unsigned char* hi, void* data)
{
Nest_t* nst;
Itvl_t itvl;
Itvl_t* it;
int size = iv->size;
if (!iv || !(nst = (Nest_t*)iv->data))
return -1;
itvl.lo = lo;
itvl.hi = hi;
itvl.data = data;
if (!(it = (Itvl_t*)dtsearch(nst->dt, &itvl)))
{
nst->changed = 1;
return dtinsert(nst->dt, &itvl) ? 0 : -1;
}
else if (fvcmp(size, it->lo, lo) || fvcmp(size, it->hi, hi))
return -1;
else if (it->data != data)
{
nst->changed = 1;
it->data = data;
return 0;
}
else
return 0;
}
static int nestdel(Iv_t* iv, unsigned char* lo, unsigned char* hi)
{
Nest_t* nst;
Itvl_t itvl;
Itvl_t* it;
int size = iv->size;
if (!(nst = (Nest_t*)iv->data))
return -1;
itvl.lo = lo;
itvl.hi = hi;
if (!(it = (Itvl_t*)dtsearch(nst->dt, &itvl)) || fvcmp(size, it->lo, lo) || fvcmp(size, it->hi, hi))
return -1;
nst->changed = 1;
dtdelete(nst->dt, it);
return 0;
}
static int nest2flat(Iv_t* iv, Nest_t* nst)
{
Itvl_t* it;
if (nst->flat)
ivclose(nst->flat);
if (!(nst->flat = ivopen(&nst->disc, ivmeth("flat"), iv->size, 0)))
return -1;
for(it = (Itvl_t*)dtfirst(nst->dt); it; it = (Itvl_t*)dtnext(nst->dt, it))
ivset(nst->flat, it->lo, it->hi, it->data);
nst->changed = 0;
return 0;
}
static unsigned char*
nestget(Iv_t* iv, unsigned char* pt)
{
Nest_t* nst;
if (!(nst = (Nest_t*)iv->data) || nst->changed && nest2flat(iv, nst) < 0)
return 0;
return nst->flat ? ivget(nst->flat, pt) : 0;
}
static Ivseg_t*
nestseg(Iv_t* iv, unsigned char* pt)
{
Nest_t* nst;
if (!(nst = (Nest_t*)iv->data) || nst->changed && nest2flat(iv, nst) < 0)
return 0;
return nst->flat ? ivseg(nst->flat, pt) : 0;
}
static int
nestevent(Iv_t* iv, int type, void* data)
{
Nest_t* nst;
switch (type)
{
case IV_OPEN:
if (!(nst = newof(0, Nest_t, 1, 0)))
return -1;
nst->dc.makef = nestmake;
nst->dc.freef = nestfree;
nst->dc.comparf = nestcmp;
if (!(nst->dt = dtopen(&nst->dc, Dtoset)))
{
free(nst);
return -1;
}
nst->changed = 0;
nst->flat = 0;
nst->freef = iv->disc->freef;
nst->iv = iv;
nst->disc = *iv->disc;
nst->disc.freef = 0;
iv->data = (void*)nst;
break;
case IV_CLOSE:
if ((nst = (Nest_t*)iv->data))
{
if (nst->flat)
ivclose(nst->flat);
if (nst->dt)
dtclose(nst->dt);
free(nst);
iv->data = 0;
}
break;
}
return 0;
}
static Ivmeth_t _Ivnested =
{
"nested",
"The nested method manages nested intervals so that only points in the smallest containing intervals will be visible.",
0,
nestget,
nestset,
nestdel,
nestseg,
nestevent,
};
IVLIB(nested)