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 new options to ArrayList FindString, FindValue #2216

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
109 changes: 94 additions & 15 deletions core/logic/smn_adt_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,27 +587,68 @@ static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}

// the blocknumber is not guaranteed to always be passed
// The parameters above 2 are optional

size_t blocknumber = 0;
if (params[0] >= 3)
{
blocknumber = (size_t)params[3];
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
}

if (blocknumber >= array->blocksize())
int startidx = -1;
if (params[0] >= 4)
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
startidx = params[4];
if (startidx > 0 && startidx > array->size())
{
return pContext->ThrowNativeError("Invalid start index %d (max: %d)", startidx, array->size());
}
}

bool reverse = false;
if (params[0] >= 5)
{
reverse = params[5];
}

typedef int (*STRCOMPARE)(const char *, const char *);
STRCOMPARE comparefn = (params[0] < 6 || params[6]) ? strcmp : strcasecmp;

char *str;
pContext->LocalToString(params[2], &str);

for (unsigned int i = 0; i < array->size(); i++)
if (reverse)
{
if (startidx < 0)
{
startidx = array->size();
}
for (int i = (startidx - 1); i >= 0; i--)
{
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
if (comparefn(str, array_str) == 0)
{
return (cell_t) i;
}
}
}
else
{
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
if (strcmp(str, array_str) == 0)
if (startidx < -1)
{
startidx = -1;
}
for (unsigned int i = (startidx + 1); i < array->size(); i++)
{
return (cell_t) i;
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
if (comparefn(str, array_str) == 0)
{
return (cell_t) i;
}
}
}

Expand All @@ -626,24 +667,62 @@ static cell_t FindValueInArray(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}

// the blocknumber is not guaranteed to always be passed
// The parameters above 2 are optional

size_t blocknumber = 0;
if (params[0] >= 3)
{
blocknumber = (size_t) params[3];
blocknumber = (size_t)params[3];
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
}

if (blocknumber >= array->blocksize())
int startidx = -1;
if (params[0] >= 4)
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
startidx = params[4];
if (startidx > 0 && startidx > array->size())
{
return pContext->ThrowNativeError("Invalid start index %d (max: %d)", startidx, array->size());
}
}

for (unsigned int i = 0; i < array->size(); i++)
bool reverse = false;
if (params[0] >= 5)
{
cell_t *blk = array->at(i);
if (params[2] == blk[blocknumber])
reverse = params[5];
}

if (reverse)
{
if (startidx < 0)
{
startidx = array->size();
}
for (int i = (startidx - 1); i >= 0; i--)
{
cell_t *blk = array->at(i);
if (params[2] == blk[blocknumber])
{
return (cell_t) i;
}
}
}
else
{
if (startidx < -1)
{
startidx = -1;
}
for (unsigned int i = (startidx + 1); i < array->size(); i++)
{
return (cell_t) i;
cell_t *blk = array->at(i);
if (params[2] == blk[blocknumber])
{
return (cell_t) i;
}
}
}

Expand Down
25 changes: 17 additions & 8 deletions plugins/include/adt_array.inc
Original file line number Diff line number Diff line change
Expand Up @@ -207,19 +207,28 @@ methodmap ArrayList < Handle {
// Returns the index for the first occurrence of the provided string. If
// the string cannot be located, -1 will be returned.
//
// @param item String to search for
// @param block Optionally which block to search in
// @param item String to search for.
// @param block Optionally which block to search in.
// @param start Index to start searching from (exclusive), or -1 for direction default.
// Valid numbers are in the interval [-1..Length].
// @param reverse Whether the search direction should be reversed.
// @param caseSensitive If true (default), comparison is case sensitive.
// If false, comparison is case insensitive.
// @return Array index, or -1 on failure
public native int FindString(const char[] item, int block=0);
// @error Invalid block, or invalid start index.
public native int FindString(const char[] item, int block=0, int start=-1, bool reverse=false, bool caseSensitive=true);

// Returns the index for the first occurrence of the provided value. If the
// value cannot be located, -1 will be returned.
//
// @param item Value to search for
// @param block Optionally which block to search in
// @return Array index, or -1 on failure
// @error Invalid block index
public native int FindValue(any item, int block=0);
// @param item Value to search for.
// @param block Optionally which block to search in.
// @param start Index to start searching from (exclusive), or -1 for direction default.
// Valid numbers are in the interval [-1..Length].
// @param reverse Whether the search direction should be reversed.
// @return Array index, or -1 on failure.
// @error Invalid block, or invalid start index.
public native int FindValue(any item, int block=0, int start=-1, bool reverse=false);

// Sort an ADT Array. Specify the type as Integer, Float, or String.
//
Expand Down
141 changes: 141 additions & 0 deletions plugins/testsuite/mock/test_arraylist_find.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#pragma semicolon 1
#pragma newdecls required
#include <testing>

enum struct TestStruct
{
int intval;
char strval[32];
}

public void OnPluginStart()
{
ArrayList list = new ArrayList(sizeof(TestStruct));

// --------------------------------------------------------------------------------

SetTestContext("EmptyArrayTest");

AssertEq("test_forward", list.FindString("index3", TestStruct::strval, -1, false), -1);
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, -1, true), -1);
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, -1, false), -1);
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, -1, true), -1);

