Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function rcutils_string_array_cmp #144

Merged
merged 3 commits into from
May 8, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions include/rcutils/types/string_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ RCUTILS_WARN_UNUSED
rcutils_ret_t
rcutils_string_array_fini(rcutils_string_array_t * string_array);

/// Compare two string arrays.
/**
* The two string arrays are compared according to lexographical order.
*
* \param[in] sa0 The first string array.
* \param[in] sa1 The second string array.
* \param[out] res Negative value if `lhs` appears before `rhs` in lexographical order.
* Zero if `lhs` and `rhs` are equal.
* Positive value if `lhs` appears after `rhs in lexographical order.
* \return `RCUTILS_RET_OK` if successful, or
* \return `RCUTILS_RET_INVALID_ARGUMENT` if there is an invalid arguments, or
* \return `RCUTILS_RET_ERROR` if an unknown error occurs.
*/
RCUTILS_PUBLIC
RCUTILS_WARN_UNUSED
rcutils_ret_t
rcutils_string_array_cmp(
const rcutils_string_array_t * lhs,
const rcutils_string_array_t * rhs,
int * res);

#ifdef __cplusplus
}
#endif
Expand Down
48 changes: 48 additions & 0 deletions src/string_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern "C"
#endif

#include <stdlib.h>
#include <string.h>

#include "rcutils/allocator.h"
#include "rcutils/error_handling.h"
Expand Down Expand Up @@ -87,6 +88,53 @@ rcutils_string_array_fini(rcutils_string_array_t * string_array)
return RCUTILS_RET_OK;
}

rcutils_ret_t
rcutils_string_array_cmp(
const rcutils_string_array_t * lhs,
const rcutils_string_array_t * rhs,
int * res)
{
if (NULL == lhs || NULL == rhs) {
RCUTILS_SET_ERROR_MSG("string_array is null");
return RCUTILS_RET_INVALID_ARGUMENT;
}
if (NULL == lhs->data || NULL == rhs->data) {
RCUTILS_SET_ERROR_MSG("string_array data is null");
return RCUTILS_RET_INVALID_ARGUMENT;
}
if (NULL == res) {
RCUTILS_SET_ERROR_MSG("res argument is null");
return RCUTILS_RET_INVALID_ARGUMENT;
}

size_t smallest_size = lhs->size;
if (rhs->size < smallest_size) {
smallest_size = rhs->size;
}

for (size_t i = 0; i < smallest_size; ++i) {
if (NULL == lhs->data[i] || NULL == rhs->data[i]) {
RCUTILS_SET_ERROR_MSG("string_array element is null");
return RCUTILS_RET_ERROR;
}
// Loop until we find a pair of strings that are not equal
int strcmp_res = strcmp(lhs->data[i], rhs->data[i]);
if (0 != strcmp_res) {
*res = strcmp_res;
return RCUTILS_RET_OK;
}
}

// If all strings equal, compare array sizes
*res = 0;
if (lhs->size < rhs->size) {
*res = -1;
} else if (lhs->size > rhs->size) {
*res = 1;
}
return RCUTILS_RET_OK;
}

#ifdef __cplusplus
}
#endif
72 changes: 72 additions & 0 deletions test/test_string_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,75 @@ TEST(test_string_array, boot_string_array) {
ret = rcutils_string_array_fini(&sa2);
ASSERT_EQ(RCUTILS_RET_OK, ret);
}

TEST(test_string_array, string_array_cmp) {
auto allocator = rcutils_get_default_allocator();
rcutils_ret_t ret = RCUTILS_RET_OK;
int res = 0;

// Initialize some string arrays
rcutils_string_array_t sa0 = rcutils_get_zero_initialized_string_array();
ret = rcutils_string_array_init(&sa0, 3, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);
sa0.data[0] = strdup("foo");
sa0.data[1] = strdup("bar");
sa0.data[2] = strdup("baz");

rcutils_string_array_t sa1 = rcutils_get_zero_initialized_string_array();
ret = rcutils_string_array_init(&sa1, 3, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);
sa1.data[0] = strdup("foo");
sa1.data[1] = strdup("bar");
sa1.data[2] = strdup("baz");

rcutils_string_array_t sa2 = rcutils_get_zero_initialized_string_array();
ret = rcutils_string_array_init(&sa2, 3, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);
sa2.data[0] = strdup("foo");
sa2.data[1] = strdup("baz");
sa2.data[2] = strdup("bar");

rcutils_string_array_t sa3 = rcutils_get_zero_initialized_string_array();
ret = rcutils_string_array_init(&sa3, 2, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);
sa3.data[0] = strdup("foo");
sa3.data[1] = strdup("bar");

rcutils_string_array_t incomplete_string_array = rcutils_get_zero_initialized_string_array();
ret = rcutils_string_array_init(&incomplete_string_array, 3, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);

// Test failure cases
EXPECT_EQ(RCUTILS_RET_INVALID_ARGUMENT, rcutils_string_array_cmp(NULL, &sa0, &res));
EXPECT_EQ(RCUTILS_RET_INVALID_ARGUMENT, rcutils_string_array_cmp(&sa0, NULL, &res));
EXPECT_EQ(RCUTILS_RET_INVALID_ARGUMENT, rcutils_string_array_cmp(&sa0, &sa1, NULL));
EXPECT_EQ(RCUTILS_RET_ERROR, rcutils_string_array_cmp(&sa0, &incomplete_string_array, &res));

// Test success cases
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa0, &sa1, &res));
EXPECT_EQ(res, 0);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa1, &sa0, &res));
EXPECT_EQ(res, 0);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa0, &sa2, &res));
EXPECT_LT(res, 0);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa2, &sa0, &res));
EXPECT_GT(res, 0);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa0, &sa3, &res));
EXPECT_GT(res, 0);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa3, &sa0, &res));
EXPECT_LT(res, 0);
// Test transitivity
EXPECT_EQ(RCUTILS_RET_OK, rcutils_string_array_cmp(&sa3, &sa2, &res));
EXPECT_LT(res, 0);

ret = rcutils_string_array_fini(&sa0);
ASSERT_EQ(RCUTILS_RET_OK, ret);
ret = rcutils_string_array_fini(&sa1);
ASSERT_EQ(RCUTILS_RET_OK, ret);
ret = rcutils_string_array_fini(&sa2);
ASSERT_EQ(RCUTILS_RET_OK, ret);
ret = rcutils_string_array_fini(&sa3);
ASSERT_EQ(RCUTILS_RET_OK, ret);
ret = rcutils_string_array_fini(&incomplete_string_array);
ASSERT_EQ(RCUTILS_RET_OK, ret);
}