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