136ac495dSmrg /* objc-map.h -- Implementation of map data structures for ObjC compiler
2*8feb0f0bSmrg Copyright (C) 2011-2020 Free Software Foundation, Inc.
336ac495dSmrg Written by Nicola Pero <nicola.pero@meta-innovation.com>
436ac495dSmrg
536ac495dSmrg This program is free software; you can redistribute it and/or modify it
636ac495dSmrg under the terms of the GNU Lesser Public License as published by the
736ac495dSmrg Free Software Foundation; either version 3, or (at your option) any
836ac495dSmrg later version.
936ac495dSmrg
1036ac495dSmrg This program is distributed in the hope that it will be useful,
1136ac495dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1236ac495dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1336ac495dSmrg GNU Lesser Public License for more details.
1436ac495dSmrg
1536ac495dSmrg You should have received a copy of the GNU Lesser Public License
1636ac495dSmrg along with this program; if not, write to the Free Software
1736ac495dSmrg Foundation, 51 Franklin Street - Fifth Floor,
1836ac495dSmrg Boston, MA 02110-1301, USA. */
1936ac495dSmrg
2036ac495dSmrg #ifndef OBJC_MAP_H
2136ac495dSmrg #define OBJC_MAP_H
2236ac495dSmrg
2336ac495dSmrg /* A map is a data structure that maps a key to a value. In this file
2436ac495dSmrg we currently have maps that can map a GCC identifier (a tree) to
2536ac495dSmrg some other GCC tree. This is what the ObjC frontend mostly needs:
2636ac495dSmrg being able to look up an identifier into an ObjC data structure. A
2736ac495dSmrg typical usage is mapping ObjC class names (as identifiers) to a
2836ac495dSmrg tree representing the class.
2936ac495dSmrg
3036ac495dSmrg This implementation is fast. :-) */
3136ac495dSmrg
3236ac495dSmrg /**
3336ac495dSmrg ** Private definitions.
3436ac495dSmrg **/
3536ac495dSmrg
3636ac495dSmrg /* We include private declaration and definitions that are required to
3736ac495dSmrg provide the implementation of inline functions. You should ignore
3836ac495dSmrg these definitions (and the implementation of the inline functions)
3936ac495dSmrg as they are not part of the public API and may change. */
4036ac495dSmrg typedef unsigned int objc_map_private_hash_t;
4136ac495dSmrg
4236ac495dSmrg /* This is used as sentinel. */
4336ac495dSmrg #define OBJC_MAP_PRIVATE_EMPTY_SLOT (tree)0
4436ac495dSmrg
4536ac495dSmrg struct GTY(()) objc_map_private {
4636ac495dSmrg /* Total number of slots. This is the maximum number of elements
4736ac495dSmrg that can be currently stored in the map before resizing. This is
4836ac495dSmrg the number of slots in the C array. Important: this is
4936ac495dSmrg guaranteed to be a power of 2. When we create (or resize) the
5036ac495dSmrg map, we round up the size to the next power of 2. This allows us
5136ac495dSmrg to convert a hash to a position in the hashtable by simply doing
5236ac495dSmrg "position = hash & mask", where mask is number_of_slots - 1
5336ac495dSmrg instead of using a modulo (which requires a division). */
5436ac495dSmrg size_t number_of_slots;
5536ac495dSmrg
5636ac495dSmrg /* This is number_of_slots - 1, precomputed. */
5736ac495dSmrg size_t mask;
5836ac495dSmrg
5936ac495dSmrg /* Number of slots that are not empty (ie, that are active). We
6036ac495dSmrg keep counts using this variable which can easily be checked
6136ac495dSmrg against max_number_of_non_empty_slots. */
6236ac495dSmrg size_t number_of_non_empty_slots;
6336ac495dSmrg
6436ac495dSmrg /* This is the load factor limit. When the number of non empty
6536ac495dSmrg slots equals this number, we need to resize the array. This is
6636ac495dSmrg calculated once, when the slots are resized, and then kept cached
6736ac495dSmrg so it can be compared quickly when elements are added. */
6836ac495dSmrg size_t max_number_of_non_empty_slots;
6936ac495dSmrg
7036ac495dSmrg /* The maximum load factor. */
7136ac495dSmrg int maximum_load_factor;
7236ac495dSmrg
7336ac495dSmrg /* These are the keys. */
7436ac495dSmrg tree * GTY ((length ("%h.number_of_slots"))) slots;
7536ac495dSmrg
7636ac495dSmrg /* These are the values. values[i] is the value corresponding
7736ac495dSmrg to slots[i]. */
7836ac495dSmrg tree * GTY ((length ("%h.number_of_slots"))) values;
7936ac495dSmrg };
8036ac495dSmrg
8136ac495dSmrg /* Private functions used to resize the map. They may be called by
8236ac495dSmrg the inline functions when adding elements. */
8336ac495dSmrg extern void
8436ac495dSmrg objc_map_private_grow (struct objc_map_private *map);
8536ac495dSmrg
8636ac495dSmrg
8736ac495dSmrg /**
8836ac495dSmrg ** The definition of a map.
8936ac495dSmrg **/
9036ac495dSmrg typedef struct objc_map_private *objc_map_t;
9136ac495dSmrg
9236ac495dSmrg
9336ac495dSmrg /**
9436ac495dSmrg ** Creating a map.
9536ac495dSmrg **/
9636ac495dSmrg
9736ac495dSmrg /* objc_map_alloc_ggc() creates a new map which is under GGC. The initial
9836ac495dSmrg capacity must be specified as an argument; this is used to size the map
9936ac495dSmrg when it is created. */
10036ac495dSmrg objc_map_t objc_map_alloc_ggc (size_t initial_capacity);
10136ac495dSmrg
10236ac495dSmrg /**
10336ac495dSmrg ** Performance tuning.
10436ac495dSmrg **/
10536ac495dSmrg
10636ac495dSmrg /* Set a maximum load factor for the data structure. This is the main
10736ac495dSmrg tuning parameter to improve performance (at the expense of
10836ac495dSmrg memory). */
10936ac495dSmrg void objc_map_set_maximum_load_factor (objc_map_t map, int number_between_zero_and_one_hundred);
11036ac495dSmrg
11136ac495dSmrg /* Read the maximum load factor. */
11236ac495dSmrg int objc_map_maximum_load_factor (objc_map_t map);
11336ac495dSmrg
11436ac495dSmrg
11536ac495dSmrg /**
11636ac495dSmrg ** Getting the value corresponding to a key.
11736ac495dSmrg **/
11836ac495dSmrg
11936ac495dSmrg /* This is the value returned by objc_map_get() when the value
12036ac495dSmrg corresponding to a key is not found. */
12136ac495dSmrg #define OBJC_MAP_NOT_FOUND (tree)1
12236ac495dSmrg
12336ac495dSmrg /* objc_map_get() returns the value associated with a certain key,
12436ac495dSmrg or OBJC_MAP_NOT_FOUND if there is no value associated with that key.
12536ac495dSmrg Note that you can also use it to simply check if the map contains a
12636ac495dSmrg pair with a certain key; just compare the result of calling
12736ac495dSmrg objc_map_get() to OBJC_MAP_NOT_FOUND.
12836ac495dSmrg
12936ac495dSmrg It is essential to always check the results of the call to make
13036ac495dSmrg sure it is not OBJC_MAP_NOT_FOUND.
13136ac495dSmrg
13236ac495dSmrg NULL is a valid value, so a key can be inserted into a map with
13336ac495dSmrg value NULL, and objc_map_get() will return NULL in that case.
13436ac495dSmrg So a result of NULL means that they key *was* found, and the value
13536ac495dSmrg associated with it was NULL. */
13636ac495dSmrg static inline tree
objc_map_get(objc_map_t map,tree key)13736ac495dSmrg objc_map_get (objc_map_t map, /* struct tree_identifier * */tree key)
13836ac495dSmrg {
13936ac495dSmrg /* The inline implementation is private and may change without notice. */
14036ac495dSmrg objc_map_private_hash_t hash = IDENTIFIER_HASH_VALUE (key);
14136ac495dSmrg size_t i = hash & map->mask;
14236ac495dSmrg size_t j = 1;
14336ac495dSmrg
14436ac495dSmrg if (map->slots[i] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
14536ac495dSmrg return OBJC_MAP_NOT_FOUND;
14636ac495dSmrg
14736ac495dSmrg if (map->slots[i] == key)
14836ac495dSmrg return map->values[i];
14936ac495dSmrg
15036ac495dSmrg while (1)
15136ac495dSmrg {
15236ac495dSmrg i = (i + j) & map->mask;
15336ac495dSmrg
15436ac495dSmrg if (map->slots[i] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
15536ac495dSmrg return OBJC_MAP_NOT_FOUND;
15636ac495dSmrg
15736ac495dSmrg if (map->slots[i] == key)
15836ac495dSmrg return map->values[i];
15936ac495dSmrg
16036ac495dSmrg j++;
16136ac495dSmrg }
16236ac495dSmrg }
16336ac495dSmrg
16436ac495dSmrg /* objc_map_put() puts a key/value pair into the map. If the map does
16536ac495dSmrg not contain the key, it is added to it with the specified value.
16636ac495dSmrg If the map already contains the key, the previous value is replaced
16736ac495dSmrg with the new one.
16836ac495dSmrg
16936ac495dSmrg You can use any identifier as key, with the exception of NULL.
17036ac495dSmrg
17136ac495dSmrg You can use any tree as value, including NULL. */
17236ac495dSmrg static inline
objc_map_put(objc_map_t map,tree key,tree value)17336ac495dSmrg void objc_map_put (objc_map_t map, /*struct tree_identifier * */tree key, tree value)
17436ac495dSmrg {
17536ac495dSmrg /* The inline implementation is private and may change without notice. */
17636ac495dSmrg objc_map_private_hash_t hash = IDENTIFIER_HASH_VALUE (key);
17736ac495dSmrg size_t i, j = 0;
17836ac495dSmrg
17936ac495dSmrg if (map->number_of_non_empty_slots == map->max_number_of_non_empty_slots)
18036ac495dSmrg objc_map_private_grow (map);
18136ac495dSmrg
18236ac495dSmrg i = hash & map->mask;
18336ac495dSmrg
18436ac495dSmrg while (1)
18536ac495dSmrg {
18636ac495dSmrg if (map->slots[i] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
18736ac495dSmrg {
18836ac495dSmrg map->number_of_non_empty_slots++;
18936ac495dSmrg map->slots[i] = key;
19036ac495dSmrg map->values[i] = value;
19136ac495dSmrg return;
19236ac495dSmrg }
19336ac495dSmrg if (map->slots[i] == key)
19436ac495dSmrg {
19536ac495dSmrg map->values[i] = value;
19636ac495dSmrg return;
19736ac495dSmrg }
19836ac495dSmrg
19936ac495dSmrg j++;
20036ac495dSmrg i = (i + j) & map->mask;
20136ac495dSmrg }
20236ac495dSmrg }
20336ac495dSmrg
20436ac495dSmrg /**
20536ac495dSmrg ** Iterating over a map using an iterator.
20636ac495dSmrg **/
20736ac495dSmrg
20836ac495dSmrg /* When using iterators you can iterate directly on the elements in
20936ac495dSmrg the map, and take an action over each one.
21036ac495dSmrg
21136ac495dSmrg Here is how you iterate over a hmap_pointer using iterators:
21236ac495dSmrg
21336ac495dSmrg objc_map_iterator_t i;
21436ac495dSmrg
21536ac495dSmrg objc_map_iterator_initialize (map, &i);
21636ac495dSmrg
21736ac495dSmrg while (objc_map_iterator_move_to_next (map, &i))
21836ac495dSmrg {
21936ac495dSmrg tree p = objc_map_iterator_current_key (map, i);
22036ac495dSmrg tree q = objc_map_iterator_current_value (map, i);
22136ac495dSmrg
22236ac495dSmrg ... do something with p and q ...
22336ac495dSmrg }
22436ac495dSmrg
22536ac495dSmrg You'll notice that the functions that modify the iterator (to
22636ac495dSmrg initialize it, or move it to the next element) take a pointer to it
22736ac495dSmrg as argument (as in "&i"), while the functions that only read its
22836ac495dSmrg state (to read the current key/value, or remove the current
22936ac495dSmrg key/value from the map) take it as a direct argument (as in "i").
23036ac495dSmrg
23136ac495dSmrg Note that all the objc_map_iterator_*() functions are inline and if
23236ac495dSmrg you follow the pattern above, the compiler should be able to inline
23336ac495dSmrg everything into a very efficient loop, roughly equivalent to
23436ac495dSmrg hand-writing a C loop that iterates directly onto the hmap_pointer
23536ac495dSmrg internal data structures. */
23636ac495dSmrg
23736ac495dSmrg /* A objc_map_iterator_t variable encapsulates the state of an
23836ac495dSmrg iteration. The fact that this is actually a size_t (pointing to
23936ac495dSmrg the index of the slot that we return next) is an internal, private
24036ac495dSmrg detail of the implementation and may change without notice. */
24136ac495dSmrg typedef size_t objc_map_iterator_t;
24236ac495dSmrg
24336ac495dSmrg /* Initialize an iterator to iterate over the specified objc_map. You
24436ac495dSmrg must use this before starting the iteration, to get a working
24536ac495dSmrg iterator. */
24636ac495dSmrg static inline
24736ac495dSmrg void
objc_map_iterator_initialize(objc_map_t map ATTRIBUTE_UNUSED,objc_map_iterator_t * i)24836ac495dSmrg objc_map_iterator_initialize (objc_map_t map ATTRIBUTE_UNUSED, objc_map_iterator_t *i)
24936ac495dSmrg {
25036ac495dSmrg /* The inline implementation is private and may change without notice. */
25136ac495dSmrg /* This is trivial, but the same API would work to initialize more
25236ac495dSmrg complicated iterators. */
25336ac495dSmrg *i = 0;
25436ac495dSmrg }
25536ac495dSmrg
25636ac495dSmrg #define OBJC_MAP_FAILURE 0
25736ac495dSmrg #define OBJC_MAP_SUCCESS 1
25836ac495dSmrg
25936ac495dSmrg /* Move the iterator to the next key/value pair, and return
26036ac495dSmrg OBJC_MAP_SUCCESS if there is such a key/value pair, and
26136ac495dSmrg OBJC_MAP_FAILURE if there are no more ones. The iterator must have
26236ac495dSmrg been initialized using objc_map_iterator_initialize(). Note that
26336ac495dSmrg because this function is modifying the iterator, you need to pass a
26436ac495dSmrg pointer to it. */
26536ac495dSmrg static inline
26636ac495dSmrg int
objc_map_iterator_move_to_next(objc_map_t map,objc_map_iterator_t * i)26736ac495dSmrg objc_map_iterator_move_to_next (objc_map_t map, objc_map_iterator_t *i)
26836ac495dSmrg {
26936ac495dSmrg /* The inline implementation is private and may change without notice. */
27036ac495dSmrg while (1)
27136ac495dSmrg {
27236ac495dSmrg void *slot;
27336ac495dSmrg if (*i == map->number_of_slots)
27436ac495dSmrg return OBJC_MAP_FAILURE;
27536ac495dSmrg
27636ac495dSmrg slot = map->slots[*i];
27736ac495dSmrg *i = *i + 1;
27836ac495dSmrg if (slot != OBJC_MAP_PRIVATE_EMPTY_SLOT)
27936ac495dSmrg return OBJC_MAP_SUCCESS;
28036ac495dSmrg }
28136ac495dSmrg }
28236ac495dSmrg
28336ac495dSmrg /* Return the current key. You can only call it after you have called
28436ac495dSmrg objc_map_iterator_move_to_next() at least once (to move to the
28536ac495dSmrg first element), and only if the last call returned
28636ac495dSmrg OBJC_MAP_SUCCESS. The behavior is otherwise undefined, probably a
28736ac495dSmrg segmentation fault. */
28836ac495dSmrg static inline
28936ac495dSmrg tree
objc_map_iterator_current_key(objc_map_t map,objc_map_iterator_t i)29036ac495dSmrg objc_map_iterator_current_key (objc_map_t map, objc_map_iterator_t i)
29136ac495dSmrg {
29236ac495dSmrg /* The inline implementation is private and may change without notice. */
29336ac495dSmrg return map->slots[i - 1];
29436ac495dSmrg }
29536ac495dSmrg
29636ac495dSmrg /* Return the current value. You can only call it after you have
29736ac495dSmrg called objc_map_iterator_move_to_next() at least once (to move to
29836ac495dSmrg the first element), and only if the last call returned
29936ac495dSmrg OBJC_MAP_SUCCESS. The behavior is otherwise undefined, probably a
30036ac495dSmrg segmentation fault. */
30136ac495dSmrg static inline
30236ac495dSmrg tree
objc_map_iterator_current_value(objc_map_t map,objc_map_iterator_t i)30336ac495dSmrg objc_map_iterator_current_value (objc_map_t map, objc_map_iterator_t i)
30436ac495dSmrg {
30536ac495dSmrg /* The inline implementation is private and may change without notice. */
30636ac495dSmrg return map->values[i - 1];
30736ac495dSmrg }
30836ac495dSmrg
30936ac495dSmrg #endif /* OBJC_MAP_H */
310