From b6481654ba03bdcbffd260e052a12a3fef7a0906 Mon Sep 17 00:00:00 2001 From: Joshua DeWeese Date: Tue, 29 Aug 2023 14:39:37 -0400 Subject: [PATCH] core/lib/cib: add several new peek functions This patch adds calls to be able to peek at items other than just the oldest item in a cib based FIFO. It also adds an "unsafe" peek to match the existing "unsafe" put and get functions. --- core/lib/include/cib.h | 67 ++++++++++++++++-- tests/unittests/tests-core/tests-core-cib.c | 78 +++++++++++++++++++++ 2 files changed, 139 insertions(+), 6 deletions(-) diff --git a/core/lib/include/cib.h b/core/lib/include/cib.h index c807b6049b..9d3b8e98dc 100644 --- a/core/lib/include/cib.h +++ b/core/lib/include/cib.h @@ -119,20 +119,75 @@ static inline int cib_get(cib_t *__restrict cib) return -1; } +/** + * @brief Get the index of an item in the buffer without removing anything. + * + * Offset 0 is the next item in the buffer that would be returned by + * `cip_get()`, offset 1 would be the following, and so on. + * + * Unsafe version, *must not* pass an offset that is larger than the number of + * items currently in the buffer! + * + * @param[in,out] cib corresponding *cib* to buffer. + * Must not be NULL. + * @param[in] offset offset from front of buffer + * + * @return index of item + * @retval -1 if no item at @p offset exists in the buffer + */ +static inline int cib_peek_at_unsafe(cib_t *__restrict cib, unsigned offset) +{ + return (cib->read_count + offset) & cib->mask; +} + +/** + * @brief Get the index of an item in the buffer without removing anything. + * + * Offset 0 is the next item in the buffer that would be returned by + * `cip_get()`, offset 1 would be the following, and so on. + * + * @param[in,out] cib corresponding *cib* to buffer. + * Must not be NULL. + * @param[in] offset offset from front of buffer + * + * @return index of item + * @retval -1 if no item at @p offset exists in the buffer + */ +static inline int cib_peek_at(cib_t *__restrict cib, unsigned offset) +{ + if (offset < cib_avail(cib)) { + return cib_peek_at_unsafe(cib, offset); + } + + return -1; +} + +/** + * @brief Get the index of the next item in buffer without removing it. + * + * Unsafe version, *must not* be called if buffer is empty! + * + * @param[in,out] cib corresponding *cib* to buffer. + * Must not be NULL. + * @return index of next item + * @retval -1 if the buffer is empty + */ +static inline int cib_peek_unsafe(cib_t *__restrict cib) +{ + return cib_peek_at_unsafe(cib, 0); +} + /** * @brief Get the index of the next item in buffer without removing it. * * @param[in,out] cib corresponding *cib* to buffer. * Must not be NULL. - * @return index of next item, -1 if the buffer is empty + * @return index of next item + * @retval -1 if the buffer is empty */ static inline int cib_peek(cib_t *__restrict cib) { - if (cib_avail(cib)) { - return (int)(cib->read_count & cib->mask); - } - - return -1; + return cib_peek_at(cib, 0); } /** diff --git a/tests/unittests/tests-core/tests-core-cib.c b/tests/unittests/tests-core/tests-core-cib.c index 40d3a69ea6..7c5d70ddbf 100644 --- a/tests/unittests/tests-core/tests-core-cib.c +++ b/tests/unittests/tests-core/tests-core-cib.c @@ -72,6 +72,83 @@ static void test_cib_peek__overflow(void) TEST_ASSERT_EQUAL_INT(TEST_CIB_SIZE-1, cib_peek(&cib)); } +static void test_cib_peek_at(void) +{ + /* Peeking an empty cib should give an error */ + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 0)); + + /* Put 1 item in cib and check that we can peek it */ + TEST_ASSERT_EQUAL_INT( 0, cib_put(&cib)); + TEST_ASSERT_EQUAL_INT( 0, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 0, cib_peek_at(&cib, 0)); + + /* Peek past the end should give an error. */ + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 1)); + + /* Put another item in cib. */ + TEST_ASSERT_EQUAL_INT( 1, cib_put(&cib)); + + /* cib should now hold the indices { 0, 1 }. Test this. */ + TEST_ASSERT_EQUAL_INT( 0, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 0, cib_peek_at(&cib, 0)); + TEST_ASSERT_EQUAL_INT( 1, cib_peek_at(&cib, 1)); + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 2)); + + /* Put another item in cib. */ + TEST_ASSERT_EQUAL_INT( 2, cib_put(&cib)); + + /* cib should now hold the indices { 0, 1, 2 }. Test this. */ + TEST_ASSERT_EQUAL_INT( 0, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 0, cib_peek_at(&cib, 0)); + TEST_ASSERT_EQUAL_INT( 1, cib_peek_at(&cib, 1)); + TEST_ASSERT_EQUAL_INT( 2, cib_peek_at(&cib, 2)); + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 3)); + + /* Put another item in cib. */ + TEST_ASSERT_EQUAL_INT( 3, cib_put(&cib)); + + /* cib should now hold the indices { 0, 1, 2, 3 }. Test this. */ + TEST_ASSERT_EQUAL_INT( 0, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 0, cib_peek_at(&cib, 0)); + TEST_ASSERT_EQUAL_INT( 1, cib_peek_at(&cib, 1)); + TEST_ASSERT_EQUAL_INT( 2, cib_peek_at(&cib, 2)); + TEST_ASSERT_EQUAL_INT( 3, cib_peek_at(&cib, 3)); + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 4)); + + /* Remove an item from cib. */ + TEST_ASSERT_EQUAL_INT( 0, cib_get(&cib)); + + /* cib should now hold the indices { 1, 2, 3 }. Test this. */ + TEST_ASSERT_EQUAL_INT( 1, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 1, cib_peek_at(&cib, 0)); + TEST_ASSERT_EQUAL_INT( 2, cib_peek_at(&cib, 1)); + TEST_ASSERT_EQUAL_INT( 3, cib_peek_at(&cib, 2)); + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 3)); + + /* Remove another item from cib. */ + TEST_ASSERT_EQUAL_INT( 1, cib_get(&cib)); + + /* cib should now hold the indices { 2, 3 }. Test this. */ + TEST_ASSERT_EQUAL_INT( 2, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 2, cib_peek_at(&cib, 0)); + TEST_ASSERT_EQUAL_INT( 3, cib_peek_at(&cib, 1)); + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 2)); + + /* Remove another item from cib. */ + TEST_ASSERT_EQUAL_INT( 2, cib_get(&cib)); + + /* cib should now hold the indices { 3 }. Test this. */ + TEST_ASSERT_EQUAL_INT( 3, cib_peek(&cib)); + TEST_ASSERT_EQUAL_INT( 3, cib_peek_at(&cib, 0)); + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 1)); + + /* Remove last item from cib. */ + TEST_ASSERT_EQUAL_INT( 3, cib_get(&cib)); + + /* Peeking an empty cib should give an error */ + TEST_ASSERT_EQUAL_INT(-1, cib_peek_at(&cib, 0)); +} + static void test_cib_avail(void) { TEST_ASSERT_EQUAL_INT(0, cib_avail(&cib)); @@ -111,6 +188,7 @@ Test *tests_core_cib_tests(void) new_TestFixture(test_singleton_cib), new_TestFixture(test_cib_peek), new_TestFixture(test_cib_peek__overflow), + new_TestFixture(test_cib_peek_at), }; EMB_UNIT_TESTCALLER(core_cib_tests, set_up, NULL, fixtures);