// --------------------------------------------------------------------------------

// Fill
TestStruct ts;
for (int i = 0; i < 10; i++)
{
ts.intval = i;
Format(ts.strval, sizeof(ts.strval), "index%d", i);
list.PushArray(ts);
}

// --------------------------------------------------------------------------------

SetTestContext("FindString");

AssertEq("test_defaults", list.FindString("index3", TestStruct::strval), 3);

AssertEq("test_forward", list.FindString("index3", TestStruct::strval, -1, false), 3);
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 0, false), 3);
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 2, false), 3);
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 3, false), -1);
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 10, false), -1);

AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, -1, true), 3);
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 0, true), -1);
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 3, true), -1);
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 4, true), 3);
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 10, true), 3);

AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, -1, false), 0);
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, -1, true), 0);
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, 1, true), 0);
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, 10, false), -1);
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, 10, true), 0);

AssertEq("test_top", list.FindString("index9", TestStruct::strval, -1, false), 9);
AssertEq("test_top", list.FindString("index9", TestStruct::strval, -1, true), 9);
AssertEq("test_top", list.FindString("index9", TestStruct::strval, 8, false), 9);
AssertEq("test_top", list.FindString("index9", TestStruct::strval, 10, false), -1);
AssertEq("test_top", list.FindString("index9", TestStruct::strval, 10, true), 9);

AssertEq("test_case_sensitive", list.FindString("INDEX0", TestStruct::strval, .caseSensitive = true), -1);
AssertEq("test_case_sensitive", list.FindString("INDEX0", TestStruct::strval, .caseSensitive = false), 0);

// --------------------------------------------------------------------------------

SetTestContext("FindValue");

AssertEq("test_defaults", list.FindValue(3, TestStruct::intval), 3);

AssertEq("test_forward", list.FindValue(3, TestStruct::intval, -1, false), 3);
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 0, false), 3);
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 2, false), 3);
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 3, false), -1);
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 10, false), -1);

AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, -1, true), 3);
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 0, true), -1);
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 3, true), -1);
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 4, true), 3);
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 10, true), 3);

AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, -1, false), 0);
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, -1, true), 0);
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, 1, true), 0);
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, 10, false), -1);
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, 10, true), 0);

AssertEq("test_top", list.FindValue(9, TestStruct::intval, -1, false), 9);
AssertEq("test_top", list.FindValue(9, TestStruct::intval, -1, true), 9);
AssertEq("test_top", list.FindValue(9, TestStruct::intval, 8, false), 9);
AssertEq("test_top", list.FindValue(9, TestStruct::intval, 10, false), -1);
AssertEq("test_top", list.FindValue(9, TestStruct::intval, 10, true), 9);

// --------------------------------------------------------------------------------

SetTestContext("IterateOverFindString");
int found, index;

// Duplicate last entry
list.PushArray(ts);

found = 0; index = -1;
while ((index = list.FindString("index9", TestStruct::strval, index, false)) != -1)
{
found++;
}
AssertEq("test_find_all_strings_forward", found, 2);

found = 0; index = -1;
while ((index = list.FindString("index9", TestStruct::strval, index, true)) != -1)
{
found++;
}
AssertEq("test_find_all_strings_reverse", found, 2);

// --------------------------------------------------------------------------------

SetTestContext("IterateOverFindValue");

found = 0, index = -1;
while ((index = list.FindValue(9, TestStruct::intval, index, false)) != -1)
{
found++;
}
AssertEq("test_find_all_values_forward", found, 2);

found = 0; index = -1;
while ((index = list.FindValue(9, TestStruct::intval, index, true)) != -1)
{
found++;
}
AssertEq("test_find_all_values_reverse", found, 2);

// --------------------------------------------------------------------------------

PrintToServer("OK");
}