cbuf.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright (c) 2015-2018 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * Upstream site with license notes :
  18. * http://git.sceen.net/rbraun/librbraun.git/
  19. */
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <stddef.h>
  23. #include <stdint.h>
  24. #include <string.h>
  25. #include <kern/cbuf.h>
  26. #include <kern/macros.h>
  27. // Negative close to 0 so that an overflow occurs early.
  28. #define CBUF_INIT_INDEX ((size_t)-500)
  29. void
  30. cbuf_init (struct cbuf *cbuf, void *buf, size_t capacity)
  31. {
  32. assert (ISP2 (capacity));
  33. cbuf->buf = buf;
  34. cbuf->capacity = capacity;
  35. cbuf->start = CBUF_INIT_INDEX;
  36. cbuf->end = cbuf->start;
  37. }
  38. static size_t
  39. cbuf_index (const struct cbuf *cbuf, size_t abs_index)
  40. {
  41. return (abs_index & (cbuf->capacity - 1));
  42. }
  43. static void
  44. cbuf_update_start (struct cbuf *cbuf)
  45. {
  46. if (cbuf_size (cbuf) > cbuf->capacity)
  47. cbuf->start = cbuf->end - cbuf->capacity;
  48. }
  49. static void
  50. cbuf_update_end (struct cbuf *cbuf)
  51. {
  52. if (cbuf_size (cbuf) > cbuf->capacity)
  53. cbuf->end = cbuf->start + cbuf->capacity;
  54. }
  55. int
  56. cbuf_push (struct cbuf *cbuf, const void *buf, size_t size, bool erase)
  57. {
  58. if (!erase)
  59. {
  60. size_t avail_size = cbuf_avail_size (cbuf);
  61. if (size > avail_size)
  62. return (EAGAIN);
  63. }
  64. return (cbuf_write (cbuf, cbuf_end (cbuf), buf, size));
  65. }
  66. int
  67. cbuf_pop (struct cbuf *cbuf, void *buf, size_t *sizep)
  68. {
  69. if (cbuf_size (cbuf) == 0)
  70. return (EAGAIN);
  71. int error = cbuf_read (cbuf, cbuf_start (cbuf), buf, sizep);
  72. assert (!error);
  73. cbuf->start += *sizep;
  74. return (0);
  75. }
  76. int
  77. cbuf_pushb (struct cbuf *cbuf, uint8_t byte, bool erase)
  78. {
  79. if (!erase)
  80. {
  81. size_t avail_size = cbuf_avail_size (cbuf);
  82. if (! avail_size)
  83. return (EAGAIN);
  84. }
  85. cbuf->buf[cbuf_index (cbuf, cbuf->end)] = byte;
  86. cbuf->end++;
  87. cbuf_update_start (cbuf);
  88. return (0);
  89. }
  90. int
  91. cbuf_popb (struct cbuf *cbuf, void *bytep)
  92. {
  93. if (cbuf_size (cbuf) == 0)
  94. return (EAGAIN);
  95. uint8_t *ptr = bytep;
  96. if (ptr)
  97. *ptr = cbuf->buf[cbuf_index (cbuf, cbuf->start)];
  98. cbuf->start++;
  99. return (0);
  100. }
  101. int
  102. cbuf_write (struct cbuf *cbuf, size_t index, const void *buf, size_t size)
  103. {
  104. if (!cbuf_index_valid (cbuf, index))
  105. return EINVAL;
  106. size_t new_end = index + size;
  107. if (!cbuf_index_valid (cbuf, new_end))
  108. {
  109. cbuf->end = new_end;
  110. cbuf_update_start (cbuf);
  111. if (size > cbuf->capacity)
  112. {
  113. size_t skip = size - cbuf->capacity;
  114. buf = (const char *)buf + skip;
  115. index += skip;
  116. size = cbuf->capacity;
  117. }
  118. }
  119. uint8_t *start = &cbuf->buf[cbuf_index (cbuf, index)],
  120. *end = start + size,
  121. *buf_end = cbuf->buf + cbuf->capacity;
  122. if (end < cbuf->buf || end > buf_end)
  123. {
  124. size_t skip = buf_end - start;
  125. memcpy (start, buf, skip);
  126. buf = (const char *)buf + skip;
  127. start = cbuf->buf;
  128. size -= skip;
  129. }
  130. memcpy (start, buf, size);
  131. return (0);
  132. }
  133. int
  134. cbuf_read (const struct cbuf *cbuf, size_t index, void *buf, size_t *sizep)
  135. {
  136. if (!cbuf_index_valid (cbuf, index))
  137. return (EINVAL);
  138. size_t size = cbuf->end - index;
  139. if (*sizep > size)
  140. *sizep = size;
  141. const uint8_t *start = &cbuf->buf[cbuf_index (cbuf, index)],
  142. *end = start + *sizep,
  143. *buf_end = cbuf->buf + cbuf->capacity;
  144. if (end > cbuf->buf && end <= buf_end)
  145. size = *sizep;
  146. else
  147. {
  148. size = buf_end - start;
  149. if (buf)
  150. {
  151. memcpy (buf, start, size);
  152. buf += size;
  153. }
  154. start = cbuf->buf;
  155. size = *sizep - size;
  156. }
  157. if (buf)
  158. memcpy (buf, start, size);
  159. return (0);
  160. }
  161. void
  162. cbuf_set_start (struct cbuf *cbuf, size_t start)
  163. {
  164. cbuf->start = start;
  165. cbuf_update_end (cbuf);
  166. }
  167. void
  168. cbuf_set_end (struct cbuf *cbuf, size_t end)
  169. {
  170. cbuf->end = end;
  171. cbuf_update_start (cbuf);
  172. }