1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 /***********************************************************************
15    idex = ident index: a lookup table for quick mapping of unit and city
16    id values to unit and city pointers.
17 
18    Method: use separate hash tables for each type.
19    Means code duplication for city/unit cases, but simplicity advantages.
20    Don't have to manage memory at all: store pointers to unit and city
21    structs allocated elsewhere, and keys are pointers to id values inside
22    the structs.
23 
24    Note id values should probably be unsigned int: here leave as plain int
25    so can use pointers to pcity->id etc.
26 ***********************************************************************/
27 
28 #ifdef HAVE_CONFIG_H
29 #include <fc_config.h>
30 #endif
31 
32 /* utility */
33 #include "log.h"
34 
35 /* common */
36 #include "city.h"
37 #include "unit.h"
38 
39 #include "idex.h"
40 
41 
42 /* struct city_hash. */
43 #define SPECHASH_TAG city
44 #define SPECHASH_INT_KEY_TYPE
45 #define SPECHASH_IDATA_TYPE struct city *
46 #include "spechash.h"
47 
48 /* struct unit_hash. */
49 #define SPECHASH_TAG unit
50 #define SPECHASH_INT_KEY_TYPE
51 #define SPECHASH_IDATA_TYPE struct unit *
52 #include "spechash.h"
53 
54 
55 /* "Global" data: */
56 static struct city_hash *idex_city_hash = NULL;
57 static struct unit_hash *idex_unit_hash = NULL;
58 
59 /**************************************************************************
60    Initialize.  Should call this at the start before use.
61 ***************************************************************************/
idex_init(void)62 void idex_init(void)
63 {
64   fc_assert_ret(idex_city_hash == NULL);
65   fc_assert_ret(idex_unit_hash == NULL);
66 
67   idex_city_hash = city_hash_new();
68   idex_unit_hash = unit_hash_new();
69 }
70 
71 /**************************************************************************
72    Free the hashs.
73 ***************************************************************************/
idex_free(void)74 void idex_free(void)
75 {
76   city_hash_destroy(idex_city_hash);
77   idex_city_hash = NULL;
78 
79   unit_hash_destroy(idex_unit_hash);
80   idex_unit_hash = NULL;
81 }
82 
83 /**************************************************************************
84    Register a city into idex, with current pcity->id.
85    Call this when pcity created.
86 ***************************************************************************/
idex_register_city(struct city * pcity)87 void idex_register_city(struct city *pcity)
88 {
89   struct city *old;
90 
91   city_hash_replace_full(idex_city_hash, pcity->id, pcity, NULL, &old);
92   fc_assert_ret_msg(NULL == old,
93                     "IDEX: city collision: new %d %p %s, old %d %p %s",
94                     pcity->id, (void *) pcity, city_name_get(pcity),
95                     old->id, (void *) old, city_name_get(old));
96 }
97 
98 /**************************************************************************
99    Register a unit into idex, with current punit->id.
100    Call this when punit created.
101 ***************************************************************************/
idex_register_unit(struct unit * punit)102 void idex_register_unit(struct unit *punit)
103 {
104   struct unit *old;
105 
106   unit_hash_replace_full(idex_unit_hash, punit->id, punit, NULL, &old);
107   fc_assert_ret_msg(NULL == old,
108                     "IDEX: unit collision: new %d %p %s, old %d %p %s",
109                     punit->id, (void *) punit, unit_rule_name(punit),
110                     old->id, (void *) old, unit_rule_name(old));
111 }
112 
113 /**************************************************************************
114    Remove a city from idex, with current pcity->id.
115    Call this when pcity deleted.
116 ***************************************************************************/
idex_unregister_city(struct city * pcity)117 void idex_unregister_city(struct city *pcity)
118 {
119   struct city *old;
120 
121   city_hash_remove_full(idex_city_hash, pcity->id, NULL, &old);
122   fc_assert_ret_msg(NULL != old,
123                     "IDEX: city unreg missing: %d %p %s",
124                     pcity->id, (void *) pcity, city_name_get(pcity));
125   fc_assert_ret_msg(old == pcity, "IDEX: city unreg mismatch: "
126                     "unreg %d %p %s, old %d %p %s",
127                     pcity->id, (void *) pcity, city_name_get(pcity),
128                     old->id, (void *) old, city_name_get(old));
129 }
130 
131 /**************************************************************************
132    Remove a unit from idex, with current punit->id.
133    Call this when punit deleted.
134 ***************************************************************************/
idex_unregister_unit(struct unit * punit)135 void idex_unregister_unit(struct unit *punit)
136 {
137   struct unit *old;
138 
139   unit_hash_remove_full(idex_unit_hash, punit->id, NULL, &old);
140   fc_assert_ret_msg(NULL != old,
141                     "IDEX: unit unreg missing: %d %p %s",
142                     punit->id, (void *) punit, unit_rule_name(punit));
143   fc_assert_ret_msg(old == punit, "IDEX: unit unreg mismatch: "
144                     "unreg %d %p %s, old %d %p %s",
145                     punit->id, (void *) punit, unit_rule_name(punit),
146                     old->id, (void*) old, unit_rule_name(old));
147 }
148 
149 /**************************************************************************
150    Lookup city with given id.
151    Returns NULL if the city is not registered (which is not an error).
152 ***************************************************************************/
idex_lookup_city(int id)153 struct city *idex_lookup_city(int id)
154 {
155   struct city *pcity;
156 
157   city_hash_lookup(idex_city_hash, id, &pcity);
158   return pcity;
159 }
160 
161 /**************************************************************************
162    Lookup unit with given id.
163    Returns NULL if the unit is not registered (which is not an error).
164 ***************************************************************************/
idex_lookup_unit(int id)165 struct unit *idex_lookup_unit(int id)
166 {
167   struct unit *punit;
168 
169   unit_hash_lookup(idex_unit_hash, id, &punit);
170   return punit;
171 }
172