1 /* Free blocks to hold around to avoid repeated mallocs... */
2 #define MAX_RECYCLED 16
4 /* Size of allocations to make. */
5 #define BUF_CHUNK_SIZE 8192
7 /* Max fragments in the iovector to writev. */
8 #define MAX_FRAGMENTS_TO_WRITE 16
10 /* This causes fragments not to be transferred from buffer to buffer,
11 * and not to be allocated in pools. The result is that stack-trace
12 * based debug-allocators work much better with this on.
14 * On the other hand, this can mask over some abuses (eg stack-based
15 * foreign buffer fragment bugs) so we disable it by default.
17 #define GSK_DEBUG_BUFFER_ALLOCATIONS 0
19 #define BUFFER_RECYCLING 0
21 #include <sys/types.h>
27 #include "protobuf-c-data-buffer.h"
34 #define PROTOBUF_C_FRAGMENT_DATA_SIZE 4096
35 #define PROTOBUF_C_FRAGMENT_DATA(frag) ((uint8_t*)(((ProtobufCDataBufferFragment*)(frag))+1))
37 /* --- ProtobufCDataBufferFragment implementation --- */
39 protobuf_c_data_buffer_fragment_avail (ProtobufCDataBufferFragment *frag)
41 return PROTOBUF_C_FRAGMENT_DATA_SIZE - frag->buf_start - frag->buf_length;
43 static inline uint8_t *
44 protobuf_c_data_buffer_fragment_start (ProtobufCDataBufferFragment *frag)
46 return PROTOBUF_C_FRAGMENT_DATA(frag) + frag->buf_start;
48 static inline uint8_t *
49 protobuf_c_data_buffer_fragment_end (ProtobufCDataBufferFragment *frag)
51 return PROTOBUF_C_FRAGMENT_DATA(frag) + frag->buf_start + frag->buf_length;
54 /* --- ProtobufCDataBufferFragment recycling --- */
56 static int num_recycled = 0;
57 static ProtobufCDataBufferFragment* recycling_stack = 0;
60 static ProtobufCDataBufferFragment *
61 new_native_fragment(ProtobufCAllocator *allocator)
63 ProtobufCDataBufferFragment *frag;
65 frag = (ProtobufCDataBufferFragment *) allocator->alloc (allocator, BUF_CHUNK_SIZE);
66 #else /* optimized (?) */
69 frag = recycling_stack;
70 recycling_stack = recycling_stack->next;
75 frag = (ProtobufCDataBufferFragment *) g_malloc (BUF_CHUNK_SIZE);
77 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
78 frag->buf_start = frag->buf_length = 0;
83 #if GSK_DEBUG_BUFFER_ALLOCATIONS || !BUFFER_RECYCLING
84 #define recycle(allocator, frag) allocator->free (allocator, frag)
85 #else /* optimized (?) */
87 recycle(ProtobufCDataBufferFragment* frag,
88 ProtobufCAllocator *allocator)
90 frag->next = recycling_stack;
91 recycling_stack = frag;
94 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
96 /* --- Global public methods --- */
98 * protobuf_c_data_buffer_cleanup_recycling_bin:
100 * Free unused buffer fragments. (Normally some are
101 * kept around to reduce strain on the global allocator.)
104 protobuf_c_data_buffer_cleanup_recycling_bin ()
106 #if !GSK_DEBUG_BUFFER_ALLOCATIONS && BUFFER_RECYCLING
107 G_LOCK (recycling_stack);
108 while (recycling_stack != NULL)
110 ProtobufCDataBufferFragment *next;
111 next = recycling_stack->next;
112 g_free (recycling_stack);
113 recycling_stack = next;
116 G_UNLOCK (recycling_stack);
120 /* --- Public methods --- */
122 * protobuf_c_data_buffer_init:
123 * @buffer: buffer to initialize (as empty).
125 * Construct an empty buffer out of raw memory.
126 * (This is equivalent to filling the buffer with 0s)
129 protobuf_c_data_buffer_init(ProtobufCDataBuffer *buffer,
130 ProtobufCAllocator *allocator)
132 buffer->first_frag = buffer->last_frag = NULL;
134 buffer->allocator = allocator;
137 #if defined(GSK_DEBUG) || GSK_DEBUG_BUFFER_ALLOCATIONS
138 static inline gboolean
139 verify_buffer (const ProtobufCDataBuffer *buffer)
141 const ProtobufCDataBufferFragment *frag;
143 for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
144 total += frag->buf_length;
145 return total == buffer->size;
147 #define CHECK_INTEGRITY(buffer) g_assert (verify_buffer (buffer))
149 #define CHECK_INTEGRITY(buffer)
153 * protobuf_c_data_buffer_append:
154 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
155 * @data: binary data to add to the buffer.
156 * @length: length of @data to add to the buffer.
158 * Append data into the buffer.
161 protobuf_c_data_buffer_append(ProtobufCDataBuffer *buffer,
165 CHECK_INTEGRITY (buffer);
166 buffer->size += length;
170 if (!buffer->last_frag)
172 buffer->last_frag = buffer->first_frag = new_native_fragment (buffer->allocator);
173 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
177 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
180 buffer->last_frag->next = new_native_fragment (buffer->allocator);
181 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
182 buffer->last_frag = buffer->last_frag->next;
187 memcpy (protobuf_c_data_buffer_fragment_end (buffer->last_frag), data, avail);
188 data = (const char *) data + avail;
190 buffer->last_frag->buf_length += avail;
192 CHECK_INTEGRITY (buffer);
196 protobuf_c_data_buffer_append_repeated_char (ProtobufCDataBuffer *buffer,
200 CHECK_INTEGRITY (buffer);
201 buffer->size += count;
205 if (!buffer->last_frag)
207 buffer->last_frag = buffer->first_frag = new_native_fragment (buffer->allocator);
208 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
212 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
215 buffer->last_frag->next = new_native_fragment (buffer->allocator);
216 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
217 buffer->last_frag = buffer->last_frag->next;
222 memset (protobuf_c_data_buffer_fragment_end (buffer->last_frag), character, avail);
224 buffer->last_frag->buf_length += avail;
226 CHECK_INTEGRITY (buffer);
231 protobuf_c_data_buffer_append_repeated_data (ProtobufCDataBuffer *buffer,
232 gconstpointer data_to_repeat,
241 * protobuf_c_data_buffer_append_string:
242 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
243 * @string: NUL-terminated string to append to the buffer.
244 * The NUL is not appended.
246 * Append a string to the buffer.
249 protobuf_c_data_buffer_append_string(ProtobufCDataBuffer *buffer,
252 assert (string != NULL);
253 protobuf_c_data_buffer_append (buffer, string, strlen (string));
257 * protobuf_c_data_buffer_append_char:
258 * @buffer: the buffer to add the byte to.
259 * @character: the byte to add to the buffer.
261 * Append a byte to a buffer.
264 protobuf_c_data_buffer_append_char(ProtobufCDataBuffer *buffer,
267 protobuf_c_data_buffer_append (buffer, &character, 1);
271 * protobuf_c_data_buffer_append_string0:
272 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
273 * @string: NUL-terminated string to append to the buffer;
276 * Append a NUL-terminated string to the buffer. The NUL is appended.
279 protobuf_c_data_buffer_append_string0 (ProtobufCDataBuffer *buffer,
282 protobuf_c_data_buffer_append (buffer, string, strlen (string) + 1);
286 * protobuf_c_data_buffer_read:
287 * @buffer: the buffer to read data from.
288 * @data: buffer to fill with up to @max_length bytes of data.
289 * @max_length: maximum number of bytes to read.
291 * Removes up to @max_length data from the beginning of the buffer,
292 * and writes it to @data. The number of bytes actually read
295 * returns: number of bytes transferred.
298 protobuf_c_data_buffer_read(ProtobufCDataBuffer *buffer,
303 size_t orig_max_length = max_length;
304 CHECK_INTEGRITY (buffer);
305 while (max_length > 0 && buffer->first_frag)
307 ProtobufCDataBufferFragment *first = buffer->first_frag;
308 if (first->buf_length <= max_length)
310 memcpy (data, protobuf_c_data_buffer_fragment_start (first), first->buf_length);
311 rv += first->buf_length;
312 data = (char *) data + first->buf_length;
313 max_length -= first->buf_length;
314 buffer->first_frag = first->next;
315 if (!buffer->first_frag)
316 buffer->last_frag = NULL;
317 recycle (buffer->allocator, first);
321 memcpy (data, protobuf_c_data_buffer_fragment_start (first), max_length);
323 first->buf_length -= max_length;
324 first->buf_start += max_length;
325 data = (char *) data + max_length;
330 assert (rv == orig_max_length || buffer->size == 0);
331 CHECK_INTEGRITY (buffer);
336 * protobuf_c_data_buffer_peek:
337 * @buffer: the buffer to peek data from the front of.
338 * This buffer is unchanged by the operation.
339 * @data: buffer to fill with up to @max_length bytes of data.
340 * @max_length: maximum number of bytes to peek.
342 * Copies up to @max_length data from the beginning of the buffer,
343 * and writes it to @data. The number of bytes actually copied
346 * This function is just like protobuf_c_data_buffer_read() except that the
347 * data is not removed from the buffer.
349 * returns: number of bytes copied into data.
352 protobuf_c_data_buffer_peek (const ProtobufCDataBuffer *buffer,
357 ProtobufCDataBufferFragment *frag = (ProtobufCDataBufferFragment *) buffer->first_frag;
358 CHECK_INTEGRITY (buffer);
359 while (max_length > 0 && frag)
361 if (frag->buf_length <= max_length)
363 memcpy (data, protobuf_c_data_buffer_fragment_start (frag), frag->buf_length);
364 rv += frag->buf_length;
365 data = (char *) data + frag->buf_length;
366 max_length -= frag->buf_length;
371 memcpy (data, protobuf_c_data_buffer_fragment_start (frag), max_length);
373 data = (char *) data + max_length;
381 * protobuf_c_data_buffer_read_line:
382 * @buffer: buffer to read a line from.
384 * Parse a newline (\n) terminated line from
385 * buffer and return it as a newly allocated string.
386 * The newline is changed to a NUL character.
388 * If the buffer does not contain a newline, then NULL is returned.
390 * returns: a newly allocated NUL-terminated string, or NULL.
393 protobuf_c_data_buffer_read_line(ProtobufCDataBuffer *buffer)
397 ProtobufCDataBufferFragment *at;
399 CHECK_INTEGRITY (buffer);
400 for (at = buffer->first_frag; at; at = at->next)
402 uint8_t *start = protobuf_c_data_buffer_fragment_start (at);
404 got = memchr (start, '\n', at->buf_length);
410 len += at->buf_length;
414 rv = buffer->allocator->alloc (buffer->allocator, len + 1);
415 /* If we found a newline, read it out, truncating
416 * it with NUL before we return from the function... */
421 protobuf_c_data_buffer_read (buffer, rv, len + newline_length);
423 CHECK_INTEGRITY (buffer);
428 * protobuf_c_data_buffer_parse_string0:
429 * @buffer: buffer to read a line from.
431 * Parse a NUL-terminated line from
432 * buffer and return it as a newly allocated string.
434 * If the buffer does not contain a newline, then NULL is returned.
436 * returns: a newly allocated NUL-terminated string, or NULL.
439 protobuf_c_data_buffer_parse_string0(ProtobufCDataBuffer *buffer)
441 int index0 = protobuf_c_data_buffer_index_of (buffer, '\0');
445 rv = buffer->allocator->alloc (buffer->allocator, index0 + 1);
446 protobuf_c_data_buffer_read (buffer, rv, index0 + 1);
451 * protobuf_c_data_buffer_peek_char:
452 * @buffer: buffer to peek a single byte from.
454 * Get the first byte in the buffer as a positive or 0 number.
455 * If the buffer is empty, -1 is returned.
456 * The buffer is unchanged.
458 * returns: an unsigned character or -1.
461 protobuf_c_data_buffer_peek_char(const ProtobufCDataBuffer *buffer)
463 const ProtobufCDataBufferFragment *frag;
465 if (buffer->size == 0)
468 for (frag = buffer->first_frag; frag; frag = frag->next)
469 if (frag->buf_length > 0)
471 return * protobuf_c_data_buffer_fragment_start ((ProtobufCDataBufferFragment*)frag);
475 * protobuf_c_data_buffer_read_char:
476 * @buffer: buffer to read a single byte from.
478 * Get the first byte in the buffer as a positive or 0 number,
479 * and remove the character from the buffer.
480 * If the buffer is empty, -1 is returned.
482 * returns: an unsigned character or -1.
485 protobuf_c_data_buffer_read_char (ProtobufCDataBuffer *buffer)
488 if (protobuf_c_data_buffer_read (buffer, &c, 1) == 0)
490 return (int) (uint8_t) c;
494 * protobuf_c_data_buffer_discard:
495 * @buffer: the buffer to discard data from.
496 * @max_discard: maximum number of bytes to discard.
498 * Removes up to @max_discard data from the beginning of the buffer,
499 * and returns the number of bytes actually discarded.
501 * returns: number of bytes discarded.
504 protobuf_c_data_buffer_discard(ProtobufCDataBuffer *buffer,
508 CHECK_INTEGRITY (buffer);
509 while (max_discard > 0 && buffer->first_frag)
511 ProtobufCDataBufferFragment *first = buffer->first_frag;
512 if (first->buf_length <= max_discard)
514 rv += first->buf_length;
515 max_discard -= first->buf_length;
516 buffer->first_frag = first->next;
517 if (!buffer->first_frag)
518 buffer->last_frag = NULL;
519 recycle (buffer->allocator, first);
524 first->buf_length -= max_discard;
525 first->buf_start += max_discard;
530 CHECK_INTEGRITY (buffer);
534 static inline protobuf_c_boolean
535 errno_is_ignorable (int e)
537 #ifdef EWOULDBLOCK /* for windows */
538 if (e == EWOULDBLOCK)
541 return e == EINTR || e == EAGAIN;
545 * protobuf_c_data_buffer_writev:
546 * @read_from: buffer to take data from.
547 * @fd: file-descriptor to write data to.
549 * Writes as much data as possible to the
550 * given file-descriptor using the writev(2)
551 * function to deal with multiple fragments
552 * efficiently, where available.
554 * returns: the number of bytes transferred,
555 * or -1 on a write error (consult errno).
558 protobuf_c_data_buffer_writev (ProtobufCDataBuffer *read_from,
564 ProtobufCDataBufferFragment *frag_at = read_from->first_frag;
565 CHECK_INTEGRITY (read_from);
566 for (nfrag = 0; frag_at != NULL
567 #ifdef MAX_FRAGMENTS_TO_WRITE
568 && nfrag < MAX_FRAGMENTS_TO_WRITE
571 frag_at = frag_at->next;
572 iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
573 frag_at = read_from->first_frag;
574 for (i = 0; i < nfrag; i++)
576 iov[i].iov_len = frag_at->buf_length;
577 iov[i].iov_base = protobuf_c_data_buffer_fragment_start (frag_at);
578 frag_at = frag_at->next;
580 rv = writev (fd, iov, nfrag);
581 if (rv < 0 && errno_is_ignorable (errno))
585 protobuf_c_data_buffer_discard (read_from, rv);
590 * protobuf_c_data_buffer_writev_len:
591 * @read_from: buffer to take data from.
592 * @fd: file-descriptor to write data to.
593 * @max_bytes: maximum number of bytes to write.
595 * Writes up to max_bytes bytes to the
596 * given file-descriptor using the writev(2)
597 * function to deal with multiple fragments
598 * efficiently, where available.
600 * returns: the number of bytes transferred,
601 * or -1 on a write error (consult errno).
604 #define MIN(a,b) ((a) < (b) ? (a) : (b))
606 protobuf_c_data_buffer_writev_len (ProtobufCDataBuffer *read_from,
614 ProtobufCDataBufferFragment *frag_at = read_from->first_frag;
615 CHECK_INTEGRITY (read_from);
616 for (nfrag = 0, bytes = 0; frag_at != NULL && bytes < max_bytes
617 #ifdef MAX_FRAGMENTS_TO_WRITE
618 && nfrag < MAX_FRAGMENTS_TO_WRITE
622 bytes += frag_at->buf_length;
623 frag_at = frag_at->next;
625 iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
626 frag_at = read_from->first_frag;
627 for (bytes = max_bytes, i = 0; i < nfrag && bytes > 0; i++)
629 size_t frag_bytes = MIN (frag_at->buf_length, bytes);
630 iov[i].iov_len = frag_bytes;
631 iov[i].iov_base = protobuf_c_data_buffer_fragment_start (frag_at);
632 frag_at = frag_at->next;
635 rv = writev (fd, iov, i);
636 if (rv < 0 && errno_is_ignorable (errno))
640 protobuf_c_data_buffer_discard (read_from, rv);
645 * protobuf_c_data_buffer_read_in_fd:
646 * @write_to: buffer to append data to.
647 * @read_from: file-descriptor to read data from.
649 * Append data into the buffer directly from the
650 * given file-descriptor.
652 * returns: the number of bytes transferred,
653 * or -1 on a read error (consult errno).
655 /* TODO: zero-copy! */
657 protobuf_c_data_buffer_read_in_fd(ProtobufCDataBuffer *write_to,
661 int rv = read (read_from, buf, sizeof (buf));
664 protobuf_c_data_buffer_append (write_to, buf, rv);
669 * protobuf_c_data_buffer_destruct:
670 * @to_destroy: the buffer to empty.
672 * Remove all fragments from a buffer, leaving it empty.
673 * The buffer is guaranteed to not to be consuming any resources,
674 * but it also is allowed to start using it again.
677 protobuf_c_data_buffer_reset(ProtobufCDataBuffer *to_destroy)
679 ProtobufCDataBufferFragment *at = to_destroy->first_frag;
680 CHECK_INTEGRITY (to_destroy);
683 ProtobufCDataBufferFragment *next = at->next;
684 recycle (to_destroy->allocator, at);
687 to_destroy->first_frag = to_destroy->last_frag = NULL;
688 to_destroy->size = 0;
692 protobuf_c_data_buffer_clear(ProtobufCDataBuffer *to_destroy)
694 ProtobufCDataBufferFragment *at = to_destroy->first_frag;
695 CHECK_INTEGRITY (to_destroy);
698 ProtobufCDataBufferFragment *next = at->next;
699 recycle (to_destroy->allocator, at);
705 * protobuf_c_data_buffer_index_of:
706 * @buffer: buffer to scan.
707 * @char_to_find: a byte to look for.
709 * Scans for the first instance of the given character.
710 * returns: its index in the buffer, or -1 if the character
711 * is not in the buffer.
714 protobuf_c_data_buffer_index_of(ProtobufCDataBuffer *buffer,
717 ProtobufCDataBufferFragment *at = buffer->first_frag;
721 uint8_t *start = protobuf_c_data_buffer_fragment_start (at);
722 uint8_t *saught = memchr (start, char_to_find, at->buf_length);
724 return (saught - start) + rv;
726 rv += at->buf_length;
733 * protobuf_c_data_buffer_str_index_of:
734 * @buffer: buffer to scan.
735 * @str_to_find: a string to look for.
737 * Scans for the first instance of the given string.
738 * returns: its index in the buffer, or -1 if the string
739 * is not in the buffer.
742 protobuf_c_data_buffer_str_index_of (ProtobufCDataBuffer *buffer,
743 const char *str_to_find)
745 ProtobufCDataBufferFragment *frag = buffer->first_frag;
747 for (frag = buffer->first_frag; frag; frag = frag->next)
749 const uint8_t *frag_at = PROTOBUF_C_FRAGMENT_DATA (frag);
750 size_t frag_rem = frag->buf_length;
753 ProtobufCDataBufferFragment *subfrag;
754 const uint8_t *subfrag_at;
757 if (*frag_at != str_to_find[0])
765 subfrag_at = frag_at + 1;
766 subfrag_rem = frag_rem - 1;
767 str_at = str_to_find + 1;
770 while (subfrag != NULL)
772 while (subfrag_rem == 0)
774 subfrag = subfrag->next;
777 subfrag_at = protobuf_c_data_buffer_fragment_start (subfrag);
778 subfrag_rem = subfrag->buf_length;
780 while (*str_at != '\0' && subfrag_rem != 0)
782 if (*str_at++ != *subfrag_at++)
799 * protobuf_c_data_buffer_drain:
800 * @dst: buffer to add to.
801 * @src: buffer to remove from.
803 * Transfer all data from @src to @dst,
804 * leaving @src empty.
806 * returns: the number of bytes transferred.
808 #if GSK_DEBUG_BUFFER_ALLOCATIONS
810 protobuf_c_data_buffer_drain (ProtobufCDataBuffer *dst,
811 ProtobufCDataBuffer *src)
813 size_t rv = src->size;
814 ProtobufCDataBufferFragment *frag;
815 CHECK_INTEGRITY (dst);
816 CHECK_INTEGRITY (src);
817 for (frag = src->first_frag; frag; frag = frag->next)
818 protobuf_c_data_buffer_append (dst,
819 protobuf_c_data_buffer_fragment_start (frag),
821 protobuf_c_data_buffer_discard (src, src->size);
822 CHECK_INTEGRITY (dst);
823 CHECK_INTEGRITY (src);
826 #else /* optimized */
828 protobuf_c_data_buffer_drain (ProtobufCDataBuffer *dst,
829 ProtobufCDataBuffer *src)
831 size_t rv = src->size;
833 CHECK_INTEGRITY (dst);
834 CHECK_INTEGRITY (src);
835 if (src->first_frag == NULL)
838 dst->size += src->size;
840 if (dst->last_frag != NULL)
842 dst->last_frag->next = src->first_frag;
843 dst->last_frag = src->last_frag;
847 dst->first_frag = src->first_frag;
848 dst->last_frag = src->last_frag;
851 src->first_frag = src->last_frag = NULL;
852 CHECK_INTEGRITY (dst);
858 * protobuf_c_data_buffer_transfer:
859 * @dst: place to copy data into.
860 * @src: place to read data from.
861 * @max_transfer: maximum number of bytes to transfer.
863 * Transfer data out of @src and into @dst.
864 * Data is removed from @src. The number of bytes
865 * transferred is returned.
867 * returns: the number of bytes transferred.
869 #if GSK_DEBUG_BUFFER_ALLOCATIONS
871 protobuf_c_data_buffer_transfer(ProtobufCDataBuffer *dst,
872 ProtobufCDataBuffer *src,
876 ProtobufCDataBufferFragment *frag;
877 CHECK_INTEGRITY (dst);
878 CHECK_INTEGRITY (src);
879 for (frag = src->first_frag; frag && max_transfer > 0; frag = frag->next)
881 size_t len = frag->buf_length;
882 if (len >= max_transfer)
884 protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), max_transfer);
890 protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), len);
895 protobuf_c_data_buffer_discard (src, rv);
896 CHECK_INTEGRITY (dst);
897 CHECK_INTEGRITY (src);
900 #else /* optimized */
902 protobuf_c_data_buffer_transfer(ProtobufCDataBuffer *dst,
903 ProtobufCDataBuffer *src,
907 CHECK_INTEGRITY (dst);
908 CHECK_INTEGRITY (src);
909 while (src->first_frag && max_transfer >= src->first_frag->buf_length)
911 ProtobufCDataBufferFragment *frag = src->first_frag;
912 src->first_frag = frag->next;
914 if (src->first_frag == NULL)
915 src->last_frag = NULL;
918 dst->last_frag->next = frag;
920 dst->first_frag = frag;
921 dst->last_frag = frag;
923 rv += frag->buf_length;
924 max_transfer -= frag->buf_length;
927 if (src->first_frag && max_transfer)
929 ProtobufCDataBufferFragment *frag = src->first_frag;
930 protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), max_transfer);
931 frag->buf_start += max_transfer;
932 frag->buf_length -= max_transfer;
936 CHECK_INTEGRITY (dst);
937 CHECK_INTEGRITY (src);
940 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
944 * protobuf_c_data_buffer_printf:
945 * @buffer: the buffer to append to.
946 * @format: printf-style format string describing what to append to buffer.
947 * @Varargs: values referenced by @format string.
949 * Append printf-style content to a buffer.
951 void protobuf_c_data_buffer_printf (ProtobufCDataBuffer *buffer,
956 va_start (args, format);
957 protobuf_c_data_buffer_vprintf (buffer, format, args);
962 * protobuf_c_data_buffer_vprintf:
963 * @buffer: the buffer to append to.
964 * @format: printf-style format string describing what to append to buffer.
965 * @args: values referenced by @format string.
967 * Append printf-style content to a buffer, given a va_list.
969 void protobuf_c_data_buffer_vprintf (ProtobufCDataBuffer *buffer,
973 gsize size = g_printf_string_upper_bound (format, args);
977 g_vsnprintf (buf, sizeof (buf), format, args);
978 protobuf_c_data_buffer_append_string (buffer, buf);
982 char *buf = g_strdup_vprintf (format, args);
983 protobuf_c_data_buffer_append_foreign (buffer, buf, strlen (buf), g_free, buf);
987 /* --- protobuf_c_data_buffer_polystr_index_of implementation --- */
988 /* Test to see if a sequence of buffer fragments
989 * starts with a particular NUL-terminated string.
992 fragment_n_str(ProtobufCDataBufferFragment *frag,
996 size_t len = strlen (string);
999 size_t test_len = frag->buf_length - frag_index;
1004 protobuf_c_data_buffer_fragment_start (frag) + frag_index,
1013 frag_index += test_len;
1014 if (frag_index >= frag->buf_length)
1024 * protobuf_c_data_buffer_polystr_index_of:
1025 * @buffer: buffer to scan.
1026 * @strings: NULL-terminated set of string.
1028 * Scans for the first instance of any of the strings
1031 * returns: the index of that instance, or -1 if not found.
1034 protobuf_c_data_buffer_polystr_index_of (ProtobufCDataBuffer *buffer,
1037 uint8_t init_char_map[16];
1040 int total_index = 0;
1041 ProtobufCDataBufferFragment *frag;
1042 memset (init_char_map, 0, sizeof (init_char_map));
1043 for (num_strings = 0; strings[num_strings] != NULL; num_strings++)
1045 uint8_t c = strings[num_strings][0];
1046 uint8_t mask = (1 << (c % 8));
1047 uint8_t *rack = init_char_map + (c / 8);
1048 if ((*rack & mask) == 0)
1056 for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
1058 const char *frag_start;
1060 int remaining = frag->buf_length;
1061 frag_start = protobuf_c_data_buffer_fragment_start (frag);
1065 const char *start = at;
1068 at = memchr (start, strings[0][0], remaining);
1072 remaining -= (at - start);
1076 while (remaining > 0)
1078 uint8_t i = (uint8_t) (*at);
1079 if (init_char_map[i / 8] & (1 << (i % 8)))
1091 /* Now test each of the strings manually. */
1094 for (test = strings; *test != NULL; test++)
1096 if (fragment_n_str(frag, at - frag_start, *test))
1097 return total_index + (at - frag_start);
1102 total_index += frag->buf_length;