Fifo.vala 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. namespace Invercargill.DataStructures {
  2. public class Fifo<T> : Enumerable<T>, Queue<T> {
  3. public bool is_unblocked { get { return !is_blocking; } }
  4. private bool is_blocking = true;
  5. private FifoItem<T>* first_item = null;
  6. private FifoItem<T>* last_item = null;
  7. public override uint? peek_count() {
  8. return null;
  9. }
  10. public override EnumerableInfo get_info() {
  11. return new EnumerableInfo.infer_ultimate (this, EnumerableCategory.EXTERNAL);
  12. }
  13. public void unblock() {
  14. mutex.lock();
  15. is_blocking = false;
  16. cond.broadcast();
  17. mutex.unlock();
  18. }
  19. public void push(owned T item) {
  20. mutex.lock();
  21. FifoItem<T>* fifo_item = new FifoItem<T>() {
  22. item = item,
  23. };
  24. if(first_item == null) {
  25. first_item = fifo_item;
  26. last_item = fifo_item;
  27. }
  28. else {
  29. last_item->next_item = fifo_item;
  30. last_item = fifo_item;
  31. }
  32. cond.broadcast();
  33. mutex.unlock();
  34. }
  35. public void push_all(Enumerable<T> items) {
  36. mutex.lock();
  37. foreach (var item in items) {
  38. FifoItem<T>* fifo_item = new FifoItem<T>() {
  39. item = item,
  40. };
  41. if(first_item == null) {
  42. first_item = fifo_item;
  43. last_item = fifo_item;
  44. }
  45. else {
  46. last_item->next_item = fifo_item;
  47. last_item = fifo_item;
  48. }
  49. }
  50. cond.broadcast();
  51. mutex.unlock();
  52. }
  53. public T pop() throws SequenceError {
  54. mutex.lock();
  55. while(is_blocking && first_item == null){
  56. cond.wait(mutex);
  57. }
  58. var item = first_item;
  59. if(item != null) {
  60. first_item = item->next_item;
  61. }
  62. mutex.unlock();
  63. if(item == null) {
  64. throw new SequenceError.NO_ELEMENTS("No elements in unblocked queue to pop");
  65. }
  66. var result = item->item;
  67. item->item = null;
  68. delete item;
  69. return result;
  70. }
  71. public T peek() throws SequenceError {
  72. var item = first_item;
  73. if(item == null) {
  74. throw new SequenceError.NO_ELEMENTS("No elements in queue");
  75. }
  76. return item->item;
  77. }
  78. public void push_start(owned T item) {
  79. mutex.lock();
  80. FifoItem<T>* fifo_item = new FifoItem<T>() {
  81. next_item = first_item,
  82. item = item,
  83. };
  84. if(first_item == null) {
  85. last_item = fifo_item;
  86. }
  87. first_item = fifo_item;
  88. cond.broadcast();
  89. mutex.unlock();
  90. }
  91. private bool has_next() {
  92. mutex.lock();
  93. while(is_blocking && first_item == null){
  94. cond.wait(mutex);
  95. }
  96. var state = first_item != null;
  97. mutex.unlock();
  98. return state;
  99. }
  100. private T get_next() {
  101. mutex.lock();
  102. var item = first_item;
  103. first_item = item->next_item;
  104. mutex.unlock();
  105. var result = item->item;
  106. item->item = null;
  107. delete item;
  108. return result;
  109. }
  110. private Cond cond = Cond ();
  111. private Mutex mutex = Mutex ();
  112. public override Tracker<T> get_tracker () {
  113. return new LambdaTracker<T>(
  114. () => has_next(),
  115. () => get_next());
  116. }
  117. ~Fifo() {
  118. var n = first_item;
  119. while(n != null) {
  120. var c = n;
  121. n = n->next_item;
  122. c->item = null;
  123. delete c;
  124. }
  125. }
  126. [Compact]
  127. private class FifoItem<T> {
  128. public T item;
  129. public FifoItem<T>* next_item;
  130. }
  131. }
  132. }