diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenlib/BLI_listbase.h | 4 | ||||
-rw-r--r-- | source/blender/blenlib/intern/listbase.c | 31 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_listbase_test.cc | 58 |
3 files changed, 93 insertions, 0 deletions
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 345d9d93d03..cf525d1c2af 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -55,6 +55,10 @@ void *BLI_listbase_bytes_find(const ListBase *listbase, const void *bytes, const size_t bytes_size, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); +void *BLI_listbase_string_or_index_find(const struct ListBase *listbase, + const char *string, + const size_t string_offset, + const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); /* find backwards */ void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 1b16f6b0aee..443bef42cc2 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -826,6 +826,37 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase, } /** + * Find the first item in the list that matches the given string, or the given index as fallback. + * + * \note The string is only used is non-NULL and non-empty. + * + * \return The found item, or NULL. + */ +void *BLI_listbase_string_or_index_find(const ListBase *listbase, + const char *string, + const size_t string_offset, + const int index) +{ + Link *link = NULL; + Link *link_at_index = NULL; + + int index_iter; + for (link = listbase->first, index_iter = 0; link; link = link->next, index_iter++) { + if (string != NULL && string[0] != '\0') { + const char *string_iter = ((const char *)link) + string_offset; + + if (string[0] == string_iter[0] && STREQ(string, string_iter)) { + return link; + } + } + if (index_iter == index) { + link_at_index = link; + } + } + return link_at_index; +} + +/** * Returns the 0-based index of the first element of listbase which contains the specified * null-terminated string at the specified offset, or -1 if not found. */ diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc index 0ba08a0cd48..d66eb214902 100644 --- a/source/blender/blenlib/tests/BLI_listbase_test.cc +++ b/source/blender/blenlib/tests/BLI_listbase_test.cc @@ -96,6 +96,64 @@ TEST(listbase, FindLinkOrIndex) BLI_freelistN(&lb); } +TEST(listbase, FindLinkFromStringOrPointer) +{ + struct TestLink { + struct TestLink *prev, *next; + char name[64]; + const void *ptr; + }; + + const char *const link1_name = "Link1"; + const char *const link2_name = "Link2"; + const void *const link1_ptr = nullptr; + const void *const link2_ptr = link2_name; + + const size_t name_offset = offsetof(struct TestLink, name); + const size_t ptr_offset = offsetof(struct TestLink, ptr); + + ListBase lb; + struct TestLink *link1 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link1"); + BLI_strncpy(link1->name, link1_name, sizeof(link1->name)); + link1->ptr = link1_ptr; + struct TestLink *link2 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link2"); + BLI_strncpy(link2->name, link2_name, sizeof(link2->name)); + link2->ptr = link2_ptr; + + /* Empty list */ + BLI_listbase_clear(&lb); + EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)nullptr); + EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)nullptr); + EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)nullptr); + EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)nullptr); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)nullptr); + + /* One link */ + BLI_addtail(&lb, link1); + EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, "", name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)nullptr); + + /* Two links */ + BLI_addtail(&lb, link2); + EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link2_name, name_offset, 0), (void *)link2); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)link2); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, -1), (void *)nullptr); + + BLI_freelistN(&lb); +} + /* -------------------------------------------------------------------- */ /* Sort utilities & test */ |