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.

239 lines
6.3 KiB

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2011-2012, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license
  7. * details.
  8. * ----------------------------------------------------------------------
  9. */
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "libcork/core/error.h"
  13. #include "libcork/core/types.h"
  14. #include "libcork/ds/managed-buffer.h"
  15. #include "libcork/ds/slice.h"
  16. #include "libcork/helpers/errors.h"
  17. /*-----------------------------------------------------------------------
  18. * Error handling
  19. */
  20. static void
  21. cork_slice_invalid_slice_set(size_t buf_size, size_t requested_offset,
  22. size_t requested_length)
  23. {
  24. cork_error_set
  25. (CORK_SLICE_ERROR, CORK_SLICE_INVALID_SLICE,
  26. "Cannot slice %zu-byte buffer at %zu:%zu",
  27. buf_size, requested_offset, requested_length);
  28. }
  29. /*-----------------------------------------------------------------------
  30. * Managed buffers
  31. */
  32. struct cork_managed_buffer_wrapped {
  33. struct cork_managed_buffer parent;
  34. void *buf;
  35. size_t size;
  36. cork_managed_buffer_freer free;
  37. };
  38. static void
  39. cork_managed_buffer_wrapped__free(struct cork_managed_buffer *vself)
  40. {
  41. struct cork_managed_buffer_wrapped *self =
  42. cork_container_of(vself, struct cork_managed_buffer_wrapped, parent);
  43. self->free(self->buf, self->size);
  44. free(self);
  45. }
  46. static struct cork_managed_buffer_iface CORK_MANAGED_BUFFER_WRAPPED = {
  47. cork_managed_buffer_wrapped__free
  48. };
  49. struct cork_managed_buffer *
  50. cork_managed_buffer_new(const void *buf, size_t size,
  51. cork_managed_buffer_freer free)
  52. {
  53. /*
  54. DEBUG("Creating new struct cork_managed_buffer [%p:%zu], refcount now 1",
  55. buf, size);
  56. */
  57. struct cork_managed_buffer_wrapped *self =
  58. cork_new(struct cork_managed_buffer_wrapped);
  59. self->parent.buf = buf;
  60. self->parent.size = size;
  61. self->parent.ref_count = 1;
  62. self->parent.iface = &CORK_MANAGED_BUFFER_WRAPPED;
  63. self->buf = (void *) buf;
  64. self->size = size;
  65. self->free = free;
  66. return &self->parent;
  67. }
  68. struct cork_managed_buffer_copied {
  69. struct cork_managed_buffer parent;
  70. };
  71. #define cork_managed_buffer_copied_data(self) \
  72. (((void *) (self)) + sizeof(struct cork_managed_buffer_copied))
  73. #define cork_managed_buffer_copied_sizeof(sz) \
  74. ((sz) + sizeof(struct cork_managed_buffer_copied))
  75. static void
  76. cork_managed_buffer_copied__free(struct cork_managed_buffer *vself)
  77. {
  78. struct cork_managed_buffer_copied *self =
  79. cork_container_of(vself, struct cork_managed_buffer_copied, parent);
  80. free(self);
  81. }
  82. static struct cork_managed_buffer_iface CORK_MANAGED_BUFFER_COPIED = {
  83. cork_managed_buffer_copied__free
  84. };
  85. struct cork_managed_buffer *
  86. cork_managed_buffer_new_copy(const void *buf, size_t size)
  87. {
  88. size_t allocated_size = cork_managed_buffer_copied_sizeof(size);
  89. struct cork_managed_buffer_copied *self = malloc(allocated_size);
  90. if (self == NULL) {
  91. return NULL;
  92. }
  93. self->parent.buf = cork_managed_buffer_copied_data(self);
  94. self->parent.size = size;
  95. self->parent.ref_count = 1;
  96. self->parent.iface = &CORK_MANAGED_BUFFER_COPIED;
  97. memcpy((void *) self->parent.buf, buf, size);
  98. return &self->parent;
  99. }
  100. static void
  101. cork_managed_buffer_free(struct cork_managed_buffer *self)
  102. {
  103. /*
  104. DEBUG("Freeing struct cork_managed_buffer [%p:%zu]", self->buf, self->size);
  105. */
  106. self->iface->free(self);
  107. }
  108. struct cork_managed_buffer *
  109. cork_managed_buffer_ref(struct cork_managed_buffer *self)
  110. {
  111. /*
  112. int old_count = self->ref_count++;
  113. DEBUG("Referencing struct cork_managed_buffer [%p:%zu], refcount now %d",
  114. self->buf, self->size, old_count + 1);
  115. */
  116. self->ref_count++;
  117. return self;
  118. }
  119. void
  120. cork_managed_buffer_unref(struct cork_managed_buffer *self)
  121. {
  122. /*
  123. int old_count = self->ref_count--;
  124. DEBUG("Dereferencing struct cork_managed_buffer [%p:%zu], refcount now %d",
  125. self->buf, self->size, old_count - 1);
  126. */
  127. if (--self->ref_count == 0) {
  128. cork_managed_buffer_free(self);
  129. }
  130. }
  131. static struct cork_slice_iface CORK_MANAGED_BUFFER__SLICE;
  132. static void
  133. cork_managed_buffer__slice_free(struct cork_slice *self)
  134. {
  135. struct cork_managed_buffer *mbuf = self->user_data;
  136. cork_managed_buffer_unref(mbuf);
  137. }
  138. static int
  139. cork_managed_buffer__slice_copy(struct cork_slice *dest,
  140. const struct cork_slice *src,
  141. size_t offset, size_t length)
  142. {
  143. struct cork_managed_buffer *mbuf = src->user_data;
  144. dest->buf = src->buf + offset;
  145. dest->size = length;
  146. dest->iface = &CORK_MANAGED_BUFFER__SLICE;
  147. dest->user_data = cork_managed_buffer_ref(mbuf);
  148. return 0;
  149. }
  150. static struct cork_slice_iface CORK_MANAGED_BUFFER__SLICE = {
  151. cork_managed_buffer__slice_free,
  152. cork_managed_buffer__slice_copy,
  153. cork_managed_buffer__slice_copy,
  154. NULL
  155. };
  156. int
  157. cork_managed_buffer_slice(struct cork_slice *dest,
  158. struct cork_managed_buffer *buffer,
  159. size_t offset, size_t length)
  160. {
  161. if ((buffer != NULL) &&
  162. (offset <= buffer->size) &&
  163. ((offset + length) <= buffer->size)) {
  164. /*
  165. DEBUG("Slicing [%p:%zu] at %zu:%zu, gives <%p:%zu>",
  166. buffer->buf, buffer->size,
  167. offset, length,
  168. buffer->buf + offset, length);
  169. */
  170. dest->buf = buffer->buf + offset;
  171. dest->size = length;
  172. dest->iface = &CORK_MANAGED_BUFFER__SLICE;
  173. dest->user_data = cork_managed_buffer_ref(buffer);
  174. return 0;
  175. }
  176. else {
  177. /*
  178. DEBUG("Cannot slice [%p:%zu] at %zu:%zu",
  179. buffer->buf, buffer->size,
  180. offset, length);
  181. */
  182. cork_slice_clear(dest);
  183. cork_slice_invalid_slice_set(0, offset, 0);
  184. return -1;
  185. }
  186. }
  187. int
  188. cork_managed_buffer_slice_offset(struct cork_slice *dest,
  189. struct cork_managed_buffer *buffer,
  190. size_t offset)
  191. {
  192. if (buffer == NULL) {
  193. cork_slice_clear(dest);
  194. cork_slice_invalid_slice_set(0, offset, 0);
  195. return -1;
  196. } else {
  197. return cork_managed_buffer_slice
  198. (dest, buffer, offset, buffer->size - offset);
  199. }
  200. }