From 4001560d9bc3d665fe767d06b3a7fb1727afe31c Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Tue, 14 Mar 2023 17:28:39 +0100 Subject: [input_buffer] Read while --- source/kit/input_buffer.c | 73 ++++++++++++++++++++++++++----- source/kit/input_buffer.h | 7 +++ source/test/unittests/input_buffer.test.c | 48 ++++++++++++++++++++ 3 files changed, 116 insertions(+), 12 deletions(-) (limited to 'source') diff --git a/source/kit/input_buffer.c b/source/kit/input_buffer.c index b9f280b..8ac7755 100644 --- a/source/kit/input_buffer.c +++ b/source/kit/input_buffer.c @@ -98,23 +98,72 @@ kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream, kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, ptrdiff_t size) { kit_ib_handle_t next; memset(&next, 0, sizeof next); + if (buf.status != KIT_OK) { next.status = buf.status; - } else { - buf_acquire(buf.internal); - buf_adjust(buf.internal, buf.offset + size); - DA_INIT(next.data, size, buf_alloc(buf.internal)); - if (next.data.size != size) - next.status = KIT_ERROR_BAD_ALLOC; - kit_out_str_t destination = { .size = next.data.size, + return next; + } + + buf_acquire(buf.internal); + buf_adjust(buf.internal, buf.offset + size); + + DA_INIT(next.data, size, buf_alloc(buf.internal)); + if (next.data.size != size) + next.status = KIT_ERROR_BAD_ALLOC; + + kit_out_str_t destination = { .size = next.data.size, .values = next.data.values }; - ptrdiff_t n = buf_read(buf.internal, buf.offset, destination); - next.offset = buf.offset + n; - next.internal = buf.internal; - DA_RESIZE(next.data, n); - if (next.data.size != n) + ptrdiff_t const n = buf_read(buf.internal, buf.offset, destination); + next.offset = buf.offset + n; + next.internal = buf.internal; + + DA_RESIZE(next.data, n); + if (next.data.size != n) + next.status = KIT_ERROR_BAD_ALLOC; + + return next; +} + +kit_ib_handle_t kit_ib_read_while( + kit_ib_handle_t buf, kit_ib_read_condition_fn condition) { + kit_ib_handle_t next; + memset(&next, 0, sizeof next); + + if (buf.status != KIT_OK) { + next.status = buf.status; + return next; + } + + buf_acquire(buf.internal); + + DA_INIT(next.data, 0, buf_alloc(buf.internal)); + + ptrdiff_t size = 0; + + for (;; ++size) { + buf_adjust(buf.internal, buf.offset + size + 1); + + DA_RESIZE(next.data, size + 1); + if (next.data.size != size + 1) next.status = KIT_ERROR_BAD_ALLOC; + + kit_out_str_t destination = { .size = 1, + .values = next.data.values + size }; + ptrdiff_t const n = buf_read(buf.internal, buf.offset + size, + destination); + + kit_str_t data = { .size = size + 1, .values = next.data.values }; + if (n != 1 || condition == NULL || condition(data) == 0) + break; } + + next.offset = buf.offset + size; + next.internal = buf.internal; + + DA_RESIZE(next.data, size); + if (next.data.size != size) + next.status = KIT_ERROR_BAD_ALLOC; + return next; } diff --git a/source/kit/input_buffer.h b/source/kit/input_buffer.h index 1b4329f..60b4872 100644 --- a/source/kit/input_buffer.h +++ b/source/kit/input_buffer.h @@ -21,6 +21,11 @@ kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream, kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, ptrdiff_t size); +typedef int (*kit_ib_read_condition_fn)(kit_str_t data); + +kit_ib_handle_t kit_ib_read_while(kit_ib_handle_t buf, + kit_ib_read_condition_fn condition); + void kit_ib_destroy(kit_ib_handle_t buf); #define KIT_IB_WRAP(upstream) \ @@ -28,8 +33,10 @@ void kit_ib_destroy(kit_ib_handle_t buf); #ifndef KIT_DISABLE_SHORT_NAMES # define ib_handle_t kit_ib_handle_t +# define ib_read_condition_fn kit_ib_read_condition_fn # define ib_wrap kit_ib_wrap # define ib_read kit_ib_read +# define ib_read_while kit_ib_read_while # define ib_destroy kit_ib_destroy # define IB_WRAP KIT_IB_WRAP diff --git a/source/test/unittests/input_buffer.test.c b/source/test/unittests/input_buffer.test.c index f1b3738..c062052 100644 --- a/source/test/unittests/input_buffer.test.c +++ b/source/test/unittests/input_buffer.test.c @@ -55,3 +55,51 @@ TEST("input buffer read twice") { ib_destroy(first); is_destroy(in); } + +static int is_integer_(str_t const data) { + for (ptrdiff_t i = 0; i < data.size; i++) + if (data.values[i] < '0' || data.values[i] > '9') + return 0; + return 1; +} + +TEST("input buffer read integer once") { + str_t text = { .size = 9, .values = "31415 foo" }; + str_t num = { .size = 5, .values = "31415" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read_while(first, is_integer_); + + REQUIRE(second.status == KIT_OK); + REQUIRE(second.data.size == 5); + REQUIRE(AR_EQUAL(num, second.data)); + + ib_destroy(second); + ib_destroy(first); + is_destroy(in); +} + +TEST("input buffer read integer twice") { + str_t text = { .size = 6, .values = "314 15" }; + str_t num_0 = { .size = 3, .values = "314" }; + str_t num_1 = { .size = 2, .values = "15" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read_while(first, is_integer_); + ib_handle_t third = ib_read(second, 1); + ib_handle_t fourth = ib_read_while(third, is_integer_); + + REQUIRE(fourth.status == KIT_OK); + REQUIRE(second.data.size == 3); + REQUIRE(fourth.data.size == 2); + REQUIRE(AR_EQUAL(num_0, second.data)); + REQUIRE(AR_EQUAL(num_1, fourth.data)); + + ib_destroy(first); + ib_destroy(second); + ib_destroy(third); + ib_destroy(fourth); + is_destroy(in); +} -- cgit v1.2.3