aGrUM  0.17.2
a C++ library for (probabilistic) graphical models
priorityQueue_tpl.h
Go to the documentation of this file.
1 
31 
32 namespace gum {
33 
34  // ===========================================================================
35  // === GENERAL IMPLEMENTATIION OF PRIORITY QUEUES ===
36  // ===========================================================================
37 
38  // basic constructor
39  template < typename Val,
40  typename Priority,
41  typename Cmp,
42  typename Alloc,
43  bool Gen >
45  PriorityQueueImplementation(Cmp compare, Size capacity) :
46  __indices(capacity >> 1, true, true),
47  __cmp(compare) {
48  __heap.reserve(capacity);
49 
50  // for debugging purposes
51  GUM_CONSTRUCTOR(PriorityQueueImplementation);
52  }
53 
54  // initializer list constructor
55  template < typename Val,
56  typename Priority,
57  typename Cmp,
58  typename Alloc,
59  bool Gen >
62  std::initializer_list< std::pair< Val, Priority > > list) :
63  __indices(Size(list.size()) / 2, true, true) {
64  // fill the queue
65  __heap.reserve(list.size());
66  for (const auto& elt: list) {
67  insert(elt.first, elt.second);
68  }
69 
70  // for debugging purposes
71  GUM_CONSTRUCTOR(PriorityQueueImplementation);
72  }
73 
74  // copy constructor
75  template < typename Val,
76  typename Priority,
77  typename Cmp,
78  typename Alloc,
79  bool Gen >
83  from) :
84  __heap(from.__heap),
85  __indices(from.__indices), __nb_elements(from.__nb_elements),
86  __cmp(from.__cmp) {
87  // fill the heap structure
88  for (const auto& elt: __indices) {
89  __heap[elt.second].second = &(elt.first);
90  }
91 
92  // for debugging purposes
93  GUM_CONS_CPY(PriorityQueueImplementation);
94  }
95 
96  // generalized copy constructor
97  template < typename Val,
98  typename Priority,
99  typename Cmp,
100  typename Alloc,
101  bool Gen >
102  template < typename OtherAlloc >
106  from) :
107  __indices(from.__indices),
108  __nb_elements(from.__nb_elements), __cmp(from.__cmp) {
109  // fill the heap structure
110  if (__nb_elements) {
111  __heap.reserve(from.__heap.size());
112  for (const auto& elt: from.__heap) {
113  __heap.push_back(elt);
114  }
115  for (const auto& elt: __indices) {
116  __heap[elt.second].second = &(elt.first);
117  }
118  }
119 
120  // for debugging purposes
121  GUM_CONS_CPY(PriorityQueueImplementation);
122  }
123 
124  // move constructor
125  template < typename Val,
126  typename Priority,
127  typename Cmp,
128  typename Alloc,
129  bool Gen >
133  __heap(std::move(from.__heap)),
134  __indices(std::move(from.__indices)),
135  __nb_elements(std::move(from.__nb_elements)), __cmp(std::move(from.__cmp)) {
136  // for debugging purposes
137  GUM_CONS_MOV(PriorityQueueImplementation);
138  }
139 
140  // destructor
141  template < typename Val,
142  typename Priority,
143  typename Cmp,
144  typename Alloc,
145  bool Gen >
148  // for debugging purposes
149  GUM_DESTRUCTOR(PriorityQueueImplementation);
150  }
151 
152  // copy operator
153  template < typename Val,
154  typename Priority,
155  typename Cmp,
156  typename Alloc,
157  bool Gen >
161  from) {
162  // avoid self assignment
163  if (this != &from) {
164  // for debugging purposes
165  GUM_OP_CPY(PriorityQueueImplementation);
166 
167  try {
168  // set the comparison function
169  __cmp = from.__cmp;
170 
171  // copy the indices and the heap
172  __indices = from.__indices;
173  __heap = from.__heap;
174  __nb_elements = from.__nb_elements;
175 
176  // restore the link between __indices and __heap
177  for (const auto& elt: __indices) {
178  __heap[elt.second].second = &(elt.first);
179  }
180  } catch (...) {
181  __heap.clear();
182  __indices.clear();
183  __nb_elements = 0;
184 
185  throw;
186  }
187  }
188 
189  return *this;
190  }
191 
192  // generalized copy operator
193  template < typename Val,
194  typename Priority,
195  typename Cmp,
196  typename Alloc,
197  bool Gen >
198  template < typename OtherAlloc >
202  from) {
203  // for debugging purposes
204  GUM_OP_CPY(PriorityQueueImplementation);
205 
206  try {
207  // set the comprison function
208  __cmp = from.__cmp;
209 
210  // copy the indices and the heap
211  __indices = from.__indices;
212  __nb_elements = from.__nb_elements;
213 
214  __heap.clear();
215  if (__nb_elements) {
216  __heap.reserve(from.__heap.size());
217  for (const auto& elt: from.__heap) {
218  __heap.push_back(elt);
219  }
220  for (const auto& elt: __indices) {
221  __heap[elt.second].second = &(elt.first);
222  }
223  }
224  } catch (...) {
225  __heap.clear();
226  __indices.clear();
227  __nb_elements = 0;
228 
229  throw;
230  }
231 
232  return *this;
233  }
234 
235  // move operator
236  template < typename Val,
237  typename Priority,
238  typename Cmp,
239  typename Alloc,
240  bool Gen >
244  // avoid self assignment
245  if (this != &from) {
246  // for debugging purposes
247  GUM_OP_MOV(PriorityQueueImplementation);
248 
249  __indices = std::move(from.__indices);
250  __heap = std::move(from.__heap);
251  __cmp = std::move(from.__cmp);
252  __nb_elements = std::move(from.__nb_elements);
253  }
254 
255  return *this;
256  }
257 
258  // returns the element at the top of the priority queue
259  template < typename Val,
260  typename Priority,
261  typename Cmp,
262  typename Alloc,
263  bool Gen >
264  INLINE const Val&
266  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
267 
268  return *(__heap[0].second);
269  }
270 
271  // returns the priority of the top element
272  template < typename Val,
273  typename Priority,
274  typename Cmp,
275  typename Alloc,
276  bool Gen >
277  INLINE const Priority&
279  const {
280  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
281 
282  return __heap[0].first;
283  }
284 
285  // returns the number of elements in the priority queue
286  template < typename Val,
287  typename Priority,
288  typename Cmp,
289  typename Alloc,
290  bool Gen >
291  INLINE Size
293  noexcept {
294  return __nb_elements;
295  }
296 
297  // return the size of the array storing the priority queue
298  template < typename Val,
299  typename Priority,
300  typename Cmp,
301  typename Alloc,
302  bool Gen >
303  INLINE Size
305  const noexcept {
306  return Size(__heap.capacity());
307  }
308 
309  // changes the size of the array storing the priority queue
310  template < typename Val,
311  typename Priority,
312  typename Cmp,
313  typename Alloc,
314  bool Gen >
315  INLINE void
317  Size new_size) {
318  if (new_size < __nb_elements) return;
319 
320  __heap.reserve(new_size);
321  __indices.resize(new_size / 2);
322  }
323 
324  // removes all the elements from the queue
325  template < typename Val,
326  typename Priority,
327  typename Cmp,
328  typename Alloc,
329  bool Gen >
330  INLINE void
332  __nb_elements = 0;
333  __heap.clear();
334  __indices.clear();
335  }
336 
337  // removes the element at index elt from the priority queue
338  template < typename Val,
339  typename Priority,
340  typename Cmp,
341  typename Alloc,
342  bool Gen >
344  Size index) {
345  if (index >= __nb_elements) return;
346 
347  // remove the element from the hashtable
348  __indices.erase(*(__heap[index].second));
349 
350  // put the last element at the "index" location
351  std::pair< Priority, const Val* > last = std::move(__heap[__nb_elements - 1]);
352  __heap.pop_back();
353  --__nb_elements;
354 
355  if (!__nb_elements || (index == __nb_elements)) return;
356 
357  // restore the heap property
358  Size i = index;
359 
360  for (Size j = (index << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
361  // let j be the max child
362  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
363  ++j;
364 
365  // if "last" is lower than heap[j], "last" must be stored at index i
366  if (__cmp(last.first, __heap[j].first)) break;
367 
368  // else pull up the jth node
369  __heap[i] = std::move(__heap[j]);
370  __indices[*(__heap[i].second)] = i;
371  }
372 
373  // put "last" back into the heap
374  __heap[i] = std::move(last);
375  __indices[*(__heap[i].second)] = i;
376  }
377 
378  // removes a given element from the priority queue (but does not return it)
379  template < typename Val,
380  typename Priority,
381  typename Cmp,
382  typename Alloc,
383  bool Gen >
385  const Val& val) {
386  try {
387  eraseByPos(__indices[val]);
388  } catch (NotFound&) {}
389  }
390 
391  // removes the top of the priority queue (but does not return it)
392  template < typename Val,
393  typename Priority,
394  typename Cmp,
395  typename Alloc,
396  bool Gen >
397  INLINE void
399  eraseByPos(0);
400  }
401 
402  // removes the top element from the priority queue and return it
403  template < typename Val,
404  typename Priority,
405  typename Cmp,
406  typename Alloc,
407  bool Gen >
409  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
410 
411  Val v = *(__heap[0].second);
412  eraseByPos(0);
413 
414  return v;
415  }
416 
417  // returns a hashtable the keys of which are the values stored in the queue
418  template < typename Val,
419  typename Priority,
420  typename Cmp,
421  typename Alloc,
422  bool Gen >
423  INLINE const HashTable< Val, Size >&
425  const noexcept {
426  return reinterpret_cast< const HashTable< Val, Size >& >(__indices);
427  }
428 
429  // inserts a new (a copy) element in the priority queue
430  template < typename Val,
431  typename Priority,
432  typename Cmp,
433  typename Alloc,
434  bool Gen >
435  INLINE Size
437  const Val& val, const Priority& priority) {
438  // create the entry in the indices hashtable (if the element already exists,
439  // __indices.insert will raise a Duplicateelement exception)
441  __indices.insert(val, 0);
442 
443  try {
444  __heap.push_back(
445  std::pair< Priority, const Val* >(priority, &new_elt.first));
446  } catch (...) {
447  __indices.erase(val);
448  throw;
449  }
450 
451  std::pair< Priority, const Val* > new_heap_val =
452  std::move(__heap[__nb_elements]);
453  ++__nb_elements;
454 
455  // restore the heap property
456  Size i = __nb_elements - 1;
457 
458  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
459  i = j, j = (j - 1) >> 1) {
460  __heap[i] = std::move(__heap[j]);
461  __indices[*(__heap[i].second)] = i;
462  }
463 
464  // put the new bucket into the heap
465  __heap[i].first = std::move(new_heap_val.first);
466  __heap[i].second = &(new_elt.first);
467  new_elt.second = i;
468 
469  return i;
470  }
471 
472  // inserts by move a new element in the priority queue
473  template < typename Val,
474  typename Priority,
475  typename Cmp,
476  typename Alloc,
477  bool Gen >
478  INLINE Size
480  Val&& val, Priority&& priority) {
481  // create the entry in the indices hashtable (if the element already exists,
482  // __indices.insert will raise a Duplicateelement exception)
484  __indices.insert(std::move(val), 0);
485 
486  try {
487  __heap.push_back(
488  std::pair< Priority, const Val* >(std::move(priority), &(new_elt.first)));
489  } catch (...) {
490  __indices.erase(new_elt.first);
491  throw;
492  }
493 
494  std::pair< Priority, const Val* > new_heap_val =
495  std::move(__heap[__nb_elements]);
496  ++__nb_elements;
497 
498  // restore the heap property
499  Size i = __nb_elements - 1;
500 
501  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
502  i = j, j = (j - 1) >> 1) {
503  __heap[i] = std::move(__heap[j]);
504  __indices[*(__heap[i].second)] = i;
505  }
506 
507  // put the new bucket into the heap
508  __heap[i].first = std::move(new_heap_val.first);
509  __heap[i].second = &(new_elt.first);
510  new_elt.second = i;
511 
512  return i;
513  }
514 
515  // emplace a new element into the priority queue
516  template < typename Val,
517  typename Priority,
518  typename Cmp,
519  typename Alloc,
520  bool Gen >
521  template < typename... Args >
522  INLINE Size
524  Args&&... args) {
525  std::pair< Val, Priority > new_elt =
526  std::make_pair< Val, Priority >(std::forward< Args >(args)...);
527  return insert(std::move(new_elt.first), std::move(new_elt.second));
528  }
529 
530  // indicates whether the priority queue is empty
531  template < typename Val,
532  typename Priority,
533  typename Cmp,
534  typename Alloc,
535  bool Gen >
536  INLINE bool
538  noexcept {
539  return (__nb_elements == 0);
540  }
541 
542  // indicates whether the priority queue contains a given value
543  template < typename Val,
544  typename Priority,
545  typename Cmp,
546  typename Alloc,
547  bool Gen >
548  INLINE bool
550  const Val& val) const {
551  return __indices.exists(val);
552  }
553 
554  // returns the element at position "index" in the priority queue
555  template < typename Val,
556  typename Priority,
557  typename Cmp,
558  typename Alloc,
559  bool Gen >
560  INLINE const Val&
562  Size index) const {
563  if (index >= __nb_elements) {
565  "not enough elements in the PriorityQueueImplementation");
566  }
567 
568  return *(__heap[index].second);
569  }
570 
571  // displays the content of the queue
572  template < typename Val,
573  typename Priority,
574  typename Cmp,
575  typename Alloc,
576  bool Gen >
577  std::string
579  const {
580  bool deja = false;
581  std::stringstream stream;
582  stream << "[";
583 
584  for (Size i = 0; i != __nb_elements; ++i, deja = true) {
585  if (deja) stream << " , ";
586 
587  stream << "(" << __heap[i].first << " , " << *(__heap[i].second) << ")";
588  }
589 
590  stream << "]";
591 
592  return stream.str();
593  }
594 
595  // changes the size of the internal structure storing the priority queue
596  template < typename Val,
597  typename Priority,
598  typename Cmp,
599  typename Alloc,
600  bool Gen >
602  setPriorityByPos(Size index, const Priority& new_priority) {
603  // check whether the element the priority of which should be changed exists
604  if (index >= __nb_elements) {
606  "not enough elements in the PriorityQueueImplementation");
607  }
608 
609  // get the element itself
610  const Val* val = __heap[index].second;
611 
612  // restore the heap property
613  Size i = index;
614 
615  // move val upward if needed
616  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
617  i = j, j = (j - 1) >> 1) {
618  __heap[i] = std::move(__heap[j]);
619  __indices[*(__heap[i].second)] = i;
620  }
621 
622  // move val downward if needed
623  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
624  // let j be the max child
625  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
626  ++j;
627 
628  // if "val" is lower than heap[j], "val" must be stored at index i
629  if (__cmp(new_priority, __heap[j].first)) break;
630 
631  // else pull up the jth node
632  __heap[i] = std::move(__heap[j]);
633  __indices[*(__heap[i].second)] = i;
634  }
635 
636  // update the index of val
637  __heap[i].first = new_priority;
638  __heap[i].second = val;
639  __indices[*val] = i;
640 
641  return i;
642  }
643 
644  // changes the size of the internal structure storing the priority queue
645  template < typename Val,
646  typename Priority,
647  typename Cmp,
648  typename Alloc,
649  bool Gen >
651  setPriorityByPos(Size index, Priority&& new_priority) {
652  // check whether the element the priority of which should be changed exists
653  if (index >= __nb_elements) {
655  "not enough elements in the PriorityQueueImplementation");
656  }
657 
658  // get the element itself
659  const Val* val = __heap[index].second;
660 
661  // restore the heap property
662  Size i = index;
663 
664  // move val upward if needed
665  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
666  i = j, j = (j - 1) >> 1) {
667  __heap[i] = std::move(__heap[j]);
668  __indices[*(__heap[i].second)] = i;
669  }
670 
671  // move val downward if needed
672  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
673  // let j be the max child
674  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
675  ++j;
676 
677  // if "val" is lower than heap[j], "val" must be stored at index i
678  if (__cmp(new_priority, __heap[j].first)) break;
679 
680  // else pull up the jth node
681  __heap[i] = std::move(__heap[j]);
682  __indices[*(__heap[i].second)] = i;
683  }
684 
685  // update the index of val
686  __heap[i].first = std::move(new_priority);
687  __heap[i].second = val;
688  __indices[*val] = i;
689 
690  return i;
691  }
692 
693  // modifies the priority of a given element
694  template < typename Val,
695  typename Priority,
696  typename Cmp,
697  typename Alloc,
698  bool Gen >
700  const Val& elt, const Priority& new_priority) {
701  setPriorityByPos(__indices[elt], new_priority);
702  }
703 
704  // modifies the priority of a given element
705  template < typename Val,
706  typename Priority,
707  typename Cmp,
708  typename Alloc,
709  bool Gen >
711  const Val& elt, Priority&& new_priority) {
712  setPriorityByPos(__indices[elt], std::move(new_priority));
713  }
714 
715  // returns the priority of a given element
716  template < typename Val,
717  typename Priority,
718  typename Cmp,
719  typename Alloc,
720  bool Gen >
721  INLINE const Priority&
723  const Val& elt) const {
724  return __heap[__indices[elt]].first;
725  }
726 
727  // returns the priority of a given element
728  template < typename Val,
729  typename Priority,
730  typename Cmp,
731  typename Alloc,
732  bool Gen >
733  INLINE const Priority&
735  Size index) const {
736  if (index > __nb_elements) {
738  "not enough elements in the PriorityQueueImplementation");
739  }
740  return __heap[index].first;
741  }
742 
743  // ===========================================================================
744  // === SCALAR OPTIMIZED IMPLEMENTATION OF PRIORITY QUEUES ===
745  // ===========================================================================
746 
747  // basic constructor
748  template < typename Val, typename Priority, typename Cmp, typename Alloc >
750  PriorityQueueImplementation(Cmp compare, Size capacity) :
751  __indices(capacity >> 1, true, true),
752  __cmp(compare) {
753  __heap.reserve(capacity);
754 
755  // for debugging purposes
756  GUM_CONSTRUCTOR(PriorityQueueImplementation);
757  }
758 
759  // initializer list constructor
760  template < typename Val, typename Priority, typename Cmp, typename Alloc >
763  std::initializer_list< std::pair< Val, Priority > > list) :
764  __indices(Size(list.size()) / 2, true, true) {
765  // fill the queue
766  __heap.reserve(list.size());
767  for (const auto& elt: list) {
768  insert(elt.first, elt.second);
769  }
770 
771  // for debugging purposes
772  GUM_CONSTRUCTOR(PriorityQueueImplementation);
773  }
774 
775  // copy constructor
776  template < typename Val, typename Priority, typename Cmp, typename Alloc >
780  from) :
781  __heap(from.__heap),
782  __indices(from.__indices), __nb_elements(from.__nb_elements),
783  __cmp(from.__cmp) {
784  // for debugging purposes
785  GUM_CONS_CPY(PriorityQueueImplementation);
786  }
787 
788  // generalized copy constructor
789  template < typename Val, typename Priority, typename Cmp, typename Alloc >
790  template < typename OtherAlloc >
794  from) :
795  __indices(from.__indices),
796  __nb_elements(from.__nb_elements), __cmp(from.__cmp) {
797  // fill the heap structure
798  if (__nb_elements) {
799  __heap.reserve(from.__heap.size());
800  for (const auto& elt: from.__heap) {
801  __heap.push_back(elt);
802  }
803  }
804 
805  // for debugging purposes
806  GUM_CONS_CPY(PriorityQueueImplementation);
807  }
808 
809  // move constructor
810  template < typename Val, typename Priority, typename Cmp, typename Alloc >
814  __heap(std::move(from.__heap)),
815  __indices(std::move(from.__indices)),
816  __nb_elements(std::move(from.__nb_elements)), __cmp(std::move(from.__cmp)) {
817  // for debugging purposes
818  GUM_CONS_MOV(PriorityQueueImplementation);
819  }
820 
821  // destructor
822  template < typename Val, typename Priority, typename Cmp, typename Alloc >
825  // for debugging purposes
826  GUM_DESTRUCTOR(PriorityQueueImplementation);
827  }
828 
829  // copy operator
830  template < typename Val, typename Priority, typename Cmp, typename Alloc >
834  from) {
835  // avoid self assignment
836  if (this != &from) {
837  // for debugging purposes
838  GUM_OP_CPY(PriorityQueueImplementation);
839 
840  try {
841  // set the comparison function
842  __cmp = from.__cmp;
843 
844  // copy the indices and the heap
845  __indices = from.__indices;
846  __heap = from.__heap;
847  __nb_elements = from.__nb_elements;
848  } catch (...) {
849  __heap.clear();
850  __indices.clear();
851  __nb_elements = 0;
852 
853  throw;
854  }
855  }
856 
857  return *this;
858  }
859 
860  // generalized copy operator
861  template < typename Val, typename Priority, typename Cmp, typename Alloc >
862  template < typename OtherAlloc >
866  from) {
867  // for debugging purposes
868  GUM_OP_CPY(PriorityQueueImplementation);
869 
870  try {
871  // set the comprison function
872  __cmp = from.__cmp;
873 
874  // copy the indices and the heap
875  __indices = from.__indices;
876  __nb_elements = from.__nb_elements;
877 
878  __heap.clear();
879  if (__nb_elements) {
880  __heap.reserve(from.__heap.size());
881  for (const auto& elt: from.__heap) {
882  __heap.push_back(elt);
883  }
884  }
885  } catch (...) {
886  __heap.clear();
887  __indices.clear();
888  __nb_elements = 0;
889 
890  throw;
891  }
892 
893  return *this;
894  }
895 
896  // move operator
897  template < typename Val, typename Priority, typename Cmp, typename Alloc >
901  // avoid self assignment
902  if (this != &from) {
903  // for debugging purposes
904  GUM_OP_MOV(PriorityQueueImplementation);
905 
906  __indices = std::move(from.__indices);
907  __heap = std::move(from.__heap);
908  __cmp = std::move(from.__cmp);
909  __nb_elements = std::move(from.__nb_elements);
910  }
911 
912  return *this;
913  }
914 
915  // returns the element at the top of the priority queue
916  template < typename Val, typename Priority, typename Cmp, typename Alloc >
917  INLINE const Val&
919  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
920 
921  return __heap[0].second;
922  }
923 
924  // returns the priority of the top element
925  template < typename Val, typename Priority, typename Cmp, typename Alloc >
926  INLINE const Priority&
928  const {
929  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
930 
931  return __heap[0].first;
932  }
933 
934  // returns the number of elements in the priority queue
935  template < typename Val, typename Priority, typename Cmp, typename Alloc >
936  INLINE Size
938  noexcept {
939  return __nb_elements;
940  }
941 
942  // return the size of the array storing the priority queue
943  template < typename Val, typename Priority, typename Cmp, typename Alloc >
944  INLINE Size
946  const noexcept {
947  return Size(__heap.capacity());
948  }
949 
950  // changes the size of the array storing the priority queue
951  template < typename Val, typename Priority, typename Cmp, typename Alloc >
952  INLINE void
954  Size new_size) {
955  if (new_size < __nb_elements) return;
956 
957  __heap.reserve(new_size);
958  __indices.resize(new_size / 2);
959  }
960 
961  // removes all the elements from the queue
962  template < typename Val, typename Priority, typename Cmp, typename Alloc >
963  INLINE void
965  __nb_elements = 0;
966  __heap.clear();
967  __indices.clear();
968  }
969 
970  // removes the element at index elt from the priority queue
971  template < typename Val, typename Priority, typename Cmp, typename Alloc >
973  Size index) {
974  if (index >= __nb_elements) return;
975 
976  // remove the element from the hashtable
977  __indices.erase(__heap[index].second);
978 
979  // put the last element at the "index" location
980  std::pair< Priority, Val > last = std::move(__heap[__nb_elements - 1]);
981  __heap.pop_back();
982  --__nb_elements;
983 
984  if (!__nb_elements || (index == __nb_elements)) return;
985 
986  // restore the heap property
987  Size i = index;
988 
989  for (Size j = (index << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
990  // let j be the max child
991  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
992  ++j;
993 
994  // if "last" is lower than heap[j], "last" must be stored at index i
995  if (__cmp(last.first, __heap[j].first)) break;
996 
997  // else pull up the jth node
998  __heap[i] = std::move(__heap[j]);
999  __indices[__heap[i].second] = i;
1000  }
1001 
1002  // put "last" back into the heap
1003  __heap[i] = std::move(last);
1004  __indices[__heap[i].second] = i;
1005  }
1006 
1007  // removes a given element from the priority queue (but does not return it)
1008  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1009  INLINE void
1011  Val val) {
1012  try {
1013  eraseByPos(__indices[val]);
1014  } catch (NotFound&) {}
1015  }
1016 
1017  // removes the top of the priority queue (but does not return it)
1018  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1019  INLINE void
1021  eraseByPos(0);
1022  }
1023 
1024  // removes the top element from the priority queue and return it
1025  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1026  INLINE Val
1028  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
1029 
1030  Val v = __heap[0].second;
1031  eraseByPos(0);
1032 
1033  return v;
1034  }
1035 
1036  // returns a hashtable the keys of which are the values stored in the queue
1037  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1038  INLINE const HashTable< Val, Size >&
1040  const noexcept {
1041  return reinterpret_cast< const HashTable< Val, Size >& >(__indices);
1042  }
1043 
1044  // inserts a new (a copy) element in the priority queue
1045  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1046  INLINE Size
1048  Val val, const Priority& priority) {
1049  // create the entry in the indices hashtable (if the element already exists,
1050  // __indices.insert will raise a Duplicateelement exception)
1052  __indices.insert(val, 0);
1053 
1054  try {
1055  __heap.push_back(std::pair< Priority, Val >(priority, val));
1056  } catch (...) {
1057  __indices.erase(val);
1058  throw;
1059  }
1060 
1061  std::pair< Priority, Val > new_heap_val = std::move(__heap[__nb_elements]);
1062  ++__nb_elements;
1063 
1064  // restore the heap property
1065  Size i = __nb_elements - 1;
1066 
1067  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
1068  i = j, j = (j - 1) >> 1) {
1069  __heap[i] = std::move(__heap[j]);
1070  __indices[__heap[i].second] = i;
1071  }
1072 
1073  // put the new bucket into the heap
1074  __heap[i].first = std::move(new_heap_val.first);
1075  __heap[i].second = val;
1076  new_elt.second = i;
1077 
1078  return i;
1079  }
1080 
1081  // inserts by move a new element in the priority queue
1082  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1083  INLINE Size
1085  Val val, Priority&& priority) {
1086  // create the entry in the indices hashtable (if the element already exists,
1087  // __indices.insert will raise a Duplicateelement exception)
1089  __indices.insert(val, 0);
1090 
1091  try {
1092  __heap.push_back(std::pair< Priority, Val >(std::move(priority), val));
1093  } catch (...) {
1094  __indices.erase(val);
1095  throw;
1096  }
1097 
1098  std::pair< Priority, Val > new_heap_val = std::move(__heap[__nb_elements]);
1099  ++__nb_elements;
1100 
1101  // restore the heap property
1102  Size i = __nb_elements - 1;
1103 
1104  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
1105  i = j, j = (j - 1) >> 1) {
1106  __heap[i] = std::move(__heap[j]);
1107  __indices[__heap[i].second] = i;
1108  }
1109 
1110  // put the new bucket into the heap
1111  __heap[i].first = std::move(new_heap_val.first);
1112  __heap[i].second = val;
1113  new_elt.second = i;
1114 
1115  return i;
1116  }
1117 
1118  // emplace a new element into the priority queue
1119  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1120  template < typename... Args >
1121  INLINE Size
1123  Args&&... args) {
1124  std::pair< Val, Priority > new_elt =
1125  std::make_pair< Val, Priority >(std::forward< Args >(args)...);
1126  return insert(new_elt.first, std::move(new_elt.second));
1127  }
1128 
1129  // indicates whether the priority queue is empty
1130  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1131  INLINE bool
1133  noexcept {
1134  return (__nb_elements == 0);
1135  }
1136 
1137  // indicates whether the priority queue contains a given value
1138  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1139  INLINE bool
1141  Val val) const {
1142  return __indices.exists(val);
1143  }
1144 
1145  // returns the element at position "index" in the priority queue
1146  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1147  INLINE const Val&
1149  Size index) const {
1150  if (index >= __nb_elements) {
1152  "not enough elements in the PriorityQueueImplementation");
1153  }
1154 
1155  return __heap[index].second;
1156  }
1157 
1158  // displays the content of the queue
1159  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1160  std::string
1162  const {
1163  bool deja = false;
1164  std::stringstream stream;
1165  stream << "[";
1166 
1167  for (Size i = 0; i != __nb_elements; ++i, deja = true) {
1168  if (deja) stream << " , ";
1169 
1170  stream << "(" << __heap[i].first << " , " << __heap[i].second << ")";
1171  }
1172 
1173  stream << "]";
1174 
1175  return stream.str();
1176  }
1177 
1178  // changes the size of the internal structure storing the priority queue
1179  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1181  setPriorityByPos(Size index, const Priority& new_priority) {
1182  // check whether the element the priority of which should be changed exists
1183  if (index >= __nb_elements) {
1185  "not enough elements in the PriorityQueueImplementation");
1186  }
1187 
1188  // get the element itself
1189  Val val = __heap[index].second;
1190 
1191  // restore the heap property
1192  Size i = index;
1193 
1194  // move val upward if needed
1195  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
1196  i = j, j = (j - 1) >> 1) {
1197  __heap[i] = std::move(__heap[j]);
1198  __indices[__heap[i].second] = i;
1199  }
1200 
1201  // move val downward if needed
1202  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
1203  // let j be the max child
1204  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
1205  ++j;
1206 
1207  // if "val" is lower than heap[j], "val" must be stored at index i
1208  if (__cmp(new_priority, __heap[j].first)) break;
1209 
1210  // else pull up the jth node
1211  __heap[i] = std::move(__heap[j]);
1212  __indices[__heap[i].second] = i;
1213  }
1214 
1215  // update the index of val
1216  __heap[i].first = new_priority;
1217  __heap[i].second = val;
1218  __indices[val] = i;
1219 
1220  return i;
1221  }
1222 
1223  // changes the size of the internal structure storing the priority queue
1224  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1226  setPriorityByPos(Size index, Priority&& new_priority) {
1227  // check whether the element the priority of which should be changed exists
1228  if (index >= __nb_elements) {
1230  "not enough elements in the PriorityQueueImplementation");
1231  }
1232 
1233  // get the element itself
1234  Val val = __heap[index].second;
1235 
1236  // restore the heap property
1237  Size i = index;
1238 
1239  // move val upward if needed
1240  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
1241  i = j, j = (j - 1) >> 1) {
1242  __heap[i] = std::move(__heap[j]);
1243  __indices[__heap[i].second] = i;
1244  }
1245 
1246  // move val downward if needed
1247  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
1248  // let j be the max child
1249  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
1250  ++j;
1251 
1252  // if "val" is lower than heap[j], "val" must be stored at index i
1253  if (__cmp(new_priority, __heap[j].first)) break;
1254 
1255  // else pull up the jth node
1256  __heap[i] = std::move(__heap[j]);
1257  __indices[__heap[i].second] = i;
1258  }
1259 
1260  // update the index of val
1261  __heap[i].first = std::move(new_priority);
1262  __heap[i].second = val;
1263  __indices[val] = i;
1264 
1265  return i;
1266  }
1267 
1268  // modifies the priority of a given element
1269  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1271  Val elt, const Priority& new_priority) {
1272  setPriorityByPos(__indices[elt], new_priority);
1273  }
1274 
1275  // modifies the priority of a given element
1276  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1278  Val elt, Priority&& new_priority) {
1279  setPriorityByPos(__indices[elt], std::move(new_priority));
1280  }
1281 
1282  // returns the priority of a given element
1283  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1284  INLINE const Priority&
1286  Val elt) const {
1287  return __heap[__indices[elt]].first;
1288  }
1289 
1290  // returns the priority of a given element
1291  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1292  INLINE const Priority&
1294  Size index) const {
1295  if (index > __nb_elements) {
1297  "not enough elements in the PriorityQueueImplementation");
1298  }
1299  return __heap[index].first;
1300  }
1301 
1302  // ===========================================================================
1303  // === PRIORITY QUEUES ===
1304  // ===========================================================================
1305 
1306  // basic constructor
1307  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1309  Size capacity) :
1310  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(cmp, capacity) {
1311  // for debugging purposes
1312  GUM_CONSTRUCTOR(PriorityQueue);
1313  }
1314 
1315  // initializer list constructor
1316  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1318  std::initializer_list< std::pair< Val, Priority > > list) :
1319  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation{list} {
1320  // for debugging purposes
1321  GUM_CONSTRUCTOR(PriorityQueue);
1322  }
1323 
1324  // copy constructor
1325  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1328  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(from) {
1329  // for debugging purposes
1330  GUM_CONS_CPY(PriorityQueue);
1331  }
1332 
1333  // generalized copy constructor
1334  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1335  template < typename OtherAlloc >
1338  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(from) {
1339  // for debugging purposes
1340  GUM_CONS_CPY(PriorityQueue);
1341  }
1342 
1343  // move constructor
1344  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1347  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(std::move(from)) {
1348  // for debugging purposes
1349  GUM_CONS_MOV(PriorityQueue);
1350  }
1351 
1352  // destructor
1353  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1355  // for debugging purposes
1356  GUM_DESTRUCTOR(PriorityQueue);
1357  }
1358 
1359  // copy operator
1360  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1364  Implementation::operator=(from);
1365  return *this;
1366  }
1367 
1368  // generalized copy operator
1369  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1370  template < typename OtherAlloc >
1374  Implementation::operator=(from);
1375  return *this;
1376  }
1377 
1378  // move operator
1379  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1383  Implementation::operator=(std::move(from));
1384  return *this;
1385  }
1386 
1387  // A \c << operator for priority queues
1388  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1389  INLINE std::ostream&
1390  operator<<(std::ostream& stream,
1392  stream << queue.toString();
1393  return stream;
1394  }
1395 
1396 } /* namespace gum */
INLINE std::ostream & operator<<(std::ostream &stream, const PriorityQueue< Val, Priority, Cmp, Alloc > &queue)
The internal class for representing priority queues.
Definition: priorityQueue.h:85
STL namespace.
Size __nb_elements
The number of elements in the heap.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Definition: agrum.h:25
void erase(const Val &val)
Removes a given element from the priority queue (but does not return it).
HashTable< Val, Size, IndexAllocator > __indices
A hashtable for quickly finding the elements by their value.
A priorityQueue is a heap in which each element has a mutable priorityA priority queue is quite simil...
Definition: priorityQueue.h:51
std::vector< std::pair< Priority, const Val *>, HeapAllocator > __heap
An array storing all the elements of the heap as well as their score.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
void resize(Size new_size)
Changes the size of the internal structure storing the priority queue.
void clear()
Removes all the elements from the queue.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
friend class PriorityQueueImplementation
All gum::PriorityQueueImplementation are friends with themselves.
Definition: priorityQueue.h:91
Cmp __cmp
Comparison function.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55