Quarks.c revision 6cc2b21f
1
2/***********************************************************
3Copyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard,
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the name Digital not be
12used in advertising or publicity pertaining to distribution of the
13software without specific, written prior permission.
14
15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
22
23******************************************************************/
24/*
25
26Copyright 1987, 1988, 1990, 1998  The Open Group
27
28Permission to use, copy, modify, distribute, and sell this software and its
29documentation for any purpose is hereby granted without fee, provided that
30the above copyright notice appear in all copies and that both that
31copyright notice and this permission notice appear in supporting
32documentation.
33
34The above copyright notice and this permission notice shall be included
35in all copies or substantial portions of the Software.
36
37THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
41OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
42ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43OTHER DEALINGS IN THE SOFTWARE.
44
45Except as contained in this notice, the name of The Open Group shall
46not be used in advertising or otherwise to promote the sale, use or
47other dealings in this Software without prior written authorization
48from The Open Group.
49
50*/
51
52#ifdef HAVE_CONFIG_H
53#include <config.h>
54#endif
55#include "Xlibint.h"
56#include <X11/Xresource.h>
57#include "Xresinternal.h"
58
59/* Not cost effective, at least for vanilla MIT clients */
60/* #define PERMQ */
61
62#ifdef PERMQ
63typedef unsigned char Bits;
64#endif
65typedef unsigned long Entry; /* dont confuse with EntryRec from Xintatom.h */
66
67static XrmQuark nextQuark = 1;	/* next available quark number */
68static unsigned long quarkMask = 0;
69static Entry zero = 0;
70static Entry *quarkTable = &zero; /* crock */
71static unsigned long quarkRehash;
72static XrmString **stringTable = NULL;
73#ifdef PERMQ
74static Bits **permTable = NULL;
75#endif
76static XrmQuark nextUniq = -1;	/* next quark from XrmUniqueQuark */
77
78#define QUANTUMSHIFT	8
79#define QUANTUMMASK	((1 << QUANTUMSHIFT) - 1)
80#define CHUNKPER	8
81#define CHUNKMASK	((CHUNKPER << QUANTUMSHIFT) - 1)
82
83#define LARGEQUARK	((Entry)0x80000000L)
84#define QUARKSHIFT	18
85#define QUARKMASK	((LARGEQUARK - 1) >> QUARKSHIFT)
86#define XSIGMASK	((1L << QUARKSHIFT) - 1)
87
88#define STRQUANTSIZE	(sizeof(XrmString) * (QUANTUMMASK + 1))
89#ifdef PERMQ
90#define QUANTSIZE	(STRQUANTSIZE + \
91			 (sizeof(Bits) * ((QUANTUMMASK + 1) >> 3))
92#else
93#define QUANTSIZE	STRQUANTSIZE
94#endif
95
96#define HASH(sig) ((sig) & quarkMask)
97#define REHASHVAL(sig) ((((sig) % quarkRehash) + 2) | 1)
98#define REHASH(idx,rehash) ((idx + rehash) & quarkMask)
99#define NAME(q) stringTable[(q) >> QUANTUMSHIFT][(q) & QUANTUMMASK]
100#ifdef PERMQ
101#define BYTEREF(q) permTable[(q) >> QUANTUMSHIFT][((q) & QUANTUMMASK) >> 3]
102#define ISPERM(q) (BYTEREF(q) & (1 << ((q) & 7)))
103#define SETPERM(q) BYTEREF(q) |= (1 << ((q) & 7))
104#define CLEARPERM(q) BYTEREF(q) &= ~(1 << ((q) & 7))
105#endif
106
107/* Permanent memory allocation */
108
109#define WALIGN sizeof(unsigned long)
110#define DALIGN sizeof(double)
111
112#define NEVERFREETABLESIZE ((8192-12) & ~(DALIGN-1))
113static char *neverFreeTable = NULL;
114static int  neverFreeTableSize = 0;
115
116static char *permalloc(unsigned int length)
117{
118    char *ret;
119
120    if (neverFreeTableSize < length) {
121	if (length >= NEVERFREETABLESIZE)
122	    return Xmalloc(length);
123	if (! (ret = Xmalloc(NEVERFREETABLESIZE)))
124	    return (char *) NULL;
125	neverFreeTableSize = NEVERFREETABLESIZE;
126	neverFreeTable = ret;
127    }
128    ret = neverFreeTable;
129    neverFreeTable += length;
130    neverFreeTableSize -= length;
131    return(ret);
132}
133
134#ifndef WORD64
135typedef struct {char a; double b;} TestType1;
136typedef struct {char a; unsigned long b;} TestType2;
137#endif
138
139#ifdef XTHREADS
140static char *_Xpermalloc(unsigned int length);
141
142char *Xpermalloc(unsigned int length)
143{
144    char *p;
145
146    _XLockMutex(_Xglobal_lock);
147    p = _Xpermalloc(length);
148    _XUnlockMutex(_Xglobal_lock);
149    return p;
150}
151#define Xpermalloc _Xpermalloc
152
153static
154#endif /* XTHREADS */
155char *Xpermalloc(unsigned int length)
156{
157    int i;
158
159    if (neverFreeTableSize && length < NEVERFREETABLESIZE) {
160#ifndef WORD64
161	if ((sizeof(TestType1) !=
162	     (sizeof(TestType2) - sizeof(unsigned long) + sizeof(double))) &&
163	    !(length & (DALIGN-1)) &&
164	    ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (DALIGN-1)))) {
165	    neverFreeTableSize -= DALIGN - i;
166	    neverFreeTable += DALIGN - i;
167	} else
168#endif
169	    if ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (WALIGN-1))) {
170		neverFreeTableSize -= WALIGN - i;
171		neverFreeTable += WALIGN - i;
172	    }
173    }
174    return permalloc(length);
175}
176
177static Bool
178ExpandQuarkTable(void)
179{
180    unsigned long oldmask, newmask;
181    register char c, *s;
182    register Entry *oldentries, *entries;
183    register Entry entry;
184    register int oldidx, newidx, rehash;
185    Signature sig;
186    XrmQuark q;
187
188    oldentries = quarkTable;
189    if ((oldmask = quarkMask))
190	newmask = (oldmask << 1) + 1;
191    else {
192	if (!stringTable) {
193	    stringTable = (XrmString **)Xmalloc(sizeof(XrmString *) *
194						CHUNKPER);
195	    if (!stringTable)
196		return False;
197	    stringTable[0] = (XrmString *)NULL;
198	}
199#ifdef PERMQ
200	if (!permTable)
201	    permTable = (Bits **)Xmalloc(sizeof(Bits *) * CHUNKPER);
202	if (!permTable)
203	    return False;
204#endif
205	stringTable[0] = (XrmString *)Xpermalloc(QUANTSIZE);
206	if (!stringTable[0])
207	    return False;
208#ifdef PERMQ
209	permTable[0] = (Bits *)((char *)stringTable[0] + STRQUANTSIZE);
210#endif
211	newmask = 0x1ff;
212    }
213    entries = Xcalloc(newmask + 1, sizeof(Entry));
214    if (!entries)
215	return False;
216    quarkTable = entries;
217    quarkMask = newmask;
218    quarkRehash = quarkMask - 2;
219    for (oldidx = 0; oldidx <= oldmask; oldidx++) {
220	if ((entry = oldentries[oldidx])) {
221	    if (entry & LARGEQUARK)
222		q = entry & (LARGEQUARK-1);
223	    else
224		q = (entry >> QUARKSHIFT) & QUARKMASK;
225	    for (sig = 0, s = NAME(q); (c = *s++); )
226		sig = (sig << 1) + c;
227	    newidx = HASH(sig);
228	    if (entries[newidx]) {
229		rehash = REHASHVAL(sig);
230		do {
231		    newidx = REHASH(newidx, rehash);
232		} while (entries[newidx]);
233	    }
234	    entries[newidx] = entry;
235	}
236    }
237    if (oldmask)
238	Xfree((char *)oldentries);
239    return True;
240}
241
242XrmQuark
243_XrmInternalStringToQuark(
244    register _Xconst char *name, register int len, register Signature sig,
245    Bool permstring)
246{
247    register XrmQuark q;
248    register Entry entry;
249    register int idx, rehash;
250    register int i;
251    register char *s1, *s2;
252    char *new;
253
254    rehash = 0;
255    idx = HASH(sig);
256    _XLockMutex(_Xglobal_lock);
257    while ((entry = quarkTable[idx])) {
258	if (entry & LARGEQUARK)
259	    q = entry & (LARGEQUARK-1);
260	else {
261	    if ((entry - sig) & XSIGMASK)
262		goto nomatch;
263	    q = (entry >> QUARKSHIFT) & QUARKMASK;
264	}
265	for (i = len, s1 = (char *)name, s2 = NAME(q); --i >= 0; ) {
266	    if (*s1++ != *s2++)
267		goto nomatch;
268	}
269	if (*s2) {
270nomatch:    if (!rehash)
271		rehash = REHASHVAL(sig);
272	    idx = REHASH(idx, rehash);
273	    continue;
274	}
275#ifdef PERMQ
276	if (permstring && !ISPERM(q)) {
277	    Xfree(NAME(q));
278	    NAME(q) = (char *)name;
279	    SETPERM(q);
280	}
281#endif
282	_XUnlockMutex(_Xglobal_lock);
283	return q;
284    }
285    if (nextUniq == nextQuark)
286	goto fail;
287    if ((nextQuark + (nextQuark >> 2)) > quarkMask) {
288	if (!ExpandQuarkTable())
289	    goto fail;
290	_XUnlockMutex(_Xglobal_lock);
291	return _XrmInternalStringToQuark(name, len, sig, permstring);
292    }
293    q = nextQuark;
294    if (!(q & QUANTUMMASK)) {
295	if (!(q & CHUNKMASK)) {
296	    if (!(new = Xrealloc((char *)stringTable,
297				 sizeof(XrmString *) *
298				 ((q >> QUANTUMSHIFT) + CHUNKPER))))
299		goto fail;
300	    stringTable = (XrmString **)new;
301#ifdef PERMQ
302	    if (!(new = Xrealloc((char *)permTable,
303				 sizeof(Bits *) *
304				 ((q >> QUANTUMSHIFT) + CHUNKPER))))
305		goto fail;
306	    permTable = (Bits **)new;
307#endif
308	}
309	new = Xpermalloc(QUANTSIZE);
310	if (!new)
311	    goto fail;
312	stringTable[q >> QUANTUMSHIFT] = (XrmString *)new;
313#ifdef PERMQ
314	permTable[q >> QUANTUMSHIFT] = (Bits *)(new + STRQUANTSIZE);
315#endif
316    }
317    if (!permstring) {
318	s2 = (char *)name;
319#ifdef PERMQ
320	name = Xmalloc(len+1);
321#else
322	name = permalloc(len+1);
323#endif
324	if (!name)
325	    goto fail;
326	for (i = len, s1 = (char *)name; --i >= 0; )
327	    *s1++ = *s2++;
328	*s1++ = '\0';
329#ifdef PERMQ
330	CLEARPERM(q);
331    }
332    else {
333	SETPERM(q);
334#endif
335    }
336    NAME(q) = (char *)name;
337    if (q <= QUARKMASK)
338	entry = (q << QUARKSHIFT) | (sig & XSIGMASK);
339    else
340	entry = q | LARGEQUARK;
341    quarkTable[idx] = entry;
342    nextQuark++;
343    _XUnlockMutex(_Xglobal_lock);
344    return q;
345 fail:
346    _XUnlockMutex(_Xglobal_lock);
347    return NULLQUARK;
348}
349
350XrmQuark
351XrmStringToQuark(
352    _Xconst char *name)
353{
354    register char c, *tname;
355    register Signature sig = 0;
356
357    if (!name)
358	return (NULLQUARK);
359
360    for (tname = (char *)name; (c = *tname++); )
361	sig = (sig << 1) + c;
362
363    return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, False);
364}
365
366XrmQuark
367XrmPermStringToQuark(
368    _Xconst char *name)
369{
370    register char c, *tname;
371    register Signature sig = 0;
372
373    if (!name)
374	return (NULLQUARK);
375
376    for (tname = (char *)name; (c = *tname++); )
377	sig = (sig << 1) + c;
378
379    return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, True);
380}
381
382XrmQuark XrmUniqueQuark(void)
383{
384    XrmQuark q;
385
386    _XLockMutex(_Xglobal_lock);
387    if (nextUniq == nextQuark)
388	q = NULLQUARK;
389    else
390	q = nextUniq--;
391    _XUnlockMutex(_Xglobal_lock);
392    return q;
393}
394
395XrmString XrmQuarkToString(register XrmQuark quark)
396{
397    XrmString s;
398
399    _XLockMutex(_Xglobal_lock);
400    if (quark <= 0 || quark >= nextQuark)
401    	s = NULLSTRING;
402    else {
403#ifdef PERMQ
404	/* We have to mark the quark as permanent, since the caller might hold
405	 * onto the string pointer forver.
406	 */
407	SETPERM(quark);
408#endif
409	s = NAME(quark);
410    }
411    _XUnlockMutex(_Xglobal_lock);
412    return s;
413}
414