You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

365 lines
8.3 KiB

  1. /*****************************************************************************
  2. Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
  3. This program is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free Software
  5. Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along with
  10. this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  11. Place, Suite 330, Boston, MA 02111-1307 USA
  12. *****************************************************************************/
  13. /**************************************************//**
  14. @file include/dyn0dyn.ic
  15. The dynamically allocated array
  16. Created 2/5/1996 Heikki Tuuri
  17. *******************************************************/
  18. /** Value of dyn_block_struct::magic_n */
  19. #define DYN_BLOCK_MAGIC_N 375767
  20. /** Flag for dyn_block_struct::used that indicates a full block */
  21. #define DYN_BLOCK_FULL_FLAG 0x1000000UL
  22. /************************************************************//**
  23. Adds a new block to a dyn array.
  24. @return created block */
  25. UNIV_INTERN
  26. dyn_block_t*
  27. dyn_array_add_block(
  28. /*================*/
  29. dyn_array_t* arr); /*!< in: dyn array */
  30. /************************************************************//**
  31. Gets the first block in a dyn array. */
  32. UNIV_INLINE
  33. dyn_block_t*
  34. dyn_array_get_first_block(
  35. /*======================*/
  36. dyn_array_t* arr) /*!< in: dyn array */
  37. {
  38. return(arr);
  39. }
  40. /************************************************************//**
  41. Gets the last block in a dyn array. */
  42. UNIV_INLINE
  43. dyn_block_t*
  44. dyn_array_get_last_block(
  45. /*=====================*/
  46. dyn_array_t* arr) /*!< in: dyn array */
  47. {
  48. if (arr->heap == NULL) {
  49. return(arr);
  50. }
  51. return(UT_LIST_GET_LAST(arr->base));
  52. }
  53. /********************************************************************//**
  54. Gets the next block in a dyn array.
  55. @return pointer to next, NULL if end of list */
  56. UNIV_INLINE
  57. dyn_block_t*
  58. dyn_array_get_next_block(
  59. /*=====================*/
  60. dyn_array_t* arr, /*!< in: dyn array */
  61. dyn_block_t* block) /*!< in: dyn array block */
  62. {
  63. ut_ad(arr && block);
  64. if (arr->heap == NULL) {
  65. ut_ad(arr == block);
  66. return(NULL);
  67. }
  68. return(UT_LIST_GET_NEXT(list, block));
  69. }
  70. /********************************************************************//**
  71. Gets the number of used bytes in a dyn array block.
  72. @return number of bytes used */
  73. UNIV_INLINE
  74. ulint
  75. dyn_block_get_used(
  76. /*===============*/
  77. dyn_block_t* block) /*!< in: dyn array block */
  78. {
  79. ut_ad(block);
  80. return((block->used) & ~DYN_BLOCK_FULL_FLAG);
  81. }
  82. /********************************************************************//**
  83. Gets pointer to the start of data in a dyn array block.
  84. @return pointer to data */
  85. UNIV_INLINE
  86. byte*
  87. dyn_block_get_data(
  88. /*===============*/
  89. dyn_block_t* block) /*!< in: dyn array block */
  90. {
  91. ut_ad(block);
  92. return(block->data);
  93. }
  94. /*********************************************************************//**
  95. Initializes a dynamic array.
  96. @return initialized dyn array */
  97. UNIV_INLINE
  98. dyn_array_t*
  99. dyn_array_create(
  100. /*=============*/
  101. dyn_array_t* arr) /*!< in: pointer to a memory buffer of
  102. size sizeof(dyn_array_t) */
  103. {
  104. ut_ad(arr);
  105. #if DYN_ARRAY_DATA_SIZE >= DYN_BLOCK_FULL_FLAG
  106. # error "DYN_ARRAY_DATA_SIZE >= DYN_BLOCK_FULL_FLAG"
  107. #endif
  108. arr->heap = NULL;
  109. arr->used = 0;
  110. #ifdef UNIV_DEBUG
  111. arr->buf_end = 0;
  112. arr->magic_n = DYN_BLOCK_MAGIC_N;
  113. #endif
  114. return(arr);
  115. }
  116. /************************************************************//**
  117. Frees a dynamic array. */
  118. UNIV_INLINE
  119. void
  120. dyn_array_free(
  121. /*===========*/
  122. dyn_array_t* arr) /*!< in: dyn array */
  123. {
  124. if (arr->heap != NULL) {
  125. mem_heap_free(arr->heap);
  126. }
  127. #ifdef UNIV_DEBUG
  128. arr->magic_n = 0;
  129. #endif
  130. }
  131. /*********************************************************************//**
  132. Makes room on top of a dyn array and returns a pointer to the added element.
  133. The caller must copy the element to the pointer returned.
  134. @return pointer to the element */
  135. UNIV_INLINE
  136. void*
  137. dyn_array_push(
  138. /*===========*/
  139. dyn_array_t* arr, /*!< in: dynamic array */
  140. ulint size) /*!< in: size in bytes of the element */
  141. {
  142. dyn_block_t* block;
  143. ulint used;
  144. ut_ad(arr);
  145. ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
  146. ut_ad(size <= DYN_ARRAY_DATA_SIZE);
  147. ut_ad(size);
  148. block = arr;
  149. used = block->used;
  150. if (used + size > DYN_ARRAY_DATA_SIZE) {
  151. /* Get the last array block */
  152. block = dyn_array_get_last_block(arr);
  153. used = block->used;
  154. if (used + size > DYN_ARRAY_DATA_SIZE) {
  155. block = dyn_array_add_block(arr);
  156. used = block->used;
  157. }
  158. }
  159. block->used = used + size;
  160. ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
  161. return((block->data) + used);
  162. }
  163. /*********************************************************************//**
  164. Makes room on top of a dyn array and returns a pointer to a buffer in it.
  165. After copying the elements, the caller must close the buffer using
  166. dyn_array_close.
  167. @return pointer to the buffer */
  168. UNIV_INLINE
  169. byte*
  170. dyn_array_open(
  171. /*===========*/
  172. dyn_array_t* arr, /*!< in: dynamic array */
  173. ulint size) /*!< in: size in bytes of the buffer; MUST be
  174. smaller than DYN_ARRAY_DATA_SIZE! */
  175. {
  176. dyn_block_t* block;
  177. ulint used;
  178. ut_ad(arr);
  179. ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
  180. ut_ad(size <= DYN_ARRAY_DATA_SIZE);
  181. ut_ad(size);
  182. block = arr;
  183. used = block->used;
  184. if (used + size > DYN_ARRAY_DATA_SIZE) {
  185. /* Get the last array block */
  186. block = dyn_array_get_last_block(arr);
  187. used = block->used;
  188. if (used + size > DYN_ARRAY_DATA_SIZE) {
  189. block = dyn_array_add_block(arr);
  190. used = block->used;
  191. ut_a(size <= DYN_ARRAY_DATA_SIZE);
  192. }
  193. }
  194. ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
  195. #ifdef UNIV_DEBUG
  196. ut_ad(arr->buf_end == 0);
  197. arr->buf_end = used + size;
  198. #endif
  199. return((block->data) + used);
  200. }
  201. /*********************************************************************//**
  202. Closes the buffer returned by dyn_array_open. */
  203. UNIV_INLINE
  204. void
  205. dyn_array_close(
  206. /*============*/
  207. dyn_array_t* arr, /*!< in: dynamic array */
  208. byte* ptr) /*!< in: buffer space from ptr up was not used */
  209. {
  210. dyn_block_t* block;
  211. ut_ad(arr);
  212. ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
  213. block = dyn_array_get_last_block(arr);
  214. ut_ad(arr->buf_end + block->data >= ptr);
  215. block->used = ptr - block->data;
  216. ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
  217. #ifdef UNIV_DEBUG
  218. arr->buf_end = 0;
  219. #endif
  220. }
  221. /************************************************************//**
  222. Returns pointer to an element in dyn array.
  223. @return pointer to element */
  224. UNIV_INLINE
  225. void*
  226. dyn_array_get_element(
  227. /*==================*/
  228. dyn_array_t* arr, /*!< in: dyn array */
  229. ulint pos) /*!< in: position of element as bytes
  230. from array start */
  231. {
  232. dyn_block_t* block;
  233. ulint used;
  234. ut_ad(arr);
  235. ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
  236. /* Get the first array block */
  237. block = dyn_array_get_first_block(arr);
  238. if (arr->heap != NULL) {
  239. used = dyn_block_get_used(block);
  240. while (pos >= used) {
  241. pos -= used;
  242. block = UT_LIST_GET_NEXT(list, block);
  243. ut_ad(block);
  244. used = dyn_block_get_used(block);
  245. }
  246. }
  247. ut_ad(block);
  248. ut_ad(dyn_block_get_used(block) >= pos);
  249. return(block->data + pos);
  250. }
  251. /************************************************************//**
  252. Returns the size of stored data in a dyn array.
  253. @return data size in bytes */
  254. UNIV_INLINE
  255. ulint
  256. dyn_array_get_data_size(
  257. /*====================*/
  258. dyn_array_t* arr) /*!< in: dyn array */
  259. {
  260. dyn_block_t* block;
  261. ulint sum = 0;
  262. ut_ad(arr);
  263. ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
  264. if (arr->heap == NULL) {
  265. return(arr->used);
  266. }
  267. /* Get the first array block */
  268. block = dyn_array_get_first_block(arr);
  269. while (block != NULL) {
  270. sum += dyn_block_get_used(block);
  271. block = dyn_array_get_next_block(arr, block);
  272. }
  273. return(sum);
  274. }
  275. /********************************************************//**
  276. Pushes n bytes to a dyn array. */
  277. UNIV_INLINE
  278. void
  279. dyn_push_string(
  280. /*============*/
  281. dyn_array_t* arr, /*!< in: dyn array */
  282. const byte* str, /*!< in: string to write */
  283. ulint len) /*!< in: string length */
  284. {
  285. ulint n_copied;
  286. while (len > 0) {
  287. if (len > DYN_ARRAY_DATA_SIZE) {
  288. n_copied = DYN_ARRAY_DATA_SIZE;
  289. } else {
  290. n_copied = len;
  291. }
  292. memcpy(dyn_array_push(arr, n_copied), str, n_copied);
  293. str += n_copied;
  294. len -= n_copied;
  295. }
  296. }