Skip to content

Commit

Permalink
added naive string find function. (#543)
Browse files Browse the repository at this point in the history
* added naive string find function.
  • Loading branch information
JonathanHenson authored Nov 11, 2019
1 parent f5da2a7 commit e069ac2
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 0 deletions.
12 changes: 12 additions & 0 deletions include/aws/common/byte_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,18 @@ int aws_byte_cursor_split_on_char_n(
size_t n,
struct aws_array_list *AWS_RESTRICT output);

/**
* Search for an exact byte match inside a cursor. The first match will be returned. Returns AWS_OP_SUCCESS
* on successful match and first_find will be set to the offset in input_str, and length will be the remaining length
* from input_str past the returned offset. If the match was not found, AWS_OP_ERR will be returned and
* AWS_ERROR_STRING_MATCH_NOT_FOUND will be raised.
*/
AWS_COMMON_API
int aws_byte_cursor_find_exact(
const struct aws_byte_cursor *AWS_RESTRICT input_str,
const struct aws_byte_cursor *AWS_RESTRICT to_find,
struct aws_byte_cursor *first_find);

/**
*
* Shrinks a byte cursor from the right for as long as the supplied predicate is true
Expand Down
1 change: 1 addition & 0 deletions include/aws/common/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ enum aws_common_error {
AWS_ERROR_MAX_FDS_EXCEEDED,
AWS_ERROR_SYS_CALL_FAILURE,
AWS_ERROR_C_STRING_BUFFER_NOT_NULL_TERMINATED,
AWS_ERROR_STRING_MATCH_NOT_FOUND,

AWS_ERROR_END_COMMON_RANGE = 0x03FF
};
Expand Down
38 changes: 38 additions & 0 deletions source/byte_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,44 @@ int aws_byte_cursor_split_on_char(
return aws_byte_cursor_split_on_char_n(input_str, split_on, 0, output);
}

int aws_byte_cursor_find_exact(
const struct aws_byte_cursor *AWS_RESTRICT input_str,
const struct aws_byte_cursor *AWS_RESTRICT to_find,
struct aws_byte_cursor *first_find) {
if (to_find->len > input_str->len) {
return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
}

if (to_find->len < 1) {
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
}

struct aws_byte_cursor working_cur = *input_str;

while (working_cur.len) {
uint8_t *first_char_location = memchr(working_cur.ptr, (char)*to_find->ptr, working_cur.len);

if (!first_char_location) {
return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
}

aws_byte_cursor_advance(&working_cur, first_char_location - working_cur.ptr);

if (working_cur.len < to_find->len) {
return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
}

if (!memcmp(working_cur.ptr, to_find->ptr, to_find->len)) {
*first_find = working_cur;
return AWS_OP_SUCCESS;
}

aws_byte_cursor_advance(&working_cur, 1);
}

return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
}

int aws_byte_buf_cat(struct aws_byte_buf *dest, size_t number_of_args, ...) {
AWS_PRECONDITION(aws_byte_buf_is_valid(dest));

Expand Down
3 changes: 3 additions & 0 deletions source/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ static struct aws_error_info errors[] = {
AWS_DEFINE_ERROR_INFO_COMMON(
AWS_ERROR_C_STRING_BUFFER_NOT_NULL_TERMINATED,
"A c-string like buffer was passed but a null terminator was not found within the bounds of the buffer."),
AWS_DEFINE_ERROR_INFO_COMMON(
AWS_ERROR_STRING_MATCH_NOT_FOUND,
"The specified substring was not present in the input string."),
};
/* clang-format on */

Expand Down
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ add_test_case(test_byte_buf_reset)
add_test_case(test_byte_cursor_compare_lexical)
add_test_case(test_byte_cursor_compare_lookup)

add_test_case(test_byte_cursor_find_str)
add_test_case(test_byte_cursor_find_str_not_found)
add_test_case(test_byte_cursor_find_str_longer_than_input)

add_test_case(byte_swap_test)
add_test_case(alignment_test)

Expand Down
82 changes: 82 additions & 0 deletions tests/byte_cursor_find_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

#include <aws/common/byte_buf.h>
#include <aws/testing/aws_test_harness.h>

static int s_test_byte_cursor_find_str_fn(struct aws_allocator *allocator, void *ctx) {
(void)allocator;
(void)ctx;

const char *string_with_match = "This is a string and we want to find a substring of it.";
const char *to_find = "and we want";

struct aws_byte_cursor string_with_match_cur = aws_byte_cursor_from_c_str(string_with_match);
struct aws_byte_cursor to_find_cur = aws_byte_cursor_from_c_str(to_find);

struct aws_byte_cursor find_res;
AWS_ZERO_STRUCT(find_res);

ASSERT_SUCCESS(aws_byte_cursor_find_exact(&string_with_match_cur, &to_find_cur, &find_res));
ASSERT_BIN_ARRAYS_EQUALS(to_find_cur.ptr, to_find_cur.len, find_res.ptr, to_find_cur.len);
ASSERT_UINT_EQUALS(string_with_match_cur.len - (find_res.ptr - string_with_match_cur.ptr), find_res.len);
ASSERT_PTR_EQUALS(string_with_match_cur.ptr + (find_res.ptr - string_with_match_cur.ptr), find_res.ptr);

return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(test_byte_cursor_find_str, s_test_byte_cursor_find_str_fn)

static int s_test_byte_cursor_find_str_not_found_fn(struct aws_allocator *allocator, void *ctx) {
(void)allocator;
(void)ctx;

const char *string_with_match = "This is a string and we want to find a substring of it.";
const char *to_find = "and we went";

struct aws_byte_cursor string_with_match_cur = aws_byte_cursor_from_c_str(string_with_match);
struct aws_byte_cursor to_find_cur = aws_byte_cursor_from_c_str(to_find);

struct aws_byte_cursor find_res;
AWS_ZERO_STRUCT(find_res);

ASSERT_ERROR(
AWS_ERROR_STRING_MATCH_NOT_FOUND, aws_byte_cursor_find_exact(&string_with_match_cur, &to_find_cur, &find_res));

return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(test_byte_cursor_find_str_not_found, s_test_byte_cursor_find_str_not_found_fn)

static int s_test_byte_cursor_find_str_longer_than_input_fn(struct aws_allocator *allocator, void *ctx) {
(void)allocator;
(void)ctx;

const char *string_with_match = "This ";
const char *to_find = "and we want";

struct aws_byte_cursor string_with_match_cur = aws_byte_cursor_from_c_str(string_with_match);
struct aws_byte_cursor to_find_cur = aws_byte_cursor_from_c_str(to_find);

struct aws_byte_cursor find_res;
AWS_ZERO_STRUCT(find_res);

ASSERT_ERROR(
AWS_ERROR_STRING_MATCH_NOT_FOUND, aws_byte_cursor_find_exact(&string_with_match_cur, &to_find_cur, &find_res));

return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(test_byte_cursor_find_str_longer_than_input, s_test_byte_cursor_find_str_longer_than_input_fn)

0 comments on commit e069ac2

Please sign in to comment.