tdq.c 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /*
  2. * tdq.c: implement a 'to-do queue', a simple de-duplicating to-do
  3. * list mechanism.
  4. */
  5. #include <assert.h>
  6. #include "puzzles.h"
  7. /*
  8. * Implementation: a tdq consists of a circular buffer of size n
  9. * storing the integers currently in the queue, plus an array of n
  10. * booleans indicating whether each integer is already there.
  11. *
  12. * Using a circular buffer of size n to store between 0 and n items
  13. * inclusive has an obvious failure mode: if the input and output
  14. * pointers are the same, how do you know whether that means the
  15. * buffer is full or empty?
  16. *
  17. * In this application we have a simple way to tell: in the former
  18. * case, the flags array is all 1s, and in the latter case it's all
  19. * 0s. So we could spot that case and check, say, flags[0].
  20. *
  21. * However, it's even easier to simply determine whether the queue is
  22. * non-empty by testing flags[buffer[op]] - that way we don't even
  23. * _have_ to compare ip against op.
  24. */
  25. struct tdq {
  26. int n;
  27. int *queue;
  28. int ip, op; /* in pointer, out pointer */
  29. bool *flags;
  30. };
  31. tdq *tdq_new(int n)
  32. {
  33. int i;
  34. tdq *tdq = snew(struct tdq);
  35. tdq->queue = snewn(n, int);
  36. tdq->flags = snewn(n, bool);
  37. for (i = 0; i < n; i++) {
  38. tdq->queue[i] = 0;
  39. tdq->flags[i] = false;
  40. }
  41. tdq->n = n;
  42. tdq->ip = tdq->op = 0;
  43. return tdq;
  44. }
  45. void tdq_free(tdq *tdq)
  46. {
  47. sfree(tdq->queue);
  48. sfree(tdq->flags);
  49. sfree(tdq);
  50. }
  51. void tdq_add(tdq *tdq, int k)
  52. {
  53. assert((unsigned)k < (unsigned)tdq->n);
  54. if (!tdq->flags[k]) {
  55. tdq->queue[tdq->ip] = k;
  56. tdq->flags[k] = true;
  57. if (++tdq->ip == tdq->n)
  58. tdq->ip = 0;
  59. }
  60. }
  61. int tdq_remove(tdq *tdq)
  62. {
  63. int ret = tdq->queue[tdq->op];
  64. if (!tdq->flags[ret])
  65. return -1;
  66. tdq->flags[ret] = false;
  67. if (++tdq->op == tdq->n)
  68. tdq->op = 0;
  69. return ret;
  70. }
  71. void tdq_fill(tdq *tdq)
  72. {
  73. int i;
  74. for (i = 0; i < tdq->n; i++)
  75. tdq_add(tdq, i);
  76. }