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>
32 #include "protobuf-c-data-buffer.h"
39 #define PROTOBUF_C_FRAGMENT_DATA_SIZE 4096
40 #define PROTOBUF_C_FRAGMENT_DATA(frag) ((uint8_t*)(((ProtobufCDataBufferFragment*)(frag))+1))
42 /* --- ProtobufCDataBufferFragment implementation --- */
44 protobuf_c_data_buffer_fragment_avail (ProtobufCDataBufferFragment *frag)
46 return PROTOBUF_C_FRAGMENT_DATA_SIZE - frag->buf_start - frag->buf_length;
48 static inline uint8_t *
49 protobuf_c_data_buffer_fragment_start (ProtobufCDataBufferFragment *frag)
51 return PROTOBUF_C_FRAGMENT_DATA(frag) + frag->buf_start;
53 static inline uint8_t *
54 protobuf_c_data_buffer_fragment_end (ProtobufCDataBufferFragment *frag)
56 return PROTOBUF_C_FRAGMENT_DATA(frag) + frag->buf_start + frag->buf_length;
59 /* --- ProtobufCDataBufferFragment recycling --- */
61 static int num_recycled = 0;
62 static ProtobufCDataBufferFragment* recycling_stack = 0;
65 static ProtobufCDataBufferFragment *
66 new_native_fragment(ProtobufCAllocator *allocator)
68 ProtobufCDataBufferFragment *frag;
70 frag = (ProtobufCDataBufferFragment *) allocator->alloc (allocator, BUF_CHUNK_SIZE);
71 #else /* optimized (?) */
74 frag = recycling_stack;
75 recycling_stack = recycling_stack->next;
80 frag = (ProtobufCDataBufferFragment *) g_malloc (BUF_CHUNK_SIZE);
82 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
83 frag->buf_start = frag->buf_length = 0;
88 #if GSK_DEBUG_BUFFER_ALLOCATIONS || !BUFFER_RECYCLING
89 #define recycle(allocator, frag) allocator->free (allocator, frag)
90 #else /* optimized (?) */
92 recycle(ProtobufCDataBufferFragment* frag,
93 ProtobufCAllocator *allocator)
95 frag->next = recycling_stack;
96 recycling_stack = frag;
99 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
101 /* --- Global public methods --- */
103 * protobuf_c_data_buffer_cleanup_recycling_bin:
105 * Free unused buffer fragments. (Normally some are
106 * kept around to reduce strain on the global allocator.)
109 protobuf_c_data_buffer_cleanup_recycling_bin ()
111 #if !GSK_DEBUG_BUFFER_ALLOCATIONS && BUFFER_RECYCLING
112 G_LOCK (recycling_stack);
113 while (recycling_stack != NULL)
115 ProtobufCDataBufferFragment *next;
116 next = recycling_stack->next;
117 g_free (recycling_stack);
118 recycling_stack = next;
121 G_UNLOCK (recycling_stack);
125 /* --- Public methods --- */
127 * protobuf_c_data_buffer_init:
128 * @buffer: buffer to initialize (as empty).
130 * Construct an empty buffer out of raw memory.
131 * (This is equivalent to filling the buffer with 0s)
134 protobuf_c_data_buffer_init(ProtobufCDataBuffer *buffer,
135 ProtobufCAllocator *allocator)
137 buffer->first_frag = buffer->last_frag = NULL;
139 buffer->allocator = allocator;
142 #if defined(GSK_DEBUG) || GSK_DEBUG_BUFFER_ALLOCATIONS
143 static inline gboolean
144 verify_buffer (const ProtobufCDataBuffer *buffer)
146 const ProtobufCDataBufferFragment *frag;
148 for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
149 total += frag->buf_length;
150 return total == buffer->size;
152 #define CHECK_INTEGRITY(buffer) g_assert (verify_buffer (buffer))
154 #define CHECK_INTEGRITY(buffer)
158 * protobuf_c_data_buffer_append:
159 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
160 * @data: binary data to add to the buffer.
161 * @length: length of @data to add to the buffer.
163 * Append data into the buffer.
166 protobuf_c_data_buffer_append(ProtobufCDataBuffer *buffer,
170 CHECK_INTEGRITY (buffer);
171 buffer->size += length;
175 if (!buffer->last_frag)
177 buffer->last_frag = buffer->first_frag = new_native_fragment (buffer->allocator);
178 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
182 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
185 buffer->last_frag->next = new_native_fragment (buffer->allocator);
186 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
187 buffer->last_frag = buffer->last_frag->next;
192 memcpy (protobuf_c_data_buffer_fragment_end (buffer->last_frag), data, avail);
193 data = (const char *) data + avail;
195 buffer->last_frag->buf_length += avail;
197 CHECK_INTEGRITY (buffer);
201 protobuf_c_data_buffer_append_repeated_char (ProtobufCDataBuffer *buffer,
205 CHECK_INTEGRITY (buffer);
206 buffer->size += count;
210 if (!buffer->last_frag)
212 buffer->last_frag = buffer->first_frag = new_native_fragment (buffer->allocator);
213 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
217 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
220 buffer->last_frag->next = new_native_fragment (buffer->allocator);
221 avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
222 buffer->last_frag = buffer->last_frag->next;
227 memset (protobuf_c_data_buffer_fragment_end (buffer->last_frag), character, avail);
229 buffer->last_frag->buf_length += avail;
231 CHECK_INTEGRITY (buffer);
236 protobuf_c_data_buffer_append_repeated_data (ProtobufCDataBuffer *buffer,
237 gconstpointer data_to_repeat,
246 * protobuf_c_data_buffer_append_string:
247 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
248 * @string: NUL-terminated string to append to the buffer.
249 * The NUL is not appended.
251 * Append a string to the buffer.
254 protobuf_c_data_buffer_append_string(ProtobufCDataBuffer *buffer,
257 assert (string != NULL);
258 protobuf_c_data_buffer_append (buffer, string, strlen (string));
262 * protobuf_c_data_buffer_append_char:
263 * @buffer: the buffer to add the byte to.
264 * @character: the byte to add to the buffer.
266 * Append a byte to a buffer.
269 protobuf_c_data_buffer_append_char(ProtobufCDataBuffer *buffer,
272 protobuf_c_data_buffer_append (buffer, &character, 1);
276 * protobuf_c_data_buffer_append_string0:
277 * @buffer: the buffer to add data to. Data is put at the end of the buffer.
278 * @string: NUL-terminated string to append to the buffer;
281 * Append a NUL-terminated string to the buffer. The NUL is appended.
284 protobuf_c_data_buffer_append_string0 (ProtobufCDataBuffer *buffer,
287 protobuf_c_data_buffer_append (buffer, string, strlen (string) + 1);
291 * protobuf_c_data_buffer_read:
292 * @buffer: the buffer to read data from.
293 * @data: buffer to fill with up to @max_length bytes of data.
294 * @max_length: maximum number of bytes to read.
296 * Removes up to @max_length data from the beginning of the buffer,
297 * and writes it to @data. The number of bytes actually read
300 * returns: number of bytes transferred.
303 protobuf_c_data_buffer_read(ProtobufCDataBuffer *buffer,
308 size_t orig_max_length = max_length;
309 CHECK_INTEGRITY (buffer);
310 while (max_length > 0 && buffer->first_frag)
312 ProtobufCDataBufferFragment *first = buffer->first_frag;
313 if (first->buf_length <= max_length)
315 memcpy (data, protobuf_c_data_buffer_fragment_start (first), first->buf_length);
316 rv += first->buf_length;
317 data = (char *) data + first->buf_length;
318 max_length -= first->buf_length;
319 buffer->first_frag = first->next;
320 if (!buffer->first_frag)
321 buffer->last_frag = NULL;
322 recycle (buffer->allocator, first);
326 memcpy (data, protobuf_c_data_buffer_fragment_start (first), max_length);
328 first->buf_length -= max_length;
329 first->buf_start += max_length;
330 data = (char *) data + max_length;
335 assert (rv == orig_max_length || buffer->size == 0);
336 CHECK_INTEGRITY (buffer);
341 * protobuf_c_data_buffer_peek:
342 * @buffer: the buffer to peek data from the front of.
343 * This buffer is unchanged by the operation.
344 * @data: buffer to fill with up to @max_length bytes of data.
345 * @max_length: maximum number of bytes to peek.
347 * Copies up to @max_length data from the beginning of the buffer,
348 * and writes it to @data. The number of bytes actually copied
351 * This function is just like protobuf_c_data_buffer_read() except that the
352 * data is not removed from the buffer.
354 * returns: number of bytes copied into data.
357 protobuf_c_data_buffer_peek (const ProtobufCDataBuffer *buffer,
362 ProtobufCDataBufferFragment *frag = (ProtobufCDataBufferFragment *) buffer->first_frag;
363 CHECK_INTEGRITY (buffer);
364 while (max_length > 0 && frag)
366 if (frag->buf_length <= max_length)
368 memcpy (data, protobuf_c_data_buffer_fragment_start (frag), frag->buf_length);
369 rv += frag->buf_length;
370 data = (char *) data + frag->buf_length;
371 max_length -= frag->buf_length;
376 memcpy (data, protobuf_c_data_buffer_fragment_start (frag), max_length);
378 data = (char *) data + max_length;
386 * protobuf_c_data_buffer_read_line:
387 * @buffer: buffer to read a line from.
389 * Parse a newline (\n) terminated line from
390 * buffer and return it as a newly allocated string.
391 * The newline is changed to a NUL character.
393 * If the buffer does not contain a newline, then NULL is returned.
395 * returns: a newly allocated NUL-terminated string, or NULL.
398 protobuf_c_data_buffer_read_line(ProtobufCDataBuffer *buffer)
402 ProtobufCDataBufferFragment *at;
404 CHECK_INTEGRITY (buffer);
405 for (at = buffer->first_frag; at; at = at->next)
407 uint8_t *start = protobuf_c_data_buffer_fragment_start (at);
409 got = memchr (start, '\n', at->buf_length);
415 len += at->buf_length;
419 rv = buffer->allocator->alloc (buffer->allocator, len + 1);
420 /* If we found a newline, read it out, truncating
421 * it with NUL before we return from the function... */
426 protobuf_c_data_buffer_read (buffer, rv, len + newline_length);
428 CHECK_INTEGRITY (buffer);
433 * protobuf_c_data_buffer_parse_string0:
434 * @buffer: buffer to read a line from.
436 * Parse a NUL-terminated line from
437 * buffer and return it as a newly allocated string.
439 * If the buffer does not contain a newline, then NULL is returned.
441 * returns: a newly allocated NUL-terminated string, or NULL.
444 protobuf_c_data_buffer_parse_string0(ProtobufCDataBuffer *buffer)
446 int index0 = protobuf_c_data_buffer_index_of (buffer, '\0');
450 rv = buffer->allocator->alloc (buffer->allocator, index0 + 1);
451 protobuf_c_data_buffer_read (buffer, rv, index0 + 1);
456 * protobuf_c_data_buffer_peek_char:
457 * @buffer: buffer to peek a single byte from.
459 * Get the first byte in the buffer as a positive or 0 number.
460 * If the buffer is empty, -1 is returned.
461 * The buffer is unchanged.
463 * returns: an unsigned character or -1.
466 protobuf_c_data_buffer_peek_char(const ProtobufCDataBuffer *buffer)
468 const ProtobufCDataBufferFragment *frag;
470 if (buffer->size == 0)
473 for (frag = buffer->first_frag; frag; frag = frag->next)
474 if (frag->buf_length > 0)
476 return * protobuf_c_data_buffer_fragment_start ((ProtobufCDataBufferFragment*)frag);
480 * protobuf_c_data_buffer_read_char:
481 * @buffer: buffer to read a single byte from.
483 * Get the first byte in the buffer as a positive or 0 number,
484 * and remove the character from the buffer.
485 * If the buffer is empty, -1 is returned.
487 * returns: an unsigned character or -1.
490 protobuf_c_data_buffer_read_char (ProtobufCDataBuffer *buffer)
493 if (protobuf_c_data_buffer_read (buffer, &c, 1) == 0)
495 return (int) (uint8_t) c;
499 * protobuf_c_data_buffer_discard:
500 * @buffer: the buffer to discard data from.
501 * @max_discard: maximum number of bytes to discard.
503 * Removes up to @max_discard data from the beginning of the buffer,
504 * and returns the number of bytes actually discarded.
506 * returns: number of bytes discarded.
509 protobuf_c_data_buffer_discard(ProtobufCDataBuffer *buffer,
513 CHECK_INTEGRITY (buffer);
514 while (max_discard > 0 && buffer->first_frag)
516 ProtobufCDataBufferFragment *first = buffer->first_frag;
517 if (first->buf_length <= max_discard)
519 rv += first->buf_length;
520 max_discard -= first->buf_length;
521 buffer->first_frag = first->next;
522 if (!buffer->first_frag)
523 buffer->last_frag = NULL;
524 recycle (buffer->allocator, first);
529 first->buf_length -= max_discard;
530 first->buf_start += max_discard;
535 CHECK_INTEGRITY (buffer);
539 static inline protobuf_c_boolean
540 errno_is_ignorable (int e)
542 #ifdef EWOULDBLOCK /* for windows */
543 if (e == EWOULDBLOCK)
546 return e == EINTR || e == EAGAIN;
550 * protobuf_c_data_buffer_writev:
551 * @read_from: buffer to take data from.
552 * @fd: file-descriptor to write data to.
554 * Writes as much data as possible to the
555 * given file-descriptor using the writev(2)
556 * function to deal with multiple fragments
557 * efficiently, where available.
559 * returns: the number of bytes transferred,
560 * or -1 on a write error (consult errno).
563 protobuf_c_data_buffer_writev (ProtobufCDataBuffer *read_from,
569 ProtobufCDataBufferFragment *frag_at = read_from->first_frag;
570 CHECK_INTEGRITY (read_from);
571 for (nfrag = 0; frag_at != NULL
572 #ifdef MAX_FRAGMENTS_TO_WRITE
573 && nfrag < MAX_FRAGMENTS_TO_WRITE
576 frag_at = frag_at->next;
577 iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
578 frag_at = read_from->first_frag;
579 for (i = 0; i < nfrag; i++)
581 iov[i].iov_len = frag_at->buf_length;
582 iov[i].iov_base = protobuf_c_data_buffer_fragment_start (frag_at);
583 frag_at = frag_at->next;
585 rv = writev (fd, iov, nfrag);
586 if (rv < 0 && errno_is_ignorable (errno))
590 protobuf_c_data_buffer_discard (read_from, rv);
595 * protobuf_c_data_buffer_writev_len:
596 * @read_from: buffer to take data from.
597 * @fd: file-descriptor to write data to.
598 * @max_bytes: maximum number of bytes to write.
600 * Writes up to max_bytes bytes to the
601 * given file-descriptor using the writev(2)
602 * function to deal with multiple fragments
603 * efficiently, where available.
605 * returns: the number of bytes transferred,
606 * or -1 on a write error (consult errno).
609 #define MIN(a,b) ((a) < (b) ? (a) : (b))
611 protobuf_c_data_buffer_writev_len (ProtobufCDataBuffer *read_from,
619 ProtobufCDataBufferFragment *frag_at = read_from->first_frag;
620 CHECK_INTEGRITY (read_from);
621 for (nfrag = 0, bytes = 0; frag_at != NULL && bytes < max_bytes
622 #ifdef MAX_FRAGMENTS_TO_WRITE
623 && nfrag < MAX_FRAGMENTS_TO_WRITE
627 bytes += frag_at->buf_length;
628 frag_at = frag_at->next;
630 iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
631 frag_at = read_from->first_frag;
632 for (bytes = max_bytes, i = 0; i < nfrag && bytes > 0; i++)
634 size_t frag_bytes = MIN (frag_at->buf_length, bytes);
635 iov[i].iov_len = frag_bytes;
636 iov[i].iov_base = protobuf_c_data_buffer_fragment_start (frag_at);
637 frag_at = frag_at->next;
640 rv = writev (fd, iov, i);
641 if (rv < 0 && errno_is_ignorable (errno))
645 protobuf_c_data_buffer_discard (read_from, rv);
650 * protobuf_c_data_buffer_read_in_fd:
651 * @write_to: buffer to append data to.
652 * @read_from: file-descriptor to read data from.
654 * Append data into the buffer directly from the
655 * given file-descriptor.
657 * returns: the number of bytes transferred,
658 * or -1 on a read error (consult errno).
660 /* TODO: zero-copy! */
662 protobuf_c_data_buffer_read_in_fd(ProtobufCDataBuffer *write_to,
666 int rv = read (read_from, buf, sizeof (buf));
669 protobuf_c_data_buffer_append (write_to, buf, rv);
674 * protobuf_c_data_buffer_destruct:
675 * @to_destroy: the buffer to empty.
677 * Remove all fragments from a buffer, leaving it empty.
678 * The buffer is guaranteed to not to be consuming any resources,
679 * but it also is allowed to start using it again.
682 protobuf_c_data_buffer_reset(ProtobufCDataBuffer *to_destroy)
684 ProtobufCDataBufferFragment *at = to_destroy->first_frag;
685 CHECK_INTEGRITY (to_destroy);
688 ProtobufCDataBufferFragment *next = at->next;
689 recycle (to_destroy->allocator, at);
692 to_destroy->first_frag = to_destroy->last_frag = NULL;
693 to_destroy->size = 0;
697 protobuf_c_data_buffer_clear(ProtobufCDataBuffer *to_destroy)
699 ProtobufCDataBufferFragment *at = to_destroy->first_frag;
700 CHECK_INTEGRITY (to_destroy);
703 ProtobufCDataBufferFragment *next = at->next;
704 recycle (to_destroy->allocator, at);
710 * protobuf_c_data_buffer_index_of:
711 * @buffer: buffer to scan.
712 * @char_to_find: a byte to look for.
714 * Scans for the first instance of the given character.
715 * returns: its index in the buffer, or -1 if the character
716 * is not in the buffer.
719 protobuf_c_data_buffer_index_of(ProtobufCDataBuffer *buffer,
722 ProtobufCDataBufferFragment *at = buffer->first_frag;
726 uint8_t *start = protobuf_c_data_buffer_fragment_start (at);
727 uint8_t *saught = memchr (start, char_to_find, at->buf_length);
729 return (saught - start) + rv;
731 rv += at->buf_length;
738 * protobuf_c_data_buffer_str_index_of:
739 * @buffer: buffer to scan.
740 * @str_to_find: a string to look for.
742 * Scans for the first instance of the given string.
743 * returns: its index in the buffer, or -1 if the string
744 * is not in the buffer.
747 protobuf_c_data_buffer_str_index_of (ProtobufCDataBuffer *buffer,
748 const char *str_to_find)
750 ProtobufCDataBufferFragment *frag = buffer->first_frag;
752 for (frag = buffer->first_frag; frag; frag = frag->next)
754 const uint8_t *frag_at = PROTOBUF_C_FRAGMENT_DATA (frag);
755 size_t frag_rem = frag->buf_length;
758 ProtobufCDataBufferFragment *subfrag;
759 const uint8_t *subfrag_at;
762 if (*frag_at != str_to_find[0])
770 subfrag_at = frag_at + 1;
771 subfrag_rem = frag_rem - 1;
772 str_at = str_to_find + 1;
775 while (subfrag != NULL)
777 while (subfrag_rem == 0)
779 subfrag = subfrag->next;
782 subfrag_at = protobuf_c_data_buffer_fragment_start (subfrag);
783 subfrag_rem = subfrag->buf_length;
785 while (*str_at != '\0' && subfrag_rem != 0)
787 if (*str_at++ != *subfrag_at++)
804 * protobuf_c_data_buffer_drain:
805 * @dst: buffer to add to.
806 * @src: buffer to remove from.
808 * Transfer all data from @src to @dst,
809 * leaving @src empty.
811 * returns: the number of bytes transferred.
813 #if GSK_DEBUG_BUFFER_ALLOCATIONS
815 protobuf_c_data_buffer_drain (ProtobufCDataBuffer *dst,
816 ProtobufCDataBuffer *src)
818 size_t rv = src->size;
819 ProtobufCDataBufferFragment *frag;
820 CHECK_INTEGRITY (dst);
821 CHECK_INTEGRITY (src);
822 for (frag = src->first_frag; frag; frag = frag->next)
823 protobuf_c_data_buffer_append (dst,
824 protobuf_c_data_buffer_fragment_start (frag),
826 protobuf_c_data_buffer_discard (src, src->size);
827 CHECK_INTEGRITY (dst);
828 CHECK_INTEGRITY (src);
831 #else /* optimized */
833 protobuf_c_data_buffer_drain (ProtobufCDataBuffer *dst,
834 ProtobufCDataBuffer *src)
836 size_t rv = src->size;
838 CHECK_INTEGRITY (dst);
839 CHECK_INTEGRITY (src);
840 if (src->first_frag == NULL)
843 dst->size += src->size;
845 if (dst->last_frag != NULL)
847 dst->last_frag->next = src->first_frag;
848 dst->last_frag = src->last_frag;
852 dst->first_frag = src->first_frag;
853 dst->last_frag = src->last_frag;
856 src->first_frag = src->last_frag = NULL;
857 CHECK_INTEGRITY (dst);
863 * protobuf_c_data_buffer_transfer:
864 * @dst: place to copy data into.
865 * @src: place to read data from.
866 * @max_transfer: maximum number of bytes to transfer.
868 * Transfer data out of @src and into @dst.
869 * Data is removed from @src. The number of bytes
870 * transferred is returned.
872 * returns: the number of bytes transferred.
874 #if GSK_DEBUG_BUFFER_ALLOCATIONS
876 protobuf_c_data_buffer_transfer(ProtobufCDataBuffer *dst,
877 ProtobufCDataBuffer *src,
881 ProtobufCDataBufferFragment *frag;
882 CHECK_INTEGRITY (dst);
883 CHECK_INTEGRITY (src);
884 for (frag = src->first_frag; frag && max_transfer > 0; frag = frag->next)
886 size_t len = frag->buf_length;
887 if (len >= max_transfer)
889 protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), max_transfer);
895 protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), len);
900 protobuf_c_data_buffer_discard (src, rv);
901 CHECK_INTEGRITY (dst);
902 CHECK_INTEGRITY (src);
905 #else /* optimized */
907 protobuf_c_data_buffer_transfer(ProtobufCDataBuffer *dst,
908 ProtobufCDataBuffer *src,
912 CHECK_INTEGRITY (dst);
913 CHECK_INTEGRITY (src);
914 while (src->first_frag && max_transfer >= src->first_frag->buf_length)
916 ProtobufCDataBufferFragment *frag = src->first_frag;
917 src->first_frag = frag->next;
919 if (src->first_frag == NULL)
920 src->last_frag = NULL;
923 dst->last_frag->next = frag;
925 dst->first_frag = frag;
926 dst->last_frag = frag;
928 rv += frag->buf_length;
929 max_transfer -= frag->buf_length;
932 if (src->first_frag && max_transfer)
934 ProtobufCDataBufferFragment *frag = src->first_frag;
935 protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), max_transfer);
936 frag->buf_start += max_transfer;
937 frag->buf_length -= max_transfer;
941 CHECK_INTEGRITY (dst);
942 CHECK_INTEGRITY (src);
945 #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
949 * protobuf_c_data_buffer_printf:
950 * @buffer: the buffer to append to.
951 * @format: printf-style format string describing what to append to buffer.
952 * @Varargs: values referenced by @format string.
954 * Append printf-style content to a buffer.
956 void protobuf_c_data_buffer_printf (ProtobufCDataBuffer *buffer,
961 va_start (args, format);
962 protobuf_c_data_buffer_vprintf (buffer, format, args);
967 * protobuf_c_data_buffer_vprintf:
968 * @buffer: the buffer to append to.
969 * @format: printf-style format string describing what to append to buffer.
970 * @args: values referenced by @format string.
972 * Append printf-style content to a buffer, given a va_list.
974 void protobuf_c_data_buffer_vprintf (ProtobufCDataBuffer *buffer,
978 gsize size = g_printf_string_upper_bound (format, args);
982 g_vsnprintf (buf, sizeof (buf), format, args);
983 protobuf_c_data_buffer_append_string (buffer, buf);
987 char *buf = g_strdup_vprintf (format, args);
988 protobuf_c_data_buffer_append_foreign (buffer, buf, strlen (buf), g_free, buf);
992 /* --- protobuf_c_data_buffer_polystr_index_of implementation --- */
993 /* Test to see if a sequence of buffer fragments
994 * starts with a particular NUL-terminated string.
997 fragment_n_str(ProtobufCDataBufferFragment *frag,
1001 size_t len = strlen (string);
1004 size_t test_len = frag->buf_length - frag_index;
1009 protobuf_c_data_buffer_fragment_start (frag) + frag_index,
1018 frag_index += test_len;
1019 if (frag_index >= frag->buf_length)
1029 * protobuf_c_data_buffer_polystr_index_of:
1030 * @buffer: buffer to scan.
1031 * @strings: NULL-terminated set of string.
1033 * Scans for the first instance of any of the strings
1036 * returns: the index of that instance, or -1 if not found.
1039 protobuf_c_data_buffer_polystr_index_of (ProtobufCDataBuffer *buffer,
1042 uint8_t init_char_map[16];
1045 int total_index = 0;
1046 ProtobufCDataBufferFragment *frag;
1047 memset (init_char_map, 0, sizeof (init_char_map));
1048 for (num_strings = 0; strings[num_strings] != NULL; num_strings++)
1050 uint8_t c = strings[num_strings][0];
1051 uint8_t mask = (1 << (c % 8));
1052 uint8_t *rack = init_char_map + (c / 8);
1053 if ((*rack & mask) == 0)
1061 for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
1063 const char *frag_start;
1065 int remaining = frag->buf_length;
1066 frag_start = protobuf_c_data_buffer_fragment_start (frag);
1070 const char *start = at;
1073 at = memchr (start, strings[0][0], remaining);
1077 remaining -= (at - start);
1081 while (remaining > 0)
1083 uint8_t i = (uint8_t) (*at);
1084 if (init_char_map[i / 8] & (1 << (i % 8)))
1096 /* Now test each of the strings manually. */
1099 for (test = strings; *test != NULL; test++)
1101 if (fragment_n_str(frag, at - frag_start, *test))
1102 return total_index + (at - frag_start);
1107 total_index += frag->buf_length;