Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

262 lignes
7.4 KiB

  1. /* rbuf.h -- round buffers.
  2. Copyright (C) 2013-2014, 2017 Genome Research Ltd.
  3. Author: Petr Danecek <pd3@sanger.ac.uk>
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. THE SOFTWARE. */
  19. #ifndef __RBUF_H__
  20. #define __RBUF_H__
  21. #include <string.h>
  22. typedef struct
  23. {
  24. int m,n,f; // m: allocated size, n: number of elements in the buffer, f: first element
  25. }
  26. rbuf_t;
  27. /**
  28. * rbuf_init() - initialize round buffer
  29. * @rbuf: the rbuf_t holder
  30. * @size: the maximum number of elements
  31. *
  32. */
  33. static inline void rbuf_init(rbuf_t *rbuf, int size)
  34. {
  35. rbuf->m = size; rbuf->n = rbuf->f = 0;
  36. }
  37. /**
  38. * rbuf_kth() - get index of the k-th element of the round buffer
  39. * @rbuf: the rbuf_t holder
  40. * @k: 0-based index. If negative, return k-th element from the end, 1-based
  41. */
  42. static inline int rbuf_kth(rbuf_t *rbuf, int k)
  43. {
  44. if ( k >= rbuf->n ) return -1;
  45. if ( k < 0 )
  46. {
  47. k = rbuf->n + k;
  48. if ( k < 0 ) return -1;
  49. }
  50. int i = k + rbuf->f;
  51. if ( i >= rbuf->m ) i -= rbuf->m;
  52. return i;
  53. }
  54. /**
  55. * rbuf_last() - get index of the last element of the round buffer
  56. * @rbuf: the rbuf_t holder
  57. */
  58. #define rbuf_last(rbuf) rbuf_kth(rbuf, -1)
  59. /**
  60. * rbuf_l2ridx() - get 0-based rbuf index which corresponds to i-th linear index
  61. * @rbuf: the rbuf_t holder
  62. * @idx: 0-based linear index
  63. *
  64. * Returns 0-based circular index or -1 if out of bounds
  65. */
  66. static inline int rbuf_l2ridx(rbuf_t *rbuf, int idx)
  67. {
  68. if ( idx < 0 || idx >= rbuf->n ) return -1;
  69. if ( idx >= rbuf->f )
  70. {
  71. int i = idx - rbuf->f;
  72. if ( i >= rbuf->n ) return -1;
  73. return i;
  74. }
  75. int i = rbuf->m - rbuf->f + idx;
  76. if ( i >= rbuf->n ) return -1;
  77. return i;
  78. }
  79. /**
  80. * rbuf_next() - get index of the next element in the round buffer
  81. * @rbuf: the rbuf_t holder
  82. * @i: pointer to the last rbuf index. Set to -1 before the first call.
  83. *
  84. * Sets i to the next position in the buffer. The return value indicates if
  85. * the position points to a valid element (1) or if there are no more elements
  86. * after *i (0). When the end is reached, *i is set to the first element in the
  87. * buffer.
  88. */
  89. static inline int rbuf_next(rbuf_t *rbuf, int *i)
  90. {
  91. if ( !rbuf->n ) return 0;
  92. if ( *i==-1 ) { *i = rbuf->f; return 1; }
  93. int n = (rbuf->f <= *i) ? *i - rbuf->f + 1 : *i + rbuf->m - rbuf->f + 1;
  94. if ( ++(*i) >= rbuf->m ) *i = 0;
  95. if ( n < rbuf->n ) return 1;
  96. *i = rbuf->f;
  97. return 0;
  98. }
  99. /**
  100. * rbuf_prev() - get index of the previous element in the round buffer
  101. * @rbuf: the rbuf_t holder
  102. * @i: pointer to the last rbuf index. Set to -1 before the first call.
  103. *
  104. * Sets i to the previous position in the buffer. The return value indicates if
  105. * the position points to a valid element (1) or if there are no more elements
  106. * before *i (0).
  107. */
  108. static inline int rbuf_prev(rbuf_t *rbuf, int *i)
  109. {
  110. if ( !rbuf->n || *i==rbuf->f ) return 0;
  111. if ( *i==-1 )
  112. {
  113. *i = rbuf_last(rbuf);
  114. return 1;
  115. }
  116. if ( --(*i) < 0 ) *i = rbuf->m - 1;
  117. return 1;
  118. }
  119. /**
  120. * rbuf_prepend() - register new element at the start of the round buffer
  121. * @rbuf: the rbuf_t holder
  122. *
  123. * Returns index of the newly inserted element.
  124. */
  125. static inline int rbuf_prepend(rbuf_t *rbuf)
  126. {
  127. if ( rbuf->n < rbuf->m ) rbuf->n++;
  128. rbuf->f = rbuf->f > 0 ? rbuf->f - 1 : rbuf->m - 1;
  129. return rbuf->f;
  130. }
  131. /**
  132. * rbuf_append() - register new element at the end of the round buffer
  133. * @rbuf: the rbuf_t holder
  134. *
  135. * Returns index of the newly inserted element.
  136. */
  137. static inline int rbuf_append(rbuf_t *rbuf)
  138. {
  139. if ( rbuf->n < rbuf->m )
  140. {
  141. rbuf->n++;
  142. int i = rbuf->f + rbuf->n;
  143. return i <= rbuf->m ? i - 1 : i - rbuf->m - 1;
  144. }
  145. rbuf->f++;
  146. if ( rbuf->f >= rbuf->m )
  147. {
  148. rbuf->f = 0;
  149. return rbuf->m - 1;
  150. }
  151. return rbuf->f - 1;
  152. }
  153. /**
  154. * rbuf_shift() - removes first element from the buffer
  155. * @rbuf: the rbuf_t holder
  156. *
  157. * Returns index of the removed element.
  158. */
  159. static inline int rbuf_shift(rbuf_t *rbuf)
  160. {
  161. if ( !rbuf->n ) return -1;
  162. int ret = rbuf->f;
  163. rbuf->f++;
  164. if ( rbuf->f >= rbuf->m ) rbuf->f = 0;
  165. rbuf->n--;
  166. return ret;
  167. }
  168. /**
  169. * rbuf_shift_n() - removes first n elements from the buffer
  170. * @rbuf: the rbuf_t holder
  171. * @n: number of elements to remove
  172. */
  173. static inline void rbuf_shift_n(rbuf_t *rbuf, int n)
  174. {
  175. if ( n >= rbuf->n )
  176. {
  177. rbuf->n = rbuf->f = 0;
  178. return;
  179. }
  180. rbuf->n -= n;
  181. rbuf->f += n;
  182. if ( rbuf->f >= rbuf->m ) rbuf->f -= rbuf->m;
  183. }
  184. /**
  185. * rbuf_expand0() - expand round buffer and set the newly allocated elements to 0
  186. * @rbuf: the rbuf holder
  187. * @type_t: data type
  188. * @n: requested number of elements
  189. * @data: data array to be realloced
  190. *
  191. * Note: The new array is linearized and leaves the rbuf.f offset untouched,
  192. * thus the size of the new buffer is determined by the current position.
  193. */
  194. #define rbuf_expand0(rbuf,type_t,n,data) \
  195. { \
  196. if ( n > (rbuf)->m ) \
  197. { \
  198. int m = n + (rbuf)->f; \
  199. m--, m|=m>>1, m|=m>>2, m|=m>>4, m|=m>>8, m|=m>>16, m++; /* kroundup32 */ \
  200. data = (type_t*) realloc(data, sizeof(type_t)*m); \
  201. type_t *ptr = data; \
  202. memset(ptr+(rbuf)->m,0,sizeof(type_t)*(m-(rbuf)->m)); \
  203. if ( (rbuf)->f ) \
  204. { \
  205. memcpy(ptr+(rbuf)->m,ptr,sizeof(type_t)*(rbuf)->f); \
  206. memset(ptr,0,sizeof(type_t)*(rbuf)->f); \
  207. } \
  208. (rbuf)->m = m; \
  209. } \
  210. }
  211. /**
  212. * rbuf_remove_kth() - remove k-th rbuf element (0-based) and memmove the data block
  213. * @rbuf: the rbuf holder
  214. * @type_t: data type
  215. * @k: k-th element to remove
  216. * @data: data array to be modified
  217. */
  218. #define rbuf_remove_kth(rbuf, type_t, kth, data) \
  219. { \
  220. int k = rbuf_kth(rbuf, kth); \
  221. if ( k < (rbuf)->f ) /* shrink from back */ \
  222. { \
  223. int l = rbuf_kth(rbuf, -1); \
  224. if ( k < l ) \
  225. { \
  226. type_t tmp = (data)[k]; \
  227. memmove(data+k, data+k+1, (l - k)*sizeof(type_t)); \
  228. (data)[l] = tmp; \
  229. } \
  230. (rbuf)->n--; \
  231. } \
  232. else /* shrink from front */ \
  233. { \
  234. if ( k > (rbuf)->f ) \
  235. { \
  236. type_t tmp = (data)[k]; \
  237. memmove(&data[(rbuf)->f+1], &data[(rbuf)->f], (k - (rbuf)->f)*sizeof(type_t)); \
  238. (data)[(rbuf)->f] = tmp; \
  239. } \
  240. (rbuf)->f++; \
  241. (rbuf)->n--; \
  242. if ( (rbuf)->f == (rbuf)->m ) (rbuf)->f = 0; \
  243. } \
  244. }
  245. #endif