These functions are not yet part of the upb build but this is a good chunk of work so let's snapshot it now. PiperOrigin-RevId: 459156286pull/13171/head
parent
cce085b7e7
commit
1c13fd0686
9 changed files with 908 additions and 0 deletions
@ -0,0 +1,45 @@ |
|||||||
|
cc_library( |
||||||
|
name = "zero_copy_stream", |
||||||
|
hdrs = [ |
||||||
|
"zero_copy_input_stream.h", |
||||||
|
"zero_copy_output_stream.h", |
||||||
|
], |
||||||
|
visibility = ["//upb/io:__pkg__"], |
||||||
|
deps = [ |
||||||
|
"//:upb", |
||||||
|
"//:port", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_library( |
||||||
|
name = "chunked_stream", |
||||||
|
testonly = 1, |
||||||
|
srcs = [ |
||||||
|
"chunked_input_stream.c", |
||||||
|
"chunked_output_stream.c", |
||||||
|
], |
||||||
|
hdrs = [ |
||||||
|
"chunked_input_stream.h", |
||||||
|
"chunked_output_stream.h", |
||||||
|
], |
||||||
|
visibility = ["//upb/io:__pkg__"], |
||||||
|
deps = [ |
||||||
|
":zero_copy_stream", |
||||||
|
"//:upb", |
||||||
|
"//:port", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_test( |
||||||
|
name = "zero_copy_stream_test", |
||||||
|
size = "small", |
||||||
|
srcs = [ |
||||||
|
"zero_copy_stream_test.cc", |
||||||
|
], |
||||||
|
deps = [ |
||||||
|
":chunked_stream", |
||||||
|
":zero_copy_stream", |
||||||
|
"//:upb", |
||||||
|
"@com_google_googletest//:gtest_main", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,4 @@ |
|||||||
|
This subdir originated as a best-effort C approximation of the C++ code in |
||||||
|
in third_party/protobuf/io/ but over time the two will invariably diverge. |
||||||
|
Comments have generally been copied verbatim and may therefore refer to C++ |
||||||
|
symbol names instead of C symbol names. |
@ -0,0 +1,110 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "upb/io/chunked_input_stream.h" |
||||||
|
|
||||||
|
// Must be last.
|
||||||
|
#include "upb/port_def.inc" |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
upb_ZeroCopyInputStream base; |
||||||
|
|
||||||
|
const char* data; |
||||||
|
size_t size; |
||||||
|
size_t limit; |
||||||
|
size_t position; |
||||||
|
size_t last_returned_size; |
||||||
|
} upb_ChunkedInputStream; |
||||||
|
|
||||||
|
static const void* upb_ChunkedInputStream_Next(upb_ZeroCopyInputStream* z, |
||||||
|
size_t* count, |
||||||
|
upb_Status* status) { |
||||||
|
upb_ChunkedInputStream* c = (upb_ChunkedInputStream*)z; |
||||||
|
UPB_ASSERT(c->position <= c->size); |
||||||
|
|
||||||
|
const char* out = c->data + c->position; |
||||||
|
|
||||||
|
const size_t chunk = UPB_MIN(c->limit, c->size - c->position); |
||||||
|
c->position += chunk; |
||||||
|
c->last_returned_size = chunk; |
||||||
|
*count = chunk; |
||||||
|
|
||||||
|
return chunk ? out : NULL; |
||||||
|
} |
||||||
|
|
||||||
|
static void upb_ChunkedInputStream_BackUp(upb_ZeroCopyInputStream* z, |
||||||
|
size_t count) { |
||||||
|
upb_ChunkedInputStream* c = (upb_ChunkedInputStream*)z; |
||||||
|
|
||||||
|
UPB_ASSERT(c->last_returned_size >= count); |
||||||
|
c->position -= count; |
||||||
|
c->last_returned_size -= count; |
||||||
|
} |
||||||
|
|
||||||
|
static bool upb_ChunkedInputStream_Skip(upb_ZeroCopyInputStream* z, |
||||||
|
size_t count) { |
||||||
|
upb_ChunkedInputStream* c = (upb_ChunkedInputStream*)z; |
||||||
|
|
||||||
|
c->last_returned_size = 0; // Don't let caller back up.
|
||||||
|
if (count > c->size - c->position) { |
||||||
|
c->position = c->size; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
c->position += count; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
static size_t upb_ChunkedInputStream_ByteCount( |
||||||
|
const upb_ZeroCopyInputStream* z) { |
||||||
|
const upb_ChunkedInputStream* c = (const upb_ChunkedInputStream*)z; |
||||||
|
|
||||||
|
return c->position; |
||||||
|
} |
||||||
|
|
||||||
|
static const _upb_ZeroCopyInputStream_VTable upb_ChunkedInputStream_vtable = { |
||||||
|
upb_ChunkedInputStream_Next, |
||||||
|
upb_ChunkedInputStream_BackUp, |
||||||
|
upb_ChunkedInputStream_Skip, |
||||||
|
upb_ChunkedInputStream_ByteCount, |
||||||
|
}; |
||||||
|
|
||||||
|
upb_ZeroCopyInputStream* upb_ChunkedInputStream_New(const void* data, |
||||||
|
size_t size, size_t limit, |
||||||
|
upb_Arena* arena) { |
||||||
|
upb_ChunkedInputStream* c = upb_Arena_Malloc(arena, sizeof(*c)); |
||||||
|
if (!c || !limit) return NULL; |
||||||
|
|
||||||
|
c->base.vtable = &upb_ChunkedInputStream_vtable; |
||||||
|
c->data = data; |
||||||
|
c->size = size; |
||||||
|
c->limit = limit; |
||||||
|
c->position = 0; |
||||||
|
c->last_returned_size = 0; |
||||||
|
|
||||||
|
return (upb_ZeroCopyInputStream*)c; |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_IO_CHUNKED_INPUT_STREAM_H_ |
||||||
|
#define UPB_IO_CHUNKED_INPUT_STREAM_H_ |
||||||
|
|
||||||
|
#include "upb/arena.h" |
||||||
|
#include "upb/io/zero_copy_input_stream.h" |
||||||
|
|
||||||
|
// Must be last.
|
||||||
|
#include "upb/port_def.inc" |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
// A ZeroCopyInputStream which wraps a flat buffer and limits the number of
|
||||||
|
// bytes that can be returned by a single call to Next().
|
||||||
|
upb_ZeroCopyInputStream* upb_ChunkedInputStream_New(const void* data, |
||||||
|
size_t size, size_t limit, |
||||||
|
upb_Arena* arena); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} /* extern "C" */ |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "upb/port_undef.inc" |
||||||
|
|
||||||
|
#endif /* UPB_IO_CHUNKED_INPUT_STREAM_H_ */ |
@ -0,0 +1,94 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "upb/io/chunked_output_stream.h" |
||||||
|
|
||||||
|
// Must be last.
|
||||||
|
#include "upb/port_def.inc" |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
upb_ZeroCopyOutputStream base; |
||||||
|
|
||||||
|
char* data; |
||||||
|
size_t size; |
||||||
|
size_t limit; |
||||||
|
size_t position; |
||||||
|
size_t last_returned_size; |
||||||
|
} upb_ChunkedOutputStream; |
||||||
|
|
||||||
|
static void* upb_ChunkedOutputStream_Next(upb_ZeroCopyOutputStream* z, |
||||||
|
size_t* count, upb_Status* status) { |
||||||
|
upb_ChunkedOutputStream* c = (upb_ChunkedOutputStream*)z; |
||||||
|
UPB_ASSERT(c->position <= c->size); |
||||||
|
|
||||||
|
char* out = c->data + c->position; |
||||||
|
|
||||||
|
const size_t chunk = UPB_MIN(c->limit, c->size - c->position); |
||||||
|
c->position += chunk; |
||||||
|
c->last_returned_size = chunk; |
||||||
|
*count = chunk; |
||||||
|
|
||||||
|
return chunk ? out : NULL; |
||||||
|
} |
||||||
|
|
||||||
|
static void upb_ChunkedOutputStream_BackUp(upb_ZeroCopyOutputStream* z, |
||||||
|
size_t count) { |
||||||
|
upb_ChunkedOutputStream* c = (upb_ChunkedOutputStream*)z; |
||||||
|
|
||||||
|
UPB_ASSERT(c->last_returned_size >= count); |
||||||
|
c->position -= count; |
||||||
|
c->last_returned_size -= count; |
||||||
|
} |
||||||
|
|
||||||
|
static size_t upb_ChunkedOutputStream_ByteCount( |
||||||
|
const upb_ZeroCopyOutputStream* z) { |
||||||
|
const upb_ChunkedOutputStream* c = (const upb_ChunkedOutputStream*)z; |
||||||
|
|
||||||
|
return c->position; |
||||||
|
} |
||||||
|
|
||||||
|
static const _upb_ZeroCopyOutputStream_VTable upb_ChunkedOutputStream_vtable = { |
||||||
|
upb_ChunkedOutputStream_Next, |
||||||
|
upb_ChunkedOutputStream_BackUp, |
||||||
|
upb_ChunkedOutputStream_ByteCount, |
||||||
|
}; |
||||||
|
|
||||||
|
upb_ZeroCopyOutputStream* upb_ChunkedOutputStream_New(void* data, size_t size, |
||||||
|
size_t limit, |
||||||
|
upb_Arena* arena) { |
||||||
|
upb_ChunkedOutputStream* c = upb_Arena_Malloc(arena, sizeof(*c)); |
||||||
|
if (!c || !limit) return NULL; |
||||||
|
|
||||||
|
c->base.vtable = &upb_ChunkedOutputStream_vtable; |
||||||
|
c->data = data; |
||||||
|
c->size = size; |
||||||
|
c->limit = limit; |
||||||
|
c->position = 0; |
||||||
|
c->last_returned_size = 0; |
||||||
|
|
||||||
|
return (upb_ZeroCopyOutputStream*)c; |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_IO_CHUNKED_OUTPUT_STREAM_H_ |
||||||
|
#define UPB_IO_CHUNKED_OUTPUT_STREAM_H_ |
||||||
|
|
||||||
|
#include "upb/arena.h" |
||||||
|
#include "upb/io/zero_copy_output_stream.h" |
||||||
|
|
||||||
|
// Must be last.
|
||||||
|
#include "upb/port_def.inc" |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
// A ZeroCopyOutputStream which wraps a flat buffer and limits the number of
|
||||||
|
// bytes that can be returned by a single call to Next().
|
||||||
|
upb_ZeroCopyOutputStream* upb_ChunkedOutputStream_New(void* data, size_t size, |
||||||
|
size_t limit, |
||||||
|
upb_Arena* arena); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} /* extern "C" */ |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "upb/port_undef.inc" |
||||||
|
|
||||||
|
#endif /* UPB_IO_CHUNKED_OUTPUT_STREAM_H_ */ |
@ -0,0 +1,129 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_IO_ZERO_COPY_INPUT_STREAM_H_ |
||||||
|
#define UPB_IO_ZERO_COPY_INPUT_STREAM_H_ |
||||||
|
|
||||||
|
#include "upb/status.h" |
||||||
|
|
||||||
|
// Must be last.
|
||||||
|
#include "upb/port_def.inc" |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
typedef struct upb_ZeroCopyInputStream upb_ZeroCopyInputStream; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
// Obtains a chunk of data from the stream.
|
||||||
|
//
|
||||||
|
// Preconditions:
|
||||||
|
// "count" and "status" are not NULL.
|
||||||
|
//
|
||||||
|
// Postconditions:
|
||||||
|
// All errors are permanent. If an error occurs then:
|
||||||
|
// - NULL will be returned to the caller.
|
||||||
|
// - *count will be set to zero.
|
||||||
|
// - *status will be set to the error.
|
||||||
|
// EOF is permanent. If EOF is reached then:
|
||||||
|
// - NULL will be returned to the caller.
|
||||||
|
// - *count will be set to zero.
|
||||||
|
// - *status will not be touched.
|
||||||
|
// Otherwise:
|
||||||
|
// - The returned value will point to a buffer containing the bytes read.
|
||||||
|
// - *count will be set to the number of bytes read.
|
||||||
|
// - *status will not be touched.
|
||||||
|
//
|
||||||
|
// Ownership of this buffer remains with the stream, and the buffer
|
||||||
|
// remains valid only until some other method of the stream is called
|
||||||
|
// or the stream is destroyed.
|
||||||
|
const void* (*Next)(struct upb_ZeroCopyInputStream* z, size_t* count, |
||||||
|
upb_Status* status); |
||||||
|
|
||||||
|
// Backs up a number of bytes, so that the next call to Next() returns
|
||||||
|
// data again that was already returned by the last call to Next(). This
|
||||||
|
// is useful when writing procedures that are only supposed to read up
|
||||||
|
// to a certain point in the input, then return. If Next() returns a
|
||||||
|
// buffer that goes beyond what you wanted to read, you can use BackUp()
|
||||||
|
// to return to the point where you intended to finish.
|
||||||
|
//
|
||||||
|
// Preconditions:
|
||||||
|
// * The last method called must have been Next().
|
||||||
|
// * count must be less than or equal to the size of the last buffer
|
||||||
|
// returned by Next().
|
||||||
|
//
|
||||||
|
// Postconditions:
|
||||||
|
// * The last "count" bytes of the last buffer returned by Next() will be
|
||||||
|
// pushed back into the stream. Subsequent calls to Next() will return
|
||||||
|
// the same data again before producing new data.
|
||||||
|
void (*BackUp)(struct upb_ZeroCopyInputStream* z, size_t count); |
||||||
|
|
||||||
|
// Skips a number of bytes. Returns false if the end of the stream is
|
||||||
|
// reached or some input error occurred. In the end-of-stream case, the
|
||||||
|
// stream is advanced to the end of the stream (so ByteCount() will return
|
||||||
|
// the total size of the stream).
|
||||||
|
bool (*Skip)(struct upb_ZeroCopyInputStream* z, size_t count); |
||||||
|
|
||||||
|
// Returns the total number of bytes read since this object was created.
|
||||||
|
size_t (*ByteCount)(const struct upb_ZeroCopyInputStream* z); |
||||||
|
} _upb_ZeroCopyInputStream_VTable; |
||||||
|
|
||||||
|
struct upb_ZeroCopyInputStream { |
||||||
|
const _upb_ZeroCopyInputStream_VTable* vtable; |
||||||
|
}; |
||||||
|
|
||||||
|
UPB_INLINE const void* upb_ZeroCopyInputStream_Next(upb_ZeroCopyInputStream* z, |
||||||
|
size_t* count, |
||||||
|
upb_Status* status) { |
||||||
|
const void* out = z->vtable->Next(z, count, status); |
||||||
|
UPB_ASSERT((out == NULL) == (*count == 0)); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
UPB_INLINE void upb_ZeroCopyInputStream_BackUp(upb_ZeroCopyInputStream* z, |
||||||
|
size_t count) { |
||||||
|
return z->vtable->BackUp(z, count); |
||||||
|
} |
||||||
|
|
||||||
|
UPB_INLINE bool upb_ZeroCopyInputStream_Skip(upb_ZeroCopyInputStream* z, |
||||||
|
size_t count) { |
||||||
|
return z->vtable->Skip(z, count); |
||||||
|
} |
||||||
|
|
||||||
|
UPB_INLINE size_t |
||||||
|
upb_ZeroCopyInputStream_ByteCount(const upb_ZeroCopyInputStream* z) { |
||||||
|
return z->vtable->ByteCount(z); |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} /* extern "C" */ |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "upb/port_undef.inc" |
||||||
|
|
||||||
|
#endif /* UPB_IO_ZERO_COPY_INPUT_STREAM_H_ */ |
@ -0,0 +1,130 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_IO_ZERO_COPY_OUTPUT_STREAM_H_ |
||||||
|
#define UPB_IO_ZERO_COPY_OUTPUT_STREAM_H_ |
||||||
|
|
||||||
|
#include "upb/status.h" |
||||||
|
|
||||||
|
// Must be last.
|
||||||
|
#include "upb/port_def.inc" |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
typedef struct upb_ZeroCopyOutputStream upb_ZeroCopyOutputStream; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
// Obtains a buffer into which data can be written. Any data written
|
||||||
|
// into this buffer will eventually (maybe instantly, maybe later on)
|
||||||
|
// be written to the output.
|
||||||
|
//
|
||||||
|
// Preconditions:
|
||||||
|
// "count" and "status" are not NULL.
|
||||||
|
//
|
||||||
|
// Postconditions:
|
||||||
|
// All errors are permanent. If an error occurs then:
|
||||||
|
// - NULL will be returned to the caller.
|
||||||
|
// - *count will be set to zero.
|
||||||
|
// - *status will be set to the error.
|
||||||
|
// EOF is permanent. If EOF is reached then:
|
||||||
|
// - NULL will be returned to the caller.
|
||||||
|
// - *count will be set to zero.
|
||||||
|
// - *status will not be touched.
|
||||||
|
// Otherwise:
|
||||||
|
// - The returned value will point to a buffer containing the bytes read.
|
||||||
|
// - *count will be set to the number of bytes read.
|
||||||
|
// - *status will not be touched.
|
||||||
|
//
|
||||||
|
// Ownership of this buffer remains with the stream, and the buffer
|
||||||
|
// remains valid only until some other method of the stream is called
|
||||||
|
// or the stream is destroyed.
|
||||||
|
//
|
||||||
|
// Any data which the caller stores in this buffer will eventually be
|
||||||
|
// written to the output (unless BackUp() is called).
|
||||||
|
void* (*Next)(struct upb_ZeroCopyOutputStream* z, size_t* count, |
||||||
|
upb_Status* status); |
||||||
|
|
||||||
|
// Backs up a number of bytes, so that the end of the last buffer returned
|
||||||
|
// by Next() is not actually written. This is needed when you finish
|
||||||
|
// writing all the data you want to write, but the last buffer was bigger
|
||||||
|
// than you needed. You don't want to write a bunch of garbage after the
|
||||||
|
// end of your data, so you use BackUp() to back up.
|
||||||
|
//
|
||||||
|
// Preconditions:
|
||||||
|
// * The last method called must have been Next().
|
||||||
|
// * count must be less than or equal to the size of the last buffer
|
||||||
|
// returned by Next().
|
||||||
|
// * The caller must not have written anything to the last "count" bytes
|
||||||
|
// of that buffer.
|
||||||
|
//
|
||||||
|
// Postconditions:
|
||||||
|
// * The last "count" bytes of the last buffer returned by Next() will be
|
||||||
|
// ignored.
|
||||||
|
//
|
||||||
|
// This method can be called with `count = 0` to finalize (flush) any
|
||||||
|
// previously returned buffer. For example, a file output stream can
|
||||||
|
// flush buffers returned from a previous call to Next() upon such
|
||||||
|
// BackUp(0) invocations. ZeroCopyOutputStream callers should always
|
||||||
|
// invoke BackUp() after a final Next() call, even if there is no
|
||||||
|
// excess buffer data to be backed up to indicate a flush point.
|
||||||
|
void (*BackUp)(struct upb_ZeroCopyOutputStream* z, size_t count); |
||||||
|
|
||||||
|
// Returns the total number of bytes written since this object was created.
|
||||||
|
size_t (*ByteCount)(const struct upb_ZeroCopyOutputStream* z); |
||||||
|
} _upb_ZeroCopyOutputStream_VTable; |
||||||
|
|
||||||
|
struct upb_ZeroCopyOutputStream { |
||||||
|
const _upb_ZeroCopyOutputStream_VTable* vtable; |
||||||
|
}; |
||||||
|
|
||||||
|
UPB_INLINE void* upb_ZeroCopyOutputStream_Next(upb_ZeroCopyOutputStream* z, |
||||||
|
size_t* count, |
||||||
|
upb_Status* status) { |
||||||
|
void* out = z->vtable->Next(z, count, status); |
||||||
|
UPB_ASSERT((out == NULL) == (*count == 0)); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
UPB_INLINE void upb_ZeroCopyOutputStream_BackUp(upb_ZeroCopyOutputStream* z, |
||||||
|
size_t count) { |
||||||
|
return z->vtable->BackUp(z, count); |
||||||
|
} |
||||||
|
|
||||||
|
UPB_INLINE size_t |
||||||
|
upb_ZeroCopyOutputStream_ByteCount(const upb_ZeroCopyOutputStream* z) { |
||||||
|
return z->vtable->ByteCount(z); |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} /* extern "C" */ |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "upb/port_undef.inc" |
||||||
|
|
||||||
|
#endif /* UPB_IO_ZERO_COPY_OUTPUT_STREAM_H_ */ |
@ -0,0 +1,290 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2022, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
// Testing strategy: For each type of I/O (array, string, file, etc.) we
|
||||||
|
// create an output stream and write some data to it, then create a
|
||||||
|
// corresponding input stream to read the same data back and expect it to
|
||||||
|
// match. When the data is written, it is written in several small chunks
|
||||||
|
// of varying sizes, with a BackUp() after each chunk. It is read back
|
||||||
|
// similarly, but with chunks separated at different points. The whole
|
||||||
|
// process is run with a variety of block sizes for both the input and
|
||||||
|
// the output.
|
||||||
|
|
||||||
|
#include "gtest/gtest.h" |
||||||
|
#include "upb/io/chunked_input_stream.h" |
||||||
|
#include "upb/io/chunked_output_stream.h" |
||||||
|
#include "upb/upb.hpp" |
||||||
|
|
||||||
|
namespace upb { |
||||||
|
namespace { |
||||||
|
|
||||||
|
class IoTest : public testing::Test { |
||||||
|
protected: |
||||||
|
// Test helpers.
|
||||||
|
|
||||||
|
// Helper to write an array of data to an output stream.
|
||||||
|
bool WriteToOutput(upb_ZeroCopyOutputStream* output, const void* data, |
||||||
|
int size); |
||||||
|
// Helper to read a fixed-length array of data from an input stream.
|
||||||
|
int ReadFromInput(upb_ZeroCopyInputStream* input, void* data, int size); |
||||||
|
// Write a string to the output stream.
|
||||||
|
void WriteString(upb_ZeroCopyOutputStream* output, const std::string& str); |
||||||
|
// Read a number of bytes equal to the size of the given string and checks
|
||||||
|
// that it matches the string.
|
||||||
|
void ReadString(upb_ZeroCopyInputStream* input, const std::string& str); |
||||||
|
// Writes some text to the output stream in a particular order. Returns
|
||||||
|
// the number of bytes written, in case the caller needs that to set up an
|
||||||
|
// input stream.
|
||||||
|
int WriteStuff(upb_ZeroCopyOutputStream* output); |
||||||
|
// Reads text from an input stream and expects it to match what
|
||||||
|
// WriteStuff() writes.
|
||||||
|
void ReadStuff(upb_ZeroCopyInputStream* input, bool read_eof = true); |
||||||
|
|
||||||
|
// Similar to WriteStuff, but performs more sophisticated testing.
|
||||||
|
int WriteStuffLarge(upb_ZeroCopyOutputStream* output); |
||||||
|
// Reads and tests a stream that should have been written to
|
||||||
|
// via WriteStuffLarge().
|
||||||
|
void ReadStuffLarge(upb_ZeroCopyInputStream* input); |
||||||
|
|
||||||
|
static const int kBlockSizes[]; |
||||||
|
static const int kBlockSizeCount; |
||||||
|
}; |
||||||
|
|
||||||
|
const int IoTest::kBlockSizes[] = {1, 2, 5, 7, 10, 23, 64}; |
||||||
|
const int IoTest::kBlockSizeCount = sizeof(IoTest::kBlockSizes) / sizeof(int); |
||||||
|
|
||||||
|
bool IoTest::WriteToOutput(upb_ZeroCopyOutputStream* output, const void* data, |
||||||
|
int size) { |
||||||
|
const uint8_t* in = reinterpret_cast<const uint8_t*>(data); |
||||||
|
size_t in_size = size; |
||||||
|
size_t out_size; |
||||||
|
|
||||||
|
while (true) { |
||||||
|
upb::Status status; |
||||||
|
void* out = upb_ZeroCopyOutputStream_Next(output, &out_size, status.ptr()); |
||||||
|
if (out_size == 0) return false; |
||||||
|
|
||||||
|
if (in_size <= out_size) { |
||||||
|
memcpy(out, in, in_size); |
||||||
|
upb_ZeroCopyOutputStream_BackUp(output, out_size - in_size); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
memcpy(out, in, out_size); |
||||||
|
in += out_size; |
||||||
|
in_size -= out_size; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int IoTest::ReadFromInput(upb_ZeroCopyInputStream* input, void* data, |
||||||
|
int size) { |
||||||
|
uint8_t* out = reinterpret_cast<uint8_t*>(data); |
||||||
|
size_t out_size = size; |
||||||
|
|
||||||
|
const void* in; |
||||||
|
size_t in_size = 0; |
||||||
|
|
||||||
|
while (true) { |
||||||
|
upb::Status status; |
||||||
|
in = upb_ZeroCopyInputStream_Next(input, &in_size, status.ptr()); |
||||||
|
|
||||||
|
if (in_size == 0) { |
||||||
|
return size - out_size; |
||||||
|
} |
||||||
|
|
||||||
|
if (out_size <= in_size) { |
||||||
|
memcpy(out, in, out_size); |
||||||
|
if (in_size > out_size) { |
||||||
|
upb_ZeroCopyInputStream_BackUp(input, in_size - out_size); |
||||||
|
} |
||||||
|
return size; // Copied all of it.
|
||||||
|
} |
||||||
|
|
||||||
|
memcpy(out, in, in_size); |
||||||
|
out += in_size; |
||||||
|
out_size -= in_size; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void IoTest::WriteString(upb_ZeroCopyOutputStream* output, |
||||||
|
const std::string& str) { |
||||||
|
EXPECT_TRUE(WriteToOutput(output, str.c_str(), str.size())); |
||||||
|
} |
||||||
|
|
||||||
|
void IoTest::ReadString(upb_ZeroCopyInputStream* input, |
||||||
|
const std::string& str) { |
||||||
|
std::unique_ptr<char[]> buffer(new char[str.size() + 1]); |
||||||
|
buffer[str.size()] = '\0'; |
||||||
|
EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size()); |
||||||
|
EXPECT_STREQ(str.c_str(), buffer.get()); |
||||||
|
} |
||||||
|
|
||||||
|
int IoTest::WriteStuff(upb_ZeroCopyOutputStream* output) { |
||||||
|
WriteString(output, "Hello world!\n"); |
||||||
|
WriteString(output, "Some te"); |
||||||
|
WriteString(output, "xt. Blah blah."); |
||||||
|
WriteString(output, "abcdefg"); |
||||||
|
WriteString(output, "01234567890123456789"); |
||||||
|
WriteString(output, "foobar"); |
||||||
|
|
||||||
|
const int result = upb_ZeroCopyOutputStream_ByteCount(output); |
||||||
|
EXPECT_EQ(result, 68); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// Reads text from an input stream and expects it to match what WriteStuff()
|
||||||
|
// writes.
|
||||||
|
void IoTest::ReadStuff(upb_ZeroCopyInputStream* input, bool read_eof) { |
||||||
|
ReadString(input, "Hello world!\n"); |
||||||
|
ReadString(input, "Some text. "); |
||||||
|
ReadString(input, "Blah "); |
||||||
|
ReadString(input, "blah."); |
||||||
|
ReadString(input, "abcdefg"); |
||||||
|
EXPECT_TRUE(upb_ZeroCopyInputStream_Skip(input, 20)); |
||||||
|
ReadString(input, "foo"); |
||||||
|
ReadString(input, "bar"); |
||||||
|
|
||||||
|
EXPECT_EQ(upb_ZeroCopyInputStream_ByteCount(input), 68); |
||||||
|
|
||||||
|
if (read_eof) { |
||||||
|
uint8_t byte; |
||||||
|
EXPECT_EQ(ReadFromInput(input, &byte, 1), 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int IoTest::WriteStuffLarge(upb_ZeroCopyOutputStream* output) { |
||||||
|
WriteString(output, "Hello world!\n"); |
||||||
|
WriteString(output, "Some te"); |
||||||
|
WriteString(output, "xt. Blah blah."); |
||||||
|
WriteString(output, std::string(100000, 'x')); // A very long string
|
||||||
|
WriteString(output, std::string(100000, 'y')); // A very long string
|
||||||
|
WriteString(output, "01234567890123456789"); |
||||||
|
|
||||||
|
const int result = upb_ZeroCopyOutputStream_ByteCount(output); |
||||||
|
EXPECT_EQ(result, 200055); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// Reads text from an input stream and expects it to match what WriteStuff()
|
||||||
|
// writes.
|
||||||
|
void IoTest::ReadStuffLarge(upb_ZeroCopyInputStream* input) { |
||||||
|
ReadString(input, "Hello world!\nSome text. "); |
||||||
|
EXPECT_TRUE(upb_ZeroCopyInputStream_Skip(input, 5)); |
||||||
|
ReadString(input, "blah."); |
||||||
|
EXPECT_TRUE(upb_ZeroCopyInputStream_Skip(input, 100000 - 10)); |
||||||
|
ReadString(input, std::string(10, 'x') + std::string(100000 - 20000, 'y')); |
||||||
|
EXPECT_TRUE(upb_ZeroCopyInputStream_Skip(input, 20000 - 10)); |
||||||
|
ReadString(input, "yyyyyyyyyy01234567890123456789"); |
||||||
|
EXPECT_EQ(upb_ZeroCopyInputStream_ByteCount(input), 200055); |
||||||
|
|
||||||
|
uint8_t byte; |
||||||
|
EXPECT_EQ(ReadFromInput(input, &byte, 1), 0); |
||||||
|
} |
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
TEST_F(IoTest, ArrayIo) { |
||||||
|
const int kBufferSize = 256; |
||||||
|
uint8_t buffer[kBufferSize]; |
||||||
|
|
||||||
|
upb::Arena arena; |
||||||
|
for (int i = 0; i < kBlockSizeCount; i++) { |
||||||
|
for (int j = 0; j < kBlockSizeCount; j++) { |
||||||
|
auto output = upb_ChunkedOutputStream_New(buffer, kBufferSize, |
||||||
|
kBlockSizes[j], arena.ptr()); |
||||||
|
int size = WriteStuff(output); |
||||||
|
auto input = |
||||||
|
upb_ChunkedInputStream_New(buffer, size, kBlockSizes[j], arena.ptr()); |
||||||
|
ReadStuff(input); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ChunkedStream, SingleInput) { |
||||||
|
const int kBufferSize = 256; |
||||||
|
uint8_t buffer[kBufferSize]; |
||||||
|
upb::Arena arena; |
||||||
|
auto input = |
||||||
|
upb_ChunkedInputStream_New(buffer, kBufferSize, kBufferSize, arena.ptr()); |
||||||
|
const void* data; |
||||||
|
size_t size; |
||||||
|
|
||||||
|
upb::Status status; |
||||||
|
data = upb_ZeroCopyInputStream_Next(input, &size, status.ptr()); |
||||||
|
EXPECT_EQ(size, kBufferSize); |
||||||
|
|
||||||
|
data = upb_ZeroCopyInputStream_Next(input, &size, status.ptr()); |
||||||
|
EXPECT_EQ(data, nullptr); |
||||||
|
EXPECT_EQ(size, 0); |
||||||
|
EXPECT_TRUE(upb_Status_IsOk(status.ptr())); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ChunkedStream, SingleOutput) { |
||||||
|
const int kBufferSize = 256; |
||||||
|
uint8_t buffer[kBufferSize]; |
||||||
|
upb::Arena arena; |
||||||
|
auto output = upb_ChunkedOutputStream_New(buffer, kBufferSize, kBufferSize, |
||||||
|
arena.ptr()); |
||||||
|
size_t size; |
||||||
|
upb::Status status; |
||||||
|
void* data = upb_ZeroCopyOutputStream_Next(output, &size, status.ptr()); |
||||||
|
EXPECT_EQ(size, kBufferSize); |
||||||
|
|
||||||
|
data = upb_ZeroCopyOutputStream_Next(output, &size, status.ptr()); |
||||||
|
EXPECT_EQ(data, nullptr); |
||||||
|
EXPECT_EQ(size, 0); |
||||||
|
EXPECT_TRUE(upb_Status_IsOk(status.ptr())); |
||||||
|
} |
||||||
|
|
||||||
|
// Check that a zero-size input array doesn't confuse the code.
|
||||||
|
TEST(ChunkedStream, InputEOF) { |
||||||
|
upb::Arena arena; |
||||||
|
char buf; |
||||||
|
auto input = upb_ChunkedInputStream_New(&buf, 0, 1, arena.ptr()); |
||||||
|
size_t size; |
||||||
|
upb::Status status; |
||||||
|
const void* data = upb_ZeroCopyInputStream_Next(input, &size, status.ptr()); |
||||||
|
EXPECT_EQ(data, nullptr); |
||||||
|
EXPECT_EQ(size, 0); |
||||||
|
EXPECT_TRUE(upb_Status_IsOk(status.ptr())); |
||||||
|
} |
||||||
|
|
||||||
|
// Check that a zero-size output array doesn't confuse the code.
|
||||||
|
TEST(ChunkedStream, OutputEOF) { |
||||||
|
upb::Arena arena; |
||||||
|
char buf; |
||||||
|
auto output = upb_ChunkedOutputStream_New(&buf, 0, 1, arena.ptr()); |
||||||
|
size_t size; |
||||||
|
upb::Status status; |
||||||
|
void* data = upb_ZeroCopyOutputStream_Next(output, &size, status.ptr()); |
||||||
|
EXPECT_EQ(data, nullptr); |
||||||
|
EXPECT_EQ(size, 0); |
||||||
|
EXPECT_TRUE(upb_Status_IsOk(status.ptr())); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace upb
|
Loading…
Reference in new issue