2006-11-26 11:13:41 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright 1995, 1998 The Open Group
|
|
|
|
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
the above copyright notice appear in all copies and that both that
|
|
|
|
copyright notice and this permission notice appear in supporting
|
|
|
|
documentation.
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
Except as contained in this notice, the name of The Open Group shall
|
|
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
|
|
other dealings in this Software without prior written authorization
|
|
|
|
from The Open Group.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
See the header set.h for a description of the set ADT.
|
|
|
|
|
|
|
|
Implementation Strategy
|
|
|
|
|
|
|
|
A bit vector is an obvious choice to represent the set, but may take
|
|
|
|
too much memory, depending on the numerically largest member in the
|
|
|
|
set. One expected common case is for the client to ask for *all*
|
|
|
|
protocol. This means it would ask for minor opcodes 0 through 65535.
|
|
|
|
Representing this as a bit vector takes 8K -- and there may be
|
|
|
|
multiple minor opcode intervals, as many as one per major (extension)
|
|
|
|
opcode). In such cases, a list-of-intervals representation would be
|
|
|
|
preferable to reduce memory consumption. Both representations will be
|
|
|
|
implemented, and RecordCreateSet will decide heuristically which one
|
|
|
|
to use based on the set members.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
|
|
#include <dix-config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "misc.h"
|
|
|
|
#include "set.h"
|
|
|
|
|
|
|
|
static int
|
|
|
|
maxMemberInInterval(RecordSetInterval *pIntervals, int nIntervals)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int maxMember = -1;
|
|
|
|
for (i = 0; i < nIntervals; i++)
|
|
|
|
{
|
|
|
|
if (maxMember < (int)pIntervals[i].last)
|
|
|
|
maxMember = pIntervals[i].last;
|
|
|
|
}
|
|
|
|
return maxMember;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
NoopDestroySet(RecordSetPtr pSet)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
/* set operations for bit vector representation */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
RecordSetRec baseSet;
|
|
|
|
int maxMember;
|
|
|
|
/* followed by the bit vector itself */
|
|
|
|
} BitVectorSet, *BitVectorSetPtr;
|
|
|
|
|
|
|
|
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
|
|
|
|
|
|
|
static void
|
|
|
|
BitVectorDestroySet(RecordSetPtr pSet)
|
|
|
|
{
|
|
|
|
xfree(pSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
BitVectorIsMemberOfSet(RecordSetPtr pSet, int pm)
|
|
|
|
{
|
|
|
|
BitVectorSetPtr pbvs = (BitVectorSetPtr)pSet;
|
|
|
|
unsigned long *pbitvec;
|
|
|
|
|
|
|
|
if ((int)pm > pbvs->maxMember) return FALSE;
|
|
|
|
pbitvec = (unsigned long *)(&pbvs[1]);
|
|
|
|
return (pbitvec[pm / BITS_PER_LONG] & ((unsigned long)1 << (pm % BITS_PER_LONG)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
BitVectorFindBit(RecordSetPtr pSet, int iterbit, Bool bitval)
|
|
|
|
{
|
|
|
|
BitVectorSetPtr pbvs = (BitVectorSetPtr)pSet;
|
|
|
|
unsigned long *pbitvec = (unsigned long *)(&pbvs[1]);
|
|
|
|
int startlong;
|
|
|
|
int startbit;
|
|
|
|
int walkbit;
|
|
|
|
int maxMember;
|
|
|
|
unsigned long skipval;
|
|
|
|
unsigned long bits;
|
|
|
|
unsigned long usefulbits;
|
|
|
|
|
|
|
|
startlong = iterbit / BITS_PER_LONG;
|
|
|
|
pbitvec += startlong;
|
|
|
|
startbit = startlong * BITS_PER_LONG;
|
|
|
|
skipval = bitval ? 0L : ~0L;
|
|
|
|
maxMember = pbvs->maxMember;
|
|
|
|
|
|
|
|
|
|
|
|
if (startbit > maxMember) return -1;
|
|
|
|
bits = *pbitvec;
|
|
|
|
usefulbits = ~(((unsigned long)1 << (iterbit - startbit)) - 1);
|
|
|
|
if ( (bits & usefulbits) == (skipval & usefulbits) )
|
|
|
|
{
|
|
|
|
pbitvec++;
|
|
|
|
startbit += BITS_PER_LONG;
|
|
|
|
|
|
|
|
while (startbit <= maxMember && *pbitvec == skipval)
|
|
|
|
{
|
|
|
|
pbitvec++;
|
|
|
|
startbit += BITS_PER_LONG;
|
|
|
|
}
|
|
|
|
if (startbit > maxMember) return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
walkbit = (startbit < iterbit) ? iterbit - startbit : 0;
|
|
|
|
|
|
|
|
bits = *pbitvec;
|
|
|
|
while (walkbit < BITS_PER_LONG && ((!(bits & ((unsigned long)1 << walkbit))) == bitval))
|
|
|
|
walkbit++;
|
|
|
|
|
|
|
|
return startbit + walkbit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static RecordSetIteratePtr
|
|
|
|
BitVectorIterateSet(RecordSetPtr pSet, RecordSetIteratePtr pIter,
|
|
|
|
RecordSetInterval *pInterval)
|
|
|
|
{
|
|
|
|
int iterbit = (int)(long)pIter;
|
|
|
|
int b;
|
|
|
|
|
|
|
|
b = BitVectorFindBit(pSet, iterbit, TRUE);
|
|
|
|
if (b == -1) return (RecordSetIteratePtr)0;
|
|
|
|
pInterval->first = b;
|
|
|
|
|
|
|
|
b = BitVectorFindBit(pSet, b, FALSE);
|
|
|
|
pInterval->last = (b < 0) ? ((BitVectorSetPtr)pSet)->maxMember : b - 1;
|
|
|
|
return (RecordSetIteratePtr)(long)(pInterval->last + 1);
|
|
|
|
}
|
|
|
|
|
2007-11-24 10:55:21 -07:00
|
|
|
static RecordSetOperations BitVectorSetOperations = {
|
2006-11-26 11:13:41 -07:00
|
|
|
BitVectorDestroySet, BitVectorIsMemberOfSet, BitVectorIterateSet };
|
|
|
|
|
2007-11-24 10:55:21 -07:00
|
|
|
static RecordSetOperations BitVectorNoFreeOperations = {
|
2006-11-26 11:13:41 -07:00
|
|
|
NoopDestroySet, BitVectorIsMemberOfSet, BitVectorIterateSet };
|
|
|
|
|
|
|
|
static int
|
|
|
|
BitVectorSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals,
|
|
|
|
int maxMember, int *alignment)
|
|
|
|
{
|
|
|
|
int nlongs;
|
|
|
|
|
|
|
|
*alignment = sizeof(unsigned long);
|
|
|
|
nlongs = (maxMember + BITS_PER_LONG) / BITS_PER_LONG;
|
|
|
|
return (sizeof(BitVectorSet) + nlongs * sizeof(unsigned long));
|
|
|
|
}
|
|
|
|
|
|
|
|
static RecordSetPtr
|
|
|
|
BitVectorCreateSet(RecordSetInterval *pIntervals, int nIntervals,
|
|
|
|
void *pMem, int memsize)
|
|
|
|
{
|
|
|
|
BitVectorSetPtr pbvs;
|
|
|
|
int i, j;
|
|
|
|
unsigned long *pbitvec;
|
|
|
|
|
|
|
|
/* allocate all storage needed by this set in one chunk */
|
|
|
|
|
|
|
|
if (pMem)
|
|
|
|
{
|
|
|
|
memset(pMem, 0, memsize);
|
|
|
|
pbvs = (BitVectorSetPtr)pMem;
|
|
|
|
pbvs->baseSet.ops = &BitVectorNoFreeOperations;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pbvs = (BitVectorSetPtr)Xcalloc(memsize);
|
|
|
|
if (!pbvs) return NULL;
|
|
|
|
pbvs->baseSet.ops = &BitVectorSetOperations;
|
|
|
|
}
|
|
|
|
|
|
|
|
pbvs->maxMember = maxMemberInInterval(pIntervals, nIntervals);
|
|
|
|
|
|
|
|
/* fill in the set */
|
|
|
|
|
|
|
|
pbitvec = (unsigned long *)(&pbvs[1]);
|
|
|
|
for (i = 0; i < nIntervals; i++)
|
|
|
|
{
|
|
|
|
for (j = pIntervals[i].first; j <= (int)pIntervals[i].last; j++)
|
|
|
|
{
|
|
|
|
pbitvec[j/BITS_PER_LONG] |= ((unsigned long)1 << (j % BITS_PER_LONG));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (RecordSetPtr)pbvs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
/* set operations for interval list representation */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
RecordSetRec baseSet;
|
|
|
|
int nIntervals;
|
|
|
|
/* followed by the intervals (RecordSetInterval) */
|
|
|
|
} IntervalListSet, *IntervalListSetPtr;
|
|
|
|
|
|
|
|
static void
|
|
|
|
IntervalListDestroySet(RecordSetPtr pSet)
|
|
|
|
{
|
|
|
|
xfree(pSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
IntervalListIsMemberOfSet(RecordSetPtr pSet, int pm)
|
|
|
|
{
|
|
|
|
IntervalListSetPtr prls = (IntervalListSetPtr)pSet;
|
|
|
|
RecordSetInterval *pInterval = (RecordSetInterval *)(&prls[1]);
|
|
|
|
int hi, lo, probe;
|
|
|
|
|
|
|
|
/* binary search */
|
|
|
|
lo = 0; hi = prls->nIntervals - 1;
|
|
|
|
while (lo <= hi)
|
|
|
|
{
|
|
|
|
probe = (hi + lo) / 2;
|
|
|
|
if (pm >= pInterval[probe].first && pm <= pInterval[probe].last) return 1;
|
|
|
|
else if (pm < pInterval[probe].first) hi = probe - 1;
|
|
|
|
else lo = probe + 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static RecordSetIteratePtr
|
|
|
|
IntervalListIterateSet(RecordSetPtr pSet, RecordSetIteratePtr pIter,
|
|
|
|
RecordSetInterval *pIntervalReturn)
|
|
|
|
{
|
|
|
|
RecordSetInterval *pInterval = (RecordSetInterval *)pIter;
|
|
|
|
IntervalListSetPtr prls = (IntervalListSetPtr)pSet;
|
|
|
|
|
|
|
|
if (pInterval == NULL)
|
|
|
|
{
|
|
|
|
pInterval = (RecordSetInterval *)(&prls[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (pInterval - (RecordSetInterval *)(&prls[1])) < prls->nIntervals )
|
|
|
|
{
|
|
|
|
*pIntervalReturn = *pInterval;
|
|
|
|
return (RecordSetIteratePtr)(++pInterval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return (RecordSetIteratePtr)NULL;
|
|
|
|
}
|
|
|
|
|
2007-11-24 10:55:21 -07:00
|
|
|
static RecordSetOperations IntervalListSetOperations = {
|
2006-11-26 11:13:41 -07:00
|
|
|
IntervalListDestroySet, IntervalListIsMemberOfSet, IntervalListIterateSet };
|
|
|
|
|
2007-11-24 10:55:21 -07:00
|
|
|
static RecordSetOperations IntervalListNoFreeOperations = {
|
2006-11-26 11:13:41 -07:00
|
|
|
NoopDestroySet, IntervalListIsMemberOfSet, IntervalListIterateSet };
|
|
|
|
|
|
|
|
static int
|
|
|
|
IntervalListMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals,
|
|
|
|
int maxMember, int *alignment)
|
|
|
|
{
|
|
|
|
*alignment = sizeof(unsigned long);
|
|
|
|
return sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval);
|
|
|
|
}
|
|
|
|
|
|
|
|
static RecordSetPtr
|
|
|
|
IntervalListCreateSet(RecordSetInterval *pIntervals, int nIntervals,
|
|
|
|
void *pMem, int memsize)
|
|
|
|
{
|
|
|
|
IntervalListSetPtr prls;
|
|
|
|
int i, j, k;
|
|
|
|
RecordSetInterval *stackIntervals = NULL;
|
|
|
|
CARD16 first;
|
|
|
|
|
|
|
|
if (nIntervals > 0)
|
|
|
|
{
|
2008-11-02 08:26:08 -07:00
|
|
|
stackIntervals = (RecordSetInterval *)xalloc(
|
2006-11-26 11:13:41 -07:00
|
|
|
sizeof(RecordSetInterval) * nIntervals);
|
|
|
|
if (!stackIntervals) return NULL;
|
|
|
|
|
|
|
|
/* sort intervals, store in stackIntervals (insertion sort) */
|
|
|
|
|
|
|
|
for (i = 0; i < nIntervals; i++)
|
|
|
|
{
|
|
|
|
first = pIntervals[i].first;
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
if (first < stackIntervals[j].first)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (k = i; k > j; k--)
|
|
|
|
{
|
|
|
|
stackIntervals[k] = stackIntervals[k-1];
|
|
|
|
}
|
|
|
|
stackIntervals[j] = pIntervals[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* merge abutting/overlapping intervals */
|
|
|
|
|
|
|
|
for (i = 0; i < nIntervals - 1; )
|
|
|
|
{
|
|
|
|
if ( (stackIntervals[i].last + (unsigned int)1) <
|
|
|
|
stackIntervals[i + 1].first)
|
|
|
|
{
|
|
|
|
i++; /* disjoint intervals */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stackIntervals[i].last = max(stackIntervals[i].last,
|
|
|
|
stackIntervals[i + 1].last);
|
|
|
|
nIntervals--;
|
|
|
|
for (j = i + 1; j < nIntervals; j++)
|
|
|
|
stackIntervals[j] = stackIntervals[j + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate and fill in set structure */
|
|
|
|
|
|
|
|
if (pMem)
|
|
|
|
{
|
|
|
|
prls = (IntervalListSetPtr)pMem;
|
|
|
|
prls->baseSet.ops = &IntervalListNoFreeOperations;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prls = (IntervalListSetPtr)
|
|
|
|
xalloc(sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval));
|
|
|
|
if (!prls) goto bailout;
|
|
|
|
prls->baseSet.ops = &IntervalListSetOperations;
|
|
|
|
}
|
|
|
|
memcpy(&prls[1], stackIntervals, nIntervals * sizeof(RecordSetInterval));
|
|
|
|
prls->nIntervals = nIntervals;
|
|
|
|
bailout:
|
2008-11-02 08:26:08 -07:00
|
|
|
if (stackIntervals) xfree(stackIntervals);
|
2006-11-26 11:13:41 -07:00
|
|
|
return (RecordSetPtr)prls;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef RecordSetPtr (*RecordCreateSetProcPtr)(
|
|
|
|
RecordSetInterval *pIntervals,
|
|
|
|
int nIntervals,
|
|
|
|
void *pMem,
|
|
|
|
int memsize
|
|
|
|
);
|
|
|
|
|
|
|
|
static int
|
|
|
|
_RecordSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals,
|
|
|
|
int *alignment,
|
|
|
|
RecordCreateSetProcPtr *ppCreateSet)
|
|
|
|
{
|
|
|
|
int bmsize, rlsize, bma, rla;
|
|
|
|
int maxMember;
|
|
|
|
|
|
|
|
/* find maximum member of set so we know how big to make the bit vector */
|
|
|
|
maxMember = maxMemberInInterval(pIntervals, nIntervals);
|
|
|
|
|
|
|
|
bmsize = BitVectorSetMemoryRequirements(pIntervals, nIntervals, maxMember,
|
|
|
|
&bma);
|
|
|
|
rlsize = IntervalListMemoryRequirements(pIntervals, nIntervals, maxMember,
|
|
|
|
&rla);
|
|
|
|
if ( ( (nIntervals > 1) && (maxMember <= 255) )
|
|
|
|
|| (bmsize < rlsize) )
|
|
|
|
{
|
|
|
|
*alignment = bma;
|
|
|
|
*ppCreateSet = BitVectorCreateSet;
|
|
|
|
return bmsize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*alignment = rla;
|
|
|
|
*ppCreateSet = IntervalListCreateSet;
|
|
|
|
return rlsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
/* user-visible functions */
|
|
|
|
|
|
|
|
int
|
2010-07-27 13:02:24 -06:00
|
|
|
RecordSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, int *alignment)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
|
|
|
RecordCreateSetProcPtr pCreateSet;
|
|
|
|
return _RecordSetMemoryRequirements(pIntervals, nIntervals, alignment,
|
|
|
|
&pCreateSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
RecordSetPtr
|
2010-07-27 13:02:24 -06:00
|
|
|
RecordCreateSet(RecordSetInterval *pIntervals, int nIntervals, void *pMem, int memsize)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
|
|
|
RecordCreateSetProcPtr pCreateSet;
|
|
|
|
int alignment;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = _RecordSetMemoryRequirements(pIntervals, nIntervals, &alignment,
|
|
|
|
&pCreateSet);
|
|
|
|
if (pMem)
|
|
|
|
{
|
|
|
|
if ( ((long)pMem & (alignment-1) ) || memsize < size)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (*pCreateSet)(pIntervals, nIntervals, pMem, size);
|
|
|
|
}
|