BLI_listbase: Add utils to search from string or index.

If a valid matching string is found, return that item, otherwise
fallback to the item matching the given index, if any.

This will be useful in RNA override code, and potentially other
areas where data in lists can be referenced by their names or indices.
This commit is contained in:
Bastien Montagne 2021-11-19 14:39:40 +01:00
parent 04ec36f677
commit d6ea881a74
3 changed files with 93 additions and 0 deletions

View File

@ -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

View File

@ -825,6 +825,37 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
return NULL;
}
/**
* 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.

View File

@ -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 */