Skip to content

Commit

Permalink
Added function for finding the first substring/character in a string.
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsAsplund committed Dec 12, 2015
1 parent 02a7897 commit 39295b7
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 4 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def find_all_files(directory, endings=None):

setup(
name='vunit_hdl',
version='0.47.0',
version='0.48.0',
packages=['vunit',
'vunit.com',
'vunit.test',
Expand Down
104 changes: 101 additions & 3 deletions vunit/vhdl/string_ops/src/string_ops.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ package string_ops is
constant start : natural := 0;
constant stop : natural := 0)
return natural;
function find (
constant s : string;
constant substring : string;
constant start : natural := 0;
constant stop : natural := 0)
return natural;
function find (
constant s : string;
constant char : character;
constant start : natural := 0;
constant stop : natural := 0)
return natural;
function strip (
str : string;
chars : string := " ")
Expand Down Expand Up @@ -116,16 +128,48 @@ package body string_ops is
end if;
end function offset;

function in_range (
function index (
constant s : string;
constant offset : natural)
return positive is
begin
if s'ascending then
return s'left + offset;
else
return s'left - offset;
end if;
end function index;

function left_of_range (
constant s : string;
constant index : natural)
return boolean is
begin
if s'ascending then
return (index >= s'left) and (index <= s'right);
return (index < s'left);
else
return (index <= s'left) and (index >= s'right);
return (index > s'left);
end if;
end function left_of_range;

function right_of_range (
constant s : string;
constant index : natural)
return boolean is
begin
if s'ascending then
return (index > s'right);
else
return (index < s'right);
end if;
end function right_of_range;

function in_range (
constant s : string;
constant index : natural)
return boolean is
begin
return not left_of_range(s, index) and not right_of_range(s, index);
end function in_range;

function slice (
Expand Down Expand Up @@ -448,6 +492,60 @@ package body string_ops is
return n;
end count;

function find (
constant s : string;
constant char : character;
constant start : natural := 0;
constant stop : natural := 0)
return natural is
variable substring : string(1 to 1);
begin
substring(1) := char;
return find(s, substring, start, stop);
end;

function find (
constant s : string;
constant substring : string;
constant start : natural := 0;
constant stop : natural := 0)
return natural is
variable start_pos, stop_pos : natural;
variable o : natural;
begin
if start = 0 or left_of_range(s, start) then
start_pos := s'left;
elsif right_of_range(s, start) then
return 0;
else
start_pos := start;
end if;

if stop = 0 or right_of_range(s, stop) then
stop_pos := s'right;
elsif left_of_range(s, stop) then
return 0;
else
stop_pos := stop;
end if;

if substring = "" then
return start_pos;
end if;

o := offset(s, start_pos);
while o <= offset(s, stop_pos) - substring'length + 1 loop
if slice(s, o, substring'length) = substring then
return index(s, o);
end if;

o := o + 1;
end loop;

return 0;

end find;

impure function split (
constant s : string;
constant sep : string;
Expand Down
40 changes: 40 additions & 0 deletions vunit/vhdl/string_ops/test/tb_string_ops.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,46 @@ begin
counting_assert(count(reverse_string, "a", 12 ,4) = 0, "Should not find anything outside of the string");
counting_assert(count("aba", "a", 3 ,1) = 0, "Should not find anything within a negative range");
counting_assert(count("aba", "abab") = 0, "Should not find anything when substring is longer than the string");
elsif run("Test find") then
counting_assert(find("", "") = 1, "Empty string should be found at the start");
counting_assert(find("foo bar", "") = 1, "Empty string should be found at the start");
counting_assert(find("foo bar", "foo") = 1, "Should find string at the start");
counting_assert(find("foo bar", "bar") = 5, "Should find string at the end");
counting_assert(find("foo bar", "o b") = 3, "Should find string in the middle");
counting_assert(find("foo bar", "foo bar") = 1, "Should find full string");
counting_assert(find("foo bar", 'f') = 1, "Should find character at the start");
counting_assert(find("foo bar", 'r') = 7, "Should find character at the end");
counting_assert(find("foo bar", ' ') = 4, "Should find character in the middle");
counting_assert(find("foo bar", "bars") = 0, "Should return 0 when string not found");
counting_assert(find("foo bar", "foo bars") = 0, "Should return 0 when string not found");
counting_assert(find("foo bar", 'q') = 0, "Should return 0 when character not found");
counting_assert(find(offset_string, "") = 10, "Empty string should be found at the start on offset string");
counting_assert(find(offset_string, "foo") = 10, "Should find string at the start on offset string");
counting_assert(find(offset_string, "bar") = 14, "Should find string at the end on offset string");
counting_assert(find(offset_string, "o b") = 12, "Should find string in the middle on offset string");
counting_assert(find(reverse_string, "") = 16, "Empty string should be found at the start on reversed string");
counting_assert(find(reverse_string, "foo") = 16, "Should find string at the start on reversed string");
counting_assert(find(reverse_string, "bar") = 12, "Should find string at the end on reversed string");
counting_assert(find(reverse_string, "o b") = 14, "Should find string in the middle on reversed string");
counting_assert(find("foo bar", "oo", 2, 6) = 2, "Should find string at the start of slice");
counting_assert(find("foo bar", "ba", 2, 6) = 5, "Should find string at the end of slice");
counting_assert(find("foo bar", "o b", 2, 6) = 3, "Should find string in the middle of slice");
counting_assert(find("foo bar", "", 2, 6) = 2, "Empty string should be found at the start of slice");
counting_assert(find("foo bar", 'f', 2, 6) = 0, "Should not find anything before slice");
counting_assert(find("foo bar", "ar", 2, 6) = 0, "Should not find anything after slice");
counting_assert(find(offset_string, 'f', 11, 15) = 0, "Should not find anything before slice in offset string");
counting_assert(find(offset_string, "ar", 11, 15) = 0, "Should not find anything after slice in offset string");
counting_assert(find(reverse_string, 'f', 15, 11) = 0, "Should not find anything before slice in reversed string");
counting_assert(find(reverse_string, "ar", 15, 11) = 0, "Should not find anything after slice in reversed string");
counting_assert(find("foo bar", "o b", 1, 100) = 3, "Should find in ranges wider than input'range");
counting_assert(find("foo bar", "zen", 1, 100) = 0, "Should not find in ranges wider than input'range");
counting_assert(find(offset_string, "o b", 1, 100) = 12, "Should find in ranges wider than input'range");
counting_assert(find(offset_string, "zen", 1, 100) = 0, "Should not find in ranges wider than input'range");
counting_assert(find(reverse_string, "o b", 100, 1) = 14, "Should find in ranges wider than input'range");
counting_assert(find(reverse_string, "zen", 100, 1) = 0, "Should not find in ranges wider than input'range");
counting_assert(find("foo bar", "o b", 3, 2) = 0, "Should not find string in negative range");
counting_assert(find("foo bar", "o b", 30, 0) = 0, "Should not find string in negative range");
counting_assert(find(reverse_string, "o b", 1, 100) = 0, "Should not find string in negative range");

elsif run("Test image") then
counting_assert(image("") = "", "Should return empty string on empty input vector.");
Expand Down

0 comments on commit 39295b7

Please sign in to comment.