]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-sel-set.mm
objc4-818.2.tar.gz
[apple/objc4.git] / runtime / objc-sel-set.mm
CommitLineData
2bfd4448 1/*
7af964d1 2 * Copyright (c) 1999-2004,2008 Apple Inc. All rights reserved.
2bfd4448
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
2bfd4448
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * objc-sel-set.h
26 * A cut-down copy of CFSet used for SEL uniquing.
27 */
28
29
30// NOTE: even on a 64-bit system, the implementation is still limited
31// to 32-bit integers (like, the count), but SEL can be any size.
32
33#include <stdint.h>
7af964d1
A
34#include "objc-private.h"
35#include "objc-sel-set.h"
2bfd4448 36
8070259c
A
37#if !__OBJC2__
38
39
8972963c 40#if !SUPPORT_MOD
7af964d1
A
41// mod-free power of 2 version
42
43#define CONSTRAIN(val, range) ((val) & ((range)-1))
44#define SIZE 27
45
46static const uint32_t __objc_sel_set_capacities[SIZE+1] = {
cd5f04f5
A
47 3, 6, 12, 24, 48, 96, 192, 384, 768, 1536, 3072, 6144, 12288, 24576,
48 49152, 98304, 196608, 393216, 786432, 1572864, 3145728, 6291456,
49 12582912, 25165824, 50331648, 100663296, 201326592, UINT32_MAX
7af964d1
A
50};
51
52static const uint32_t __objc_sel_set_buckets[SIZE] = { // powers of 2
cd5f04f5
A
53 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
54 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
55 16777216, 33554432, 67108864, 134217728, 268435456
7af964d1
A
56};
57
58#else
59// prime version
60
61#define CONSTRAIN(val, range) ((val) % (range))
62#define SIZE 42
63
64static const uint32_t __objc_sel_set_capacities[SIZE+1] = {
cd5f04f5
A
65 4, 8, 17, 29, 47, 76, 123, 199, 322, 521, 843, 1364, 2207, 3571,
66 5778, 9349, 15127, 24476, 39603, 64079, 103682, 167761, 271443,
67 439204, 710647, 1149851, 1860498, 3010349, 4870847, 7881196, 12752043,
68 20633239, 33385282, 54018521, 87403803, 141422324, 228826127, 370248451,
69 599074578, 969323029, 1568397607, 2537720636U, UINT32_MAX
2bfd4448
A
70};
71
7af964d1 72static const uint32_t __objc_sel_set_buckets[SIZE] = { // primes
cd5f04f5
A
73 5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779,
74 9349, 15121, 24473, 39607, 64081, 103681, 167759, 271429, 439199,
75 710641, 1149857, 1860503, 3010349, 4870843, 7881193, 12752029, 20633237,
76 33385273, 54018521, 87403763, 141422317, 228826121, 370248451, 599074561,
77 969323023, 1568397599, 2537720629U, 4106118251U
2bfd4448
A
78};
79
7af964d1
A
80#endif
81
2bfd4448
A
82struct __objc_sel_set {
83 uint32_t _count; /* number of slots used */
84 uint32_t _capacity; /* maximum number of used slots */
85 uint32_t _bucketsNum; /* number of slots */
86 SEL *_buckets; /* can be NULL if not allocated yet */
87};
88
89struct __objc_sel_set_finds {
90 SEL match;
91 uint32_t nomatch;
92};
93
94// candidate may not be 0; match is 0 if not present
95static struct __objc_sel_set_finds __objc_sel_set_findBuckets(struct __objc_sel_set *sset, SEL candidate) {
96 struct __objc_sel_set_finds ret = {0, 0xffffffff};
7af964d1 97 uint32_t probe = CONSTRAIN((uint32_t)_objc_strhash((const char *)candidate), sset->_bucketsNum);
2bfd4448
A
98 for (;;) {
99 SEL currentSel = sset->_buckets[probe];
100 if (!currentSel) {
101 ret.nomatch = probe;
102 return ret;
8972963c 103 } else if (!ret.match && 0 == strcmp((const char *)currentSel, (const char *)candidate)) {
2bfd4448
A
104 ret.match = currentSel;
105 }
106 probe++;
107 if (sset->_bucketsNum <= probe) {
108 probe -= sset->_bucketsNum;
109 }
110 }
111}
112
113// create a set with given starting capacity, will resize as needed
cd5f04f5 114struct __objc_sel_set *__objc_sel_set_create(size_t selrefs) {
7af964d1
A
115 uint32_t idx;
116
cd5f04f5 117 struct __objc_sel_set *sset = (struct __objc_sel_set *)
31875a97 118 malloc(sizeof(struct __objc_sel_set));
2bfd4448
A
119 if (!sset) _objc_fatal("objc_sel_set failure");
120 sset->_count = 0;
7af964d1 121
cd5f04f5 122 // heuristic to convert executable's selrefs count to table size
34d5b5e8 123#if TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST
cd5f04f5
A
124 for (idx = 0; __objc_sel_set_capacities[idx] < selrefs; idx++);
125 if (idx > 0 && selrefs < 1536) idx--;
126#else
127 if (selrefs < 1024) selrefs = 1024;
128 for (idx = 0; __objc_sel_set_capacities[idx] < selrefs; idx++);
129 idx++;
130#endif
131
7af964d1 132 if (SIZE <= idx) _objc_fatal("objc_sel_set failure");
2bfd4448
A
133 sset->_capacity = __objc_sel_set_capacities[idx];
134 sset->_bucketsNum = __objc_sel_set_buckets[idx];
31875a97 135 sset->_buckets = (SEL *)calloc(sset->_bucketsNum, sizeof(SEL));
2bfd4448
A
136 if (!sset->_buckets) _objc_fatal("objc_sel_set failure");
137 return sset;
138}
139
140// returns 0 on failure; candidate may not be 0
cd5f04f5 141SEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate) {
2bfd4448
A
142 return __objc_sel_set_findBuckets(sset, candidate).match;
143}
144
145// value may not be 0; should not be called unless it is known the value is not in the set
cd5f04f5 146void __objc_sel_set_add(struct __objc_sel_set *sset, SEL value) {
2bfd4448
A
147 if (sset->_count == sset->_capacity) {
148 SEL *oldbuckets = sset->_buckets;
149 uint32_t oldnbuckets = sset->_bucketsNum;
150 uint32_t idx, capacity = sset->_count + 1;
151 for (idx = 0; __objc_sel_set_capacities[idx] < capacity; idx++);
7af964d1 152 if (SIZE <= idx) _objc_fatal("objc_sel_set failure");
2bfd4448
A
153 sset->_capacity = __objc_sel_set_capacities[idx];
154 sset->_bucketsNum = __objc_sel_set_buckets[idx];
cd5f04f5 155 sset->_buckets = (SEL *)
31875a97 156 calloc(sset->_bucketsNum, sizeof(SEL));
2bfd4448
A
157 if (!sset->_buckets) _objc_fatal("objc_sel_set failure");
158 for (idx = 0; idx < oldnbuckets; idx++) {
159 SEL currentSel = oldbuckets[idx];
160 if (currentSel) {
161 uint32_t nomatch = __objc_sel_set_findBuckets(sset, currentSel).nomatch;
162 sset->_buckets[nomatch] = currentSel;
163 }
164 }
31875a97 165 free(oldbuckets);
2bfd4448 166 }
7af964d1
A
167 {
168 uint32_t nomatch = __objc_sel_set_findBuckets(sset, value).nomatch;
169 sset->_buckets[nomatch] = value;
170 sset->_count++;
171 }
2bfd4448 172}
8070259c
A
173
174
175// !__OBJC2__
176#endif