uncrustify as demanded.
[oweals/gnunet.git] / src / rps / gnunet-service-rps_view.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C)
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file rps/gnunet-service-rps_view.c
23  * @brief wrapper around the "local view"
24  * @author Julius Bünger
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-rps_view.h"
29 #include <inttypes.h>
30
31 struct View {
32   /**
33    * Array containing the peers
34    */
35   struct GNUNET_PeerIdentity *array;
36
37   /**
38    * (Maximum) length of the view
39    */
40   uint32_t length;
41
42   /**
43    * Multipeermap containing the peers
44    */
45   struct GNUNET_CONTAINER_MultiPeerMap *mpm;
46 };
47
48
49 /**
50  * Create an empty view.
51  *
52  * @param len the maximum length for the view
53  * @return The newly created view
54  */
55 struct View *
56 View_create(uint32_t len)
57 {
58   struct View *view;
59
60   view = GNUNET_new(struct View);
61   view->length = len;
62   view->array = GNUNET_new_array(len, struct GNUNET_PeerIdentity);
63   view->mpm =
64     GNUNET_CONTAINER_multipeermap_create(len, GNUNET_NO);  /* might even be
65                                                            * set to _YES */
66   return view;
67 }
68
69
70 /**
71  * Change length of view
72  *
73  * If size is decreased, peers with higher indices are removed.
74  *
75  * @param view The view that is changed
76  * @param len the (maximum) length for the view
77  */
78 void
79 View_change_len(struct View *view,
80                 uint32_t len)
81 {
82   uint32_t i;
83   uint32_t *index;
84
85   if (GNUNET_CONTAINER_multipeermap_size(view->mpm) < len)
86     { /* Simply shrink */
87       /* We might simply clear and free the left over space */
88       GNUNET_array_grow(view->array, view->length, len);
89     }
90   else /* We have to remove elements */
91     {
92       /* TODO find a way to preserve indices */
93       for (i = 0; i < len; i++)
94         {
95           index = GNUNET_CONTAINER_multipeermap_get(view->mpm, &view->array[i]);
96           GNUNET_assert(NULL != index);
97           GNUNET_free(index);
98         }
99       GNUNET_array_grow(view->array, view->length, len);
100       GNUNET_CONTAINER_multipeermap_destroy(view->mpm);
101       view->mpm = GNUNET_CONTAINER_multipeermap_create(len, GNUNET_NO);
102       for (i = 0; i < len; i++)
103         {
104           index = GNUNET_new(uint32_t);
105           *index = i;
106           GNUNET_CONTAINER_multipeermap_put(view->mpm, &view->array[i], index,
107                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
108         }
109     }
110   GNUNET_assert(view->length == len);
111 }
112
113
114 /**
115  * Get the view as an array
116  *
117  * @param view The view of which the array representation is of interest
118  * @return the view in array representation
119  */
120 const struct GNUNET_PeerIdentity *
121 View_get_as_array(const struct View *view)
122 {
123   return view->array;
124 }
125
126
127 /**
128  * Get the size of the view
129  *
130  * @param view The view of which the size should be returned
131  * @return current number of actually contained peers
132  */
133 unsigned int
134 View_size(const struct View *view)
135 {
136   return GNUNET_CONTAINER_multipeermap_size(view->mpm);
137 }
138
139
140 /**
141  * Insert peer into the view
142  *
143  * @param view The view to put the peer into
144  * @param peer the peer to insert
145  *
146  * @return GNUNET_OK if peer was actually inserted
147  *         GNUNET_NO if peer was not inserted
148  */
149 int
150 View_put(struct View *view,
151          const struct GNUNET_PeerIdentity *peer)
152 {
153   uint32_t *index;
154
155   if ((view->length <= View_size(view)) ||  /* If array is 'full' */
156       (GNUNET_YES == View_contains_peer(view, peer)))
157     {
158       return GNUNET_NO;
159     }
160   else
161     {
162       index = GNUNET_new(uint32_t);
163       *index = (uint32_t)View_size(view);
164       view->array[*index] = *peer;
165       GNUNET_CONTAINER_multipeermap_put(view->mpm, peer, index,
166                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
167       return GNUNET_OK;
168     }
169 }
170
171
172 /**
173  * Check whether view contains a peer
174  *
175  * @param view The which is checked for a peer
176  * @param peer the peer to check for
177  *
178  * @return GNUNET_OK if view contains peer
179  *         GNUNET_NO otherwise
180  */
181 int
182 View_contains_peer(const struct View *view,
183                    const struct GNUNET_PeerIdentity *peer)
184 {
185   return GNUNET_CONTAINER_multipeermap_contains(view->mpm, peer);
186 }
187
188
189 /**
190  * Remove peer from view
191  *
192  * @param view The view of which to remove the peer
193  * @param peer the peer to remove
194  *
195  * @return GNUNET_OK if view contained peer and removed it successfully
196  *         GNUNET_NO if view does not contain peer
197  */
198 int
199 View_remove_peer(struct View *view,
200                  const struct GNUNET_PeerIdentity *peer)
201 {
202   uint32_t *index;
203   uint32_t *swap_index;
204   uint32_t last_index;
205
206   if (GNUNET_NO == View_contains_peer(view, peer))
207     {
208       return GNUNET_NO;
209     }
210   index = GNUNET_CONTAINER_multipeermap_get(view->mpm, peer);
211   GNUNET_assert(NULL != index);
212   last_index = View_size(view) - 1;
213   if (*index < last_index)
214     { /* Fill the 'gap' in the array with the last peer */
215       view->array[*index] = view->array[last_index];
216       GNUNET_assert(GNUNET_YES == View_contains_peer(view,
217                                                      &view->array[last_index]));
218       swap_index = GNUNET_CONTAINER_multipeermap_get(view->mpm,
219                                                      &view->array[last_index]);
220       GNUNET_assert(NULL != swap_index);
221       *swap_index = *index;
222       GNUNET_free(index);
223     }
224   GNUNET_CONTAINER_multipeermap_remove_all(view->mpm, peer);
225   return GNUNET_OK;
226 }
227
228
229 /**
230  * Get a peer by index
231  *
232  * @param view the view of which to get the peer
233  * @param index the index of the peer to get
234  *
235  * @return peer to the corresponding index.
236  *         NULL if this index is not known
237  */
238 const struct GNUNET_PeerIdentity *
239 View_get_peer_by_index(const struct View *view,
240                        uint32_t index)
241 {
242   if (index < GNUNET_CONTAINER_multipeermap_size(view->mpm))
243     {
244       return &view->array[index];
245     }
246   else
247     {
248       return NULL;
249     }
250 }
251
252
253 /**
254  * Clear the view
255  *
256  * @param view The view to clear
257  */
258 void
259 View_clear(struct View *view)
260 {
261   for (uint32_t i = 0; 0 < View_size(view); i++)
262     { /* Need to free indices stored at peers */
263       uint32_t *index;
264
265       GNUNET_assert(GNUNET_YES ==
266                     GNUNET_CONTAINER_multipeermap_contains(view->mpm, &view->array[i]));
267       index = GNUNET_CONTAINER_multipeermap_get(view->mpm, &view->array[i]);
268       GNUNET_assert(NULL != index);
269       GNUNET_free(index);
270       GNUNET_CONTAINER_multipeermap_remove_all(view->mpm, &view->array[i]);
271     }
272   GNUNET_assert(0 == View_size(view));
273 }
274
275
276 /**
277  * Destroy view.
278  *
279  * @param view the view to destroy
280  */
281 void
282 View_destroy(struct View *view)
283 {
284   View_clear(view);
285   GNUNET_free(view->array);
286   view->array = NULL;
287   GNUNET_CONTAINER_multipeermap_destroy(view->mpm);
288   GNUNET_free(view);
289 }
290
291 /* end of gnunet-service-rps_view.c */