3 Copyright 1995, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
31 See the header set.h for a description of the set ADT.
33 Implementation Strategy
35 A bit vector is an obvious choice to represent the set, but may take
36 too much memory, depending on the numerically largest member in the
37 set. One expected common case is for the client to ask for *all*
38 protocol. This means it would ask for minor opcodes 0 through 65535.
39 Representing this as a bit vector takes 8K -- and there may be
40 multiple minor opcode intervals, as many as one per major (extension)
41 opcode). In such cases, a list-of-intervals representation would be
42 preferable to reduce memory consumption. Both representations will be
43 implemented, and RecordCreateSet will decide heuristically which one
44 to use based on the set members.
48 #ifdef HAVE_DIX_CONFIG_H
49 #include <dix-config.h>
58 * Ideally we would always use _Alignof(type) here, but that requires C11, so
59 * we approximate this using sizeof(void*) for older C standards as that
60 * should be a valid assumption on all supported architectures.
62 #if defined(__STDC__) && (__STDC_VERSION__ - 0 >= 201112L)
63 #define MinSetAlignment(type) max(_Alignof(type), _Alignof(unsigned long))
65 #define MinSetAlignment(type) max(sizeof(void*), sizeof(unsigned long))
69 maxMemberInInterval(RecordSetInterval
* pIntervals
, int nIntervals
)
74 for (i
= 0; i
< nIntervals
; i
++) {
75 if (maxMember
< (int) pIntervals
[i
].last
)
76 maxMember
= pIntervals
[i
].last
;
82 NoopDestroySet(RecordSetPtr pSet
)
86 /***************************************************************************/
88 /* set operations for bit vector representation */
93 /* followed by the bit vector itself */
94 } BitVectorSet
, *BitVectorSetPtr
;
96 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
99 BitVectorDestroySet(RecordSetPtr pSet
)
105 BitVectorIsMemberOfSet(RecordSetPtr pSet
, int pm
)
107 BitVectorSetPtr pbvs
= (BitVectorSetPtr
) pSet
;
108 unsigned long *pbitvec
;
110 if ((int) pm
> pbvs
->maxMember
)
112 pbitvec
= (unsigned long *) (&pbvs
[1]);
113 return (pbitvec
[pm
/ BITS_PER_LONG
] &
114 ((unsigned long) 1 << (pm
% BITS_PER_LONG
)));
118 BitVectorFindBit(RecordSetPtr pSet
, int iterbit
, Bool bitval
)
120 BitVectorSetPtr pbvs
= (BitVectorSetPtr
) pSet
;
121 unsigned long *pbitvec
= (unsigned long *) (&pbvs
[1]);
126 unsigned long skipval
;
128 unsigned long usefulbits
;
130 startlong
= iterbit
/ BITS_PER_LONG
;
131 pbitvec
+= startlong
;
132 startbit
= startlong
* BITS_PER_LONG
;
133 skipval
= bitval
? 0L : ~0L;
134 maxMember
= pbvs
->maxMember
;
136 if (startbit
> maxMember
)
139 usefulbits
= ~(((unsigned long) 1 << (iterbit
- startbit
)) - 1);
140 if ((bits
& usefulbits
) == (skipval
& usefulbits
)) {
142 startbit
+= BITS_PER_LONG
;
144 while (startbit
<= maxMember
&& *pbitvec
== skipval
) {
146 startbit
+= BITS_PER_LONG
;
148 if (startbit
> maxMember
)
152 walkbit
= (startbit
< iterbit
) ? iterbit
- startbit
: 0;
155 while (walkbit
< BITS_PER_LONG
&&
156 ((!(bits
& ((unsigned long) 1 << walkbit
))) == bitval
))
159 return startbit
+ walkbit
;
162 static RecordSetIteratePtr
163 BitVectorIterateSet(RecordSetPtr pSet
, RecordSetIteratePtr pIter
,
164 RecordSetInterval
* pInterval
)
166 int iterbit
= (int) (long) pIter
;
169 b
= BitVectorFindBit(pSet
, iterbit
, TRUE
);
171 return (RecordSetIteratePtr
) 0;
172 pInterval
->first
= b
;
174 b
= BitVectorFindBit(pSet
, b
, FALSE
);
175 pInterval
->last
= (b
< 0) ? ((BitVectorSetPtr
) pSet
)->maxMember
: b
- 1;
176 return (RecordSetIteratePtr
) (long) (pInterval
->last
+ 1);
179 static RecordSetOperations BitVectorSetOperations
= {
180 BitVectorDestroySet
, BitVectorIsMemberOfSet
, BitVectorIterateSet
183 static RecordSetOperations BitVectorNoFreeOperations
= {
184 NoopDestroySet
, BitVectorIsMemberOfSet
, BitVectorIterateSet
188 BitVectorSetMemoryRequirements(RecordSetInterval
* pIntervals
, int nIntervals
,
189 int maxMember
, int *alignment
)
193 *alignment
= MinSetAlignment(BitVectorSet
);
194 nlongs
= (maxMember
+ BITS_PER_LONG
) / BITS_PER_LONG
;
195 return (sizeof(BitVectorSet
) + nlongs
* sizeof(unsigned long));
199 BitVectorCreateSet(RecordSetInterval
* pIntervals
, int nIntervals
,
200 void *pMem
, int memsize
)
202 BitVectorSetPtr pbvs
;
204 unsigned long *pbitvec
;
206 /* allocate all storage needed by this set in one chunk */
209 memset(pMem
, 0, memsize
);
210 pbvs
= (BitVectorSetPtr
) pMem
;
211 pbvs
->baseSet
.ops
= &BitVectorNoFreeOperations
;
214 pbvs
= (BitVectorSetPtr
) calloc(1, memsize
);
217 pbvs
->baseSet
.ops
= &BitVectorSetOperations
;
220 pbvs
->maxMember
= maxMemberInInterval(pIntervals
, nIntervals
);
222 /* fill in the set */
224 pbitvec
= (unsigned long *) (&pbvs
[1]);
225 for (i
= 0; i
< nIntervals
; i
++) {
226 for (j
= pIntervals
[i
].first
; j
<= (int) pIntervals
[i
].last
; j
++) {
227 pbitvec
[j
/ BITS_PER_LONG
] |=
228 ((unsigned long) 1 << (j
% BITS_PER_LONG
));
231 return (RecordSetPtr
) pbvs
;
234 /***************************************************************************/
236 /* set operations for interval list representation */
239 RecordSetRec baseSet
;
241 /* followed by the intervals (RecordSetInterval) */
242 } IntervalListSet
, *IntervalListSetPtr
;
245 IntervalListDestroySet(RecordSetPtr pSet
)
251 IntervalListIsMemberOfSet(RecordSetPtr pSet
, int pm
)
253 IntervalListSetPtr prls
= (IntervalListSetPtr
) pSet
;
254 RecordSetInterval
*pInterval
= (RecordSetInterval
*) (&prls
[1]);
259 hi
= prls
->nIntervals
- 1;
261 probe
= (hi
+ lo
) / 2;
262 if (pm
>= pInterval
[probe
].first
&& pm
<= pInterval
[probe
].last
)
264 else if (pm
< pInterval
[probe
].first
)
272 static RecordSetIteratePtr
273 IntervalListIterateSet(RecordSetPtr pSet
, RecordSetIteratePtr pIter
,
274 RecordSetInterval
* pIntervalReturn
)
276 RecordSetInterval
*pInterval
= (RecordSetInterval
*) pIter
;
277 IntervalListSetPtr prls
= (IntervalListSetPtr
) pSet
;
279 if (pInterval
== NULL
) {
280 pInterval
= (RecordSetInterval
*) (&prls
[1]);
283 if ((pInterval
- (RecordSetInterval
*) (&prls
[1])) < prls
->nIntervals
) {
284 *pIntervalReturn
= *pInterval
;
285 return (RecordSetIteratePtr
) (++pInterval
);
288 return (RecordSetIteratePtr
) NULL
;
291 static RecordSetOperations IntervalListSetOperations
= {
292 IntervalListDestroySet
, IntervalListIsMemberOfSet
, IntervalListIterateSet
295 static RecordSetOperations IntervalListNoFreeOperations
= {
296 NoopDestroySet
, IntervalListIsMemberOfSet
, IntervalListIterateSet
300 IntervalListMemoryRequirements(RecordSetInterval
* pIntervals
, int nIntervals
,
301 int maxMember
, int *alignment
)
303 *alignment
= MinSetAlignment(IntervalListSet
);
304 return sizeof(IntervalListSet
) + nIntervals
* sizeof(RecordSetInterval
);
308 IntervalListCreateSet(RecordSetInterval
* pIntervals
, int nIntervals
,
309 void *pMem
, int memsize
)
311 IntervalListSetPtr prls
;
313 RecordSetInterval
*stackIntervals
= NULL
;
316 if (nIntervals
> 0) {
317 stackIntervals
= xallocarray(nIntervals
, sizeof(RecordSetInterval
));
321 /* sort intervals, store in stackIntervals (insertion sort) */
323 for (i
= 0; i
< nIntervals
; i
++) {
324 first
= pIntervals
[i
].first
;
325 for (j
= 0; j
< i
; j
++) {
326 if (first
< stackIntervals
[j
].first
)
329 for (k
= i
; k
> j
; k
--) {
330 stackIntervals
[k
] = stackIntervals
[k
- 1];
332 stackIntervals
[j
] = pIntervals
[i
];
335 /* merge abutting/overlapping intervals */
337 for (i
= 0; i
< nIntervals
- 1;) {
338 if ((stackIntervals
[i
].last
+ (unsigned int) 1) <
339 stackIntervals
[i
+ 1].first
) {
340 i
++; /* disjoint intervals */
343 stackIntervals
[i
].last
= max(stackIntervals
[i
].last
,
344 stackIntervals
[i
+ 1].last
);
346 for (j
= i
+ 1; j
< nIntervals
; j
++)
347 stackIntervals
[j
] = stackIntervals
[j
+ 1];
352 /* allocate and fill in set structure */
355 prls
= (IntervalListSetPtr
) pMem
;
356 prls
->baseSet
.ops
= &IntervalListNoFreeOperations
;
359 prls
= (IntervalListSetPtr
)
360 malloc(sizeof(IntervalListSet
) +
361 nIntervals
* sizeof(RecordSetInterval
));
364 prls
->baseSet
.ops
= &IntervalListSetOperations
;
366 memcpy(&prls
[1], stackIntervals
, nIntervals
* sizeof(RecordSetInterval
));
367 prls
->nIntervals
= nIntervals
;
369 free(stackIntervals
);
370 return (RecordSetPtr
) prls
;
373 typedef RecordSetPtr(*RecordCreateSetProcPtr
) (RecordSetInterval
* pIntervals
,
375 void *pMem
, int memsize
);
378 _RecordSetMemoryRequirements(RecordSetInterval
* pIntervals
, int nIntervals
,
380 RecordCreateSetProcPtr
* ppCreateSet
)
382 int bmsize
, rlsize
, bma
, rla
;
385 /* find maximum member of set so we know how big to make the bit vector */
386 maxMember
= maxMemberInInterval(pIntervals
, nIntervals
);
388 bmsize
= BitVectorSetMemoryRequirements(pIntervals
, nIntervals
, maxMember
,
390 rlsize
= IntervalListMemoryRequirements(pIntervals
, nIntervals
, maxMember
,
392 if (((nIntervals
> 1) && (maxMember
<= 255))
393 || (bmsize
< rlsize
)) {
395 *ppCreateSet
= BitVectorCreateSet
;
400 *ppCreateSet
= IntervalListCreateSet
;
405 /***************************************************************************/
407 /* user-visible functions */
410 RecordSetMemoryRequirements(RecordSetInterval
* pIntervals
, int nIntervals
,
413 RecordCreateSetProcPtr pCreateSet
;
415 return _RecordSetMemoryRequirements(pIntervals
, nIntervals
, alignment
,
420 RecordCreateSet(RecordSetInterval
* pIntervals
, int nIntervals
, void *pMem
,
423 RecordCreateSetProcPtr pCreateSet
;
427 size
= _RecordSetMemoryRequirements(pIntervals
, nIntervals
, &alignment
,
430 if (((long) pMem
& (alignment
- 1)) || memsize
< size
)
433 return (*pCreateSet
) (pIntervals
, nIntervals
, pMem
, size
);