FD.io VPP  v16.06
Vector Packet Processing
fheap.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vppinfra/fheap.h>
16 
17 /* Fibonacci heaps. */
20 { return i != ~0 ? vec_elt_at_index (f->nodes, i) : 0; }
21 
24 { return fheap_get_node (f, f->min_root); }
25 
26 static void fheap_validate (fheap_t * f)
27 {
28  fheap_node_t * n, * m;
29  uword ni, si;
30 
31  if (! CLIB_DEBUG || ! f->enable_validate)
32  return;
33 
34  vec_foreach_index (ni, f->nodes)
35  {
36  n = vec_elt_at_index (f->nodes, ni);
37 
38  if (! n->is_valid)
39  continue;
40 
41  /* Min root must have minimal key. */
42  m = vec_elt_at_index (f->nodes, f->min_root);
43  ASSERT (n->key >= m->key);
44 
45  /* Min root must have no parent. */
46  if (ni == f->min_root)
47  ASSERT (n->parent == ~0);
48 
49  /* Check sibling linkages. */
50  if (n->next_sibling == ~0)
51  ASSERT (n->prev_sibling == ~0);
52  else if (n->prev_sibling == ~0)
53  ASSERT (n->next_sibling == ~0);
54  else
55  {
56  fheap_node_t * prev, * next;
57  u32 si = n->next_sibling, si_start = si;
58  do {
59  m = vec_elt_at_index (f->nodes, si);
60  prev = vec_elt_at_index (f->nodes, m->prev_sibling);
61  next = vec_elt_at_index (f->nodes, m->next_sibling);
62  ASSERT (prev->next_sibling == si);
63  ASSERT (next->prev_sibling == si);
64  si = m->next_sibling;
65  } while (si != si_start);
66  }
67 
68  /* Loop through all siblings. */
69  {
70  u32 n_siblings = 0;
71 
73  m = vec_elt_at_index (f->nodes, si);
74 
75  /* All siblings must have same parent. */
76  ASSERT (m->parent == n->parent);
77 
78  n_siblings += 1;
79  }));
80 
81  /* Either parent is non-empty or there are siblings present. */
82  if (n->parent == ~0 && ni != f->min_root)
83  ASSERT (n_siblings > 0);
84  }
85 
86  /* Loop through all children. */
87  {
88  u32 found_first_child = n->first_child == ~0;
89  u32 n_children = 0;
90 
92  m = vec_elt_at_index (f->nodes, si);
93 
94  /* Children must have larger keys than their parent. */
95  ASSERT (m->key >= n->key);
96 
97  if (! found_first_child)
98  found_first_child = si == n->first_child;
99 
100  n_children += 1;
101  }));
102 
103  /* Check that first child is present on list. */
104  ASSERT (found_first_child);
105 
106  /* Make sure rank is correct. */
107  ASSERT (n->rank == n_children);
108  }
109  }
110 
111  /* Increment serial number for each successful validate.
112  Failure can be used as condition for gdb breakpoints. */
113  f->validate_serial++;
114 }
115 
116 always_inline void
117 fheap_node_add_sibling (fheap_t * f, u32 ni, u32 ni_to_add)
118 {
119  fheap_node_t * n = vec_elt_at_index (f->nodes, ni);
120  fheap_node_t * n_to_add = vec_elt_at_index (f->nodes, ni_to_add);
121  fheap_node_t * n_next = fheap_get_node (f, n->next_sibling);
122  fheap_node_t * parent;
123 
124  /* Empty list? */
125  if (n->next_sibling == ~0)
126  {
127  ASSERT (n->prev_sibling == ~0);
128  n->next_sibling = n->prev_sibling = ni_to_add;
129  n_to_add->next_sibling = n_to_add->prev_sibling = ni;
130  }
131  else
132  {
133  /* Add node after existing node. */
134  n_to_add->prev_sibling = ni;
135  n_to_add->next_sibling = n->next_sibling;
136 
137  n->next_sibling = ni_to_add;
138  n_next->prev_sibling = ni_to_add;
139  }
140 
141  n_to_add->parent = n->parent;
142  parent = fheap_get_node (f, n->parent);
143  if (parent)
144  parent->rank += 1;
145 }
146 
147 void fheap_add (fheap_t * f, u32 ni, u32 key)
148 {
149  fheap_node_t * r, * n;
150  u32 ri;
151 
152  n = vec_elt_at_index (f->nodes, ni);
153 
154  memset (n, 0, sizeof (n[0]));
155  n->parent = n->first_child = n->next_sibling = n->prev_sibling = ~0;
156  n->key = key;
157 
158  r = fheap_get_root (f);
159  ri = f->min_root;
160  if (! r)
161  {
162  /* No root? Add node as new root. */
163  f->min_root = ni;
164  }
165  else
166  {
167  /* Add node as sibling of current root. */
168  fheap_node_add_sibling (f, ri, ni);
169 
170  /* New node may become new root. */
171  if (r->key > n->key)
172  f->min_root = ni;
173  }
174 
175  fheap_validate (f);
176 }
177 
180 {
181  fheap_node_t * n = vec_elt_at_index (f->nodes, ni);
182  u32 prev_ni = n->prev_sibling;
183  u32 next_ni = n->next_sibling;
184  u32 list_has_single_element = prev_ni == ni;
185  fheap_node_t * prev = fheap_get_node (f, prev_ni);
186  fheap_node_t * next = fheap_get_node (f, next_ni);
187  fheap_node_t * p = fheap_get_node (f, n->parent);
188 
189  if (p)
190  {
191  ASSERT (p->rank > 0);
192  p->rank -= 1;
193  p->first_child = list_has_single_element ? ~0 : next_ni;
194  }
195 
196  if (prev)
197  {
198  ASSERT (prev->next_sibling == ni);
199  prev->next_sibling = next_ni;
200  }
201  if (next)
202  {
203  ASSERT (next->prev_sibling == ni);
204  next->prev_sibling = prev_ni;
205  }
206 
207  n->prev_sibling = n->next_sibling = ni;
208  n->parent = ~0;
209  n->is_valid = invalidate == 0;
210 
211  return list_has_single_element ? ~0 : next_ni;
212 }
213 
215 { return fheap_node_remove_internal (f, ni, /* invalidate */ 0); }
216 
218 { return fheap_node_remove_internal (f, ni, /* invalidate */ 1); }
219 
220 static void fheap_link_root (fheap_t * f, u32 ni)
221 {
222  fheap_node_t * n = vec_elt_at_index (f->nodes, ni);
223  fheap_node_t * r, * lo, * hi;
224  u32 ri, lo_i, hi_i, k;
225 
226  while (1)
227  {
228  k = n->rank;
230  ri = f->root_list_by_rank[k];
231  r = fheap_get_node (f, ri);
232  if (! r)
233  {
234  f->root_list_by_rank[k] = ni;
235  return;
236  }
237 
238  f->root_list_by_rank[k] = ~0;
239 
240  /* Sort n/r into lo/hi by their keys. */
241  lo = r, lo_i = ri;
242  hi = n, hi_i = ni;
243  if (hi->key < lo->key)
244  {
245  u32 ti;
246  fheap_node_t * tn;
247  ti = lo_i, tn = lo;
248  lo = hi, lo_i = hi_i;
249  hi = tn, hi_i = ti;
250  }
251 
252  /* Remove larger key. */
253  fheap_node_remove (f, hi_i);
254 
255  /* Add larger key as child of smaller one. */
256  if (lo->first_child == ~0)
257  {
258  hi->parent = lo_i;
259  lo->first_child = hi_i;
260  lo->rank = 1;
261  }
262  else
263  fheap_node_add_sibling (f, lo->first_child, hi_i);
264 
265  /* Following Fredman & Trajan: "When making a root node X a child of another node in a linking step,
266  we unmark X". */
267  hi->is_marked = 0;
268 
269  ni = lo_i;
270  n = lo;
271  }
272 }
273 
274 u32 fheap_del_min (fheap_t * f, u32 * min_key)
275 {
276  fheap_node_t * r = fheap_get_root (f);
277  u32 to_delete_min_ri = f->min_root;
278  u32 ri, ni;
279 
280  /* Empty heap? */
281  if (! r)
282  return ~0;
283 
284  /* Root's children become siblings. Call this step a; see below. */
285  if (r->first_child != ~0)
286  {
287  u32 ci, cni, rni;
288  fheap_node_t * c, * cn, * rn;
289 
290  /* Splice child & root circular lists together. */
291  ci = r->first_child;
292  c = vec_elt_at_index (f->nodes, ci);
293 
294  cni = c->next_sibling;
295  rni = r->next_sibling;
296  cn = vec_elt_at_index (f->nodes, cni);
297  rn = vec_elt_at_index (f->nodes, rni);
298 
299  r->next_sibling = cni;
300  c->next_sibling = rni;
301  cn->prev_sibling = to_delete_min_ri;
302  rn->prev_sibling = ci;
303  }
304 
305  /* Remove min root. */
306  ri = fheap_node_remove_and_invalidate (f, to_delete_min_ri);
307 
308  /* Find new min root from among siblings including the ones we've just added. */
309  f->min_root = ~0;
310  if (ri != ~0)
311  {
312  u32 ri_last, ri_next, i, min_ds;
313 
314  r = fheap_get_node (f, ri);
315  ri_last = r->prev_sibling;
316  while (1)
317  {
318  /* Step a above can put children (with r->parent != ~0) on root list. */
319  r->parent = ~0;
320 
321  ri_next = r->next_sibling;
322  fheap_link_root (f, ri);
323  if (ri == ri_last)
324  break;
325  ri = ri_next;
326  r = fheap_get_node (f, ri);
327  }
328 
329  min_ds = ~0;
331  {
332  ni = f->root_list_by_rank[i];
333  if (ni == ~0)
334  continue;
335  f->root_list_by_rank[i] = ~0;
336  r = fheap_get_node (f, ni);
337  if (r->key < min_ds)
338  {
339  f->min_root = ni;
340  min_ds = r->key;
341  ASSERT (r->parent == ~0);
342  }
343  }
344  }
345 
346  /* Return deleted min root. */
347  r = vec_elt_at_index (f->nodes, to_delete_min_ri);
348  if (min_key)
349  *min_key = r->key;
350 
351  fheap_validate (f);
352 
353  return to_delete_min_ri;
354 }
355 
356 static void fheap_mark_parent (fheap_t * f, u32 pi)
357 {
358  fheap_node_t * p = vec_elt_at_index (f->nodes, pi);
359 
360  /* Parent is a root: do nothing. */
361  if (p->parent == ~0)
362  return;
363 
364  /* If not marked, mark it. */
365  if (! p->is_marked)
366  {
367  p->is_marked = 1;
368  return;
369  }
370 
371  /* Its a previously marked, non-root parent.
372  Cut edge to its parent and add to root list. */
373  fheap_node_remove (f, pi);
374  fheap_node_add_sibling (f, f->min_root, pi);
375 
376  /* Unmark it since its now a root node. */
377  p->is_marked = 0;
378 
379  /* "Cascading cuts": check parent. */
380  if (p->parent != ~0)
381  fheap_mark_parent (f, p->parent);
382 }
383 
384 /* Set key to new smaller value. */
385 void fheap_decrease_key (fheap_t * f, u32 ni, u32 new_key)
386 {
387  fheap_node_t * n = vec_elt_at_index (f->nodes, ni);
388  fheap_node_t * r = fheap_get_root (f);
389 
390  n->key = new_key;
391 
392  if (n->parent != ~0)
393  {
394  fheap_mark_parent (f, n->parent);
395 
396  /* Remove node and add to root list. */
397  fheap_node_remove (f, ni);
398  fheap_node_add_sibling (f, f->min_root, ni);
399  }
400 
401  if (n->key < r->key)
402  f->min_root = ni;
403 
404  fheap_validate (f);
405 }
406 
407 void fheap_del (fheap_t * f, u32 ni)
408 {
409  fheap_node_t * n;
410 
411  n = vec_elt_at_index (f->nodes, ni);
412 
413  if (n->parent == ~0)
414  {
415  ASSERT (ni == f->min_root);
416  fheap_del_min (f, 0);
417  }
418  else
419  {
420  u32 ci;
421 
422  fheap_mark_parent (f, n->parent);
423 
424  /* Add children to root list. */
426  fheap_node_remove (f, ci);
427  fheap_node_add_sibling (f, f->min_root, ci);
428  }));
429 
431  }
432 
433  fheap_validate (f);
434 }
vmrglw vmrglh hi
#define vec_foreach_index(var, v)
Iterate over vector indices.
u32 parent
Definition: fheap.h:25
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
always_inline u32 fheap_node_remove(fheap_t *f, u32 ni)
Definition: fheap.c:214
void fheap_add(fheap_t *f, u32 ni, u32 key)
Definition: fheap.c:147
always_inline void fheap_node_add_sibling(fheap_t *f, u32 ni, u32 ni_to_add)
Definition: fheap.c:117
always_inline fheap_node_t * fheap_get_node(fheap_t *f, u32 i)
Definition: fheap.c:19
fheap_node_t * nodes
Definition: fheap.h:74
#define always_inline
Definition: clib.h:84
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
always_inline u32 fheap_node_remove_internal(fheap_t *f, u32 ni, u32 invalidate)
Definition: fheap.c:179
u32 prev_sibling
Definition: fheap.h:31
always_inline fheap_node_t * fheap_get_root(fheap_t *f)
Definition: fheap.c:23
static void fheap_link_root(fheap_t *f, u32 ni)
Definition: fheap.c:220
#define foreach_fheap_node_sibling(f, ni, first_ni, body)
Definition: fheap.h:46
u32 * root_list_by_rank
Definition: fheap.h:76
u32 validate_serial
Definition: fheap.h:80
u32 is_valid
Definition: fheap.h:43
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u32 rank
Definition: fheap.h:38
always_inline u32 fheap_node_remove_and_invalidate(fheap_t *f, u32 ni)
Definition: fheap.c:217
u32 next_sibling
Definition: fheap.h:31
u64 uword
Definition: types.h:112
static void fheap_mark_parent(fheap_t *f, u32 pi)
Definition: fheap.c:356
void fheap_del(fheap_t *f, u32 ni)
Definition: fheap.c:407
u32 enable_validate
Definition: fheap.h:78
Definition: fheap.h:70
u32 first_child
Definition: fheap.h:28
void fheap_decrease_key(fheap_t *f, u32 ni, u32 new_key)
Definition: fheap.c:385
u32 fheap_del_min(fheap_t *f, u32 *min_key)
Definition: fheap.c:274
u32 is_marked
Definition: fheap.h:40
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:443
static void fheap_validate(fheap_t *f)
Definition: fheap.c:26
u32 min_root
Definition: fheap.h:71
u32 key
Definition: fheap.h:35