xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/objc/objc-map.h (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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