1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "upb/io/chunked_output_stream.h"
9
10 // Must be last.
11 #include "upb/port/def.inc"
12
13 typedef struct {
14 upb_ZeroCopyOutputStream base;
15
16 char* data;
17 size_t size;
18 size_t limit;
19 size_t position;
20 size_t last_returned_size;
21 } upb_ChunkedOutputStream;
22
upb_ChunkedOutputStream_Next(upb_ZeroCopyOutputStream * z,size_t * count,upb_Status * status)23 static void* upb_ChunkedOutputStream_Next(upb_ZeroCopyOutputStream* z,
24 size_t* count, upb_Status* status) {
25 upb_ChunkedOutputStream* c = (upb_ChunkedOutputStream*)z;
26 UPB_ASSERT(c->position <= c->size);
27
28 char* out = c->data + c->position;
29
30 const size_t chunk = UPB_MIN(c->limit, c->size - c->position);
31 c->position += chunk;
32 c->last_returned_size = chunk;
33 *count = chunk;
34
35 return chunk ? out : NULL;
36 }
37
upb_ChunkedOutputStream_BackUp(upb_ZeroCopyOutputStream * z,size_t count)38 static void upb_ChunkedOutputStream_BackUp(upb_ZeroCopyOutputStream* z,
39 size_t count) {
40 upb_ChunkedOutputStream* c = (upb_ChunkedOutputStream*)z;
41
42 UPB_ASSERT(c->last_returned_size >= count);
43 c->position -= count;
44 c->last_returned_size -= count;
45 }
46
upb_ChunkedOutputStream_ByteCount(const upb_ZeroCopyOutputStream * z)47 static size_t upb_ChunkedOutputStream_ByteCount(
48 const upb_ZeroCopyOutputStream* z) {
49 const upb_ChunkedOutputStream* c = (const upb_ChunkedOutputStream*)z;
50
51 return c->position;
52 }
53
54 static const _upb_ZeroCopyOutputStream_VTable upb_ChunkedOutputStream_vtable = {
55 upb_ChunkedOutputStream_Next,
56 upb_ChunkedOutputStream_BackUp,
57 upb_ChunkedOutputStream_ByteCount,
58 };
59
upb_ChunkedOutputStream_New(void * data,size_t size,size_t limit,upb_Arena * arena)60 upb_ZeroCopyOutputStream* upb_ChunkedOutputStream_New(void* data, size_t size,
61 size_t limit,
62 upb_Arena* arena) {
63 upb_ChunkedOutputStream* c = upb_Arena_Malloc(arena, sizeof(*c));
64 if (!c || !limit) return NULL;
65
66 c->base.vtable = &upb_ChunkedOutputStream_vtable;
67 c->data = data;
68 c->size = size;
69 c->limit = limit;
70 c->position = 0;
71 c->last_returned_size = 0;
72
73 return (upb_ZeroCopyOutputStream*)c;
74 }
75