2 This file is part of GNUnet.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file rps/gnunet-service-rps_view.c
23 * @brief wrapper around the "local view"
24 * @author Julius Bünger
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-rps_view.h"
33 * Array containing the peers
35 struct GNUNET_PeerIdentity *array;
38 * (Maximum) length of the view
43 * Multipeermap containing the peers
45 struct GNUNET_CONTAINER_MultiPeerMap *mpm;
50 * Create an empty view.
52 * @param len the maximum length for the view
53 * @return The newly created view
56 View_create(uint32_t len)
60 view = GNUNET_new(struct View);
62 view->array = GNUNET_new_array(len, struct GNUNET_PeerIdentity);
64 GNUNET_CONTAINER_multipeermap_create(len, GNUNET_NO); /* might even be
71 * Change length of view
73 * If size is decreased, peers with higher indices are removed.
75 * @param view The view that is changed
76 * @param len the (maximum) length for the view
79 View_change_len(struct View *view,
85 if (GNUNET_CONTAINER_multipeermap_size(view->mpm) < len)
87 /* We might simply clear and free the left over space */
88 GNUNET_array_grow(view->array, view->length, len);
90 else /* We have to remove elements */
92 /* TODO find a way to preserve indices */
93 for (i = 0; i < len; i++)
95 index = GNUNET_CONTAINER_multipeermap_get(view->mpm, &view->array[i]);
96 GNUNET_assert(NULL != index);
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++)
104 index = GNUNET_new(uint32_t);
106 GNUNET_CONTAINER_multipeermap_put(view->mpm, &view->array[i], index,
107 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
110 GNUNET_assert(view->length == len);
115 * Get the view as an array
117 * @param view The view of which the array representation is of interest
118 * @return the view in array representation
120 const struct GNUNET_PeerIdentity *
121 View_get_as_array(const struct View *view)
128 * Get the size of the view
130 * @param view The view of which the size should be returned
131 * @return current number of actually contained peers
134 View_size(const struct View *view)
136 return GNUNET_CONTAINER_multipeermap_size(view->mpm);
141 * Insert peer into the view
143 * @param view The view to put the peer into
144 * @param peer the peer to insert
146 * @return GNUNET_OK if peer was actually inserted
147 * GNUNET_NO if peer was not inserted
150 View_put(struct View *view,
151 const struct GNUNET_PeerIdentity *peer)
155 if ((view->length <= View_size(view)) || /* If array is 'full' */
156 (GNUNET_YES == View_contains_peer(view, peer)))
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);
173 * Check whether view contains a peer
175 * @param view The which is checked for a peer
176 * @param peer the peer to check for
178 * @return GNUNET_OK if view contains peer
179 * GNUNET_NO otherwise
182 View_contains_peer(const struct View *view,
183 const struct GNUNET_PeerIdentity *peer)
185 return GNUNET_CONTAINER_multipeermap_contains(view->mpm, peer);
190 * Remove peer from view
192 * @param view The view of which to remove the peer
193 * @param peer the peer to remove
195 * @return GNUNET_OK if view contained peer and removed it successfully
196 * GNUNET_NO if view does not contain peer
199 View_remove_peer(struct View *view,
200 const struct GNUNET_PeerIdentity *peer)
203 uint32_t *swap_index;
206 if (GNUNET_NO == View_contains_peer(view, peer))
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;
224 GNUNET_CONTAINER_multipeermap_remove_all(view->mpm, peer);
230 * Get a peer by index
232 * @param view the view of which to get the peer
233 * @param index the index of the peer to get
235 * @return peer to the corresponding index.
236 * NULL if this index is not known
238 const struct GNUNET_PeerIdentity *
239 View_get_peer_by_index(const struct View *view,
242 if (index < GNUNET_CONTAINER_multipeermap_size(view->mpm))
244 return &view->array[index];
256 * @param view The view to clear
259 View_clear(struct View *view)
261 for (uint32_t i = 0; 0 < View_size(view); i++)
262 { /* Need to free indices stored at peers */
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);
270 GNUNET_CONTAINER_multipeermap_remove_all(view->mpm, &view->array[i]);
272 GNUNET_assert(0 == View_size(view));
279 * @param view the view to destroy
282 View_destroy(struct View *view)
285 GNUNET_free(view->array);
287 GNUNET_CONTAINER_multipeermap_destroy(view->mpm);
291 /* end of gnunet-service-rps_view.c */