forked from Mirrors/openclonk
C4Script: Accept array parameter for Min, Max
Min/Max with array parameter will return the smallest/largest value of all elements of the array. If any array element is not an integer, nor convertible to integer, the function will fail.objectmenu
parent
b7cffa5e82
commit
4fddda20f9
|
@ -23,11 +23,29 @@
|
|||
</params>
|
||||
</syntax>
|
||||
<desc>Returns the greater of two values.</desc>
|
||||
</func>
|
||||
<func>
|
||||
<title>Max</title>
|
||||
<category>Arithmetics</category>
|
||||
<version>7.0 OC</version>
|
||||
<syntax>
|
||||
<rtype>int</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>array</type>
|
||||
<name>values</name>
|
||||
<desc>array of integers</desc>
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>
|
||||
Returns the largest value from an array. All array elements must be
|
||||
integers (or convertible to integer).
|
||||
</desc>
|
||||
<related>
|
||||
<funclink>Min</funclink>
|
||||
<funclink>Inside</funclink>
|
||||
<funclink>BoundBy</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>PeterW</author><date>2001-12</date>
|
||||
</funcs>
|
||||
|
|
|
@ -23,11 +23,30 @@
|
|||
</params>
|
||||
</syntax>
|
||||
<desc>Returns the lesser of two values.</desc>
|
||||
</func>
|
||||
<func>
|
||||
<title>Min</title>
|
||||
<category>Arithmetics</category>
|
||||
<version>7.0 OC</version>
|
||||
<syntax>
|
||||
<rtype>int</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>array</type>
|
||||
<name>values</name>
|
||||
<desc>array of integers</desc>
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>
|
||||
Returns the smallest value from an array. All array elements must be
|
||||
integers (or convertible to integer).
|
||||
</desc>
|
||||
|
||||
<related>
|
||||
<funclink>Max</funclink>
|
||||
<funclink>Inside</funclink>
|
||||
<funclink>BoundBy</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>PeterW</author><date>2001-12</date>
|
||||
</funcs>
|
||||
|
|
|
@ -47,6 +47,7 @@ class Nillable
|
|||
public:
|
||||
inline Nillable(const T &value) : _nil(!value && !C4Value::IsNullableType(C4ValueConv<T>::Type())), _val(value) {}
|
||||
inline Nillable() : _nil(true), _val(T()) {}
|
||||
inline Nillable(std::nullptr_t) : _nil(true), _val(T()) {}
|
||||
template <typename T2> inline Nillable(const Nillable<T2> & n2) : _nil(n2._nil), _val(n2._val) {}
|
||||
inline Nillable(const Nillable<void> & n2) : _nil(true), _val(T()) {}
|
||||
inline bool IsNil() const { return _nil; }
|
||||
|
|
|
@ -458,14 +458,56 @@ static long FnArcCos(C4PropList * _this, long iVal, long iRadius)
|
|||
return (long) floor(f1+0.5);
|
||||
}
|
||||
|
||||
static long FnMin(C4PropList * _this, long iVal1, long iVal2)
|
||||
static std::pair<Nillable<int32_t>, Nillable<int32_t>> minmax(const char *func, const C4Value &a_val, const Nillable<int32_t> &b_opt)
|
||||
{
|
||||
return std::min(iVal1,iVal2);
|
||||
if (a_val.CheckConversion(C4V_Int))
|
||||
{
|
||||
int32_t a = a_val.getInt();
|
||||
int32_t b = b_opt;
|
||||
if (a > b)
|
||||
std::swap(a, b);
|
||||
return std::make_pair(a, b);
|
||||
}
|
||||
else if (a_val.CheckConversion(C4V_Array))
|
||||
{
|
||||
const C4ValueArray *a = a_val.getArray();
|
||||
if (a->GetSize() == 0)
|
||||
return std::make_pair(nullptr, nullptr);
|
||||
|
||||
if (!a->GetItem(0).CheckConversion(C4V_Int))
|
||||
{
|
||||
throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but element %d of array is of type %s", func, 0, a->GetItem(0).GetTypeName()).getData());
|
||||
}
|
||||
int32_t min, max;
|
||||
min = max = a->GetItem(0).getInt();
|
||||
|
||||
for (int32_t i = 1; i < a->GetSize(); ++i)
|
||||
{
|
||||
if (!a->GetItem(i).CheckConversion(C4V_Int))
|
||||
{
|
||||
throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but element %d of array is of type %s", func, i, a->GetItem(i).GetTypeName()).getData());
|
||||
}
|
||||
int32_t value = a->GetItem(i).getInt();
|
||||
min = std::min(min, value);
|
||||
max = std::max(max, value);
|
||||
}
|
||||
|
||||
return std::make_pair(min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but is of type %s", func, a_val.GetTypeName()).getData());
|
||||
}
|
||||
}
|
||||
|
||||
static long FnMax(C4PropList * _this, long iVal1, long iVal2)
|
||||
static Nillable<int32_t> FnMin(C4PropList * _this, const C4Value &a, Nillable<int32_t> b)
|
||||
{
|
||||
return std::max(iVal1,iVal2);
|
||||
return minmax("Min", a, b).first;
|
||||
}
|
||||
|
||||
static Nillable<int32_t> FnMax(C4PropList * _this, const C4Value &a, Nillable<int32_t> b)
|
||||
{
|
||||
return minmax("Max", a, b).second;
|
||||
}
|
||||
|
||||
static long FnDistance(C4PropList * _this, long iX1, long iY1, long iX2, long iY2)
|
||||
|
|
|
@ -38,8 +38,9 @@ TEST_F(AulPredefFunctionTest, Translate)
|
|||
EXPECT_EQ(C4VString("a"), RunExpr("Translate(\"a\")"));
|
||||
}
|
||||
|
||||
TEST_F(AulPredefFunctionTest, Min)
|
||||
TEST_F(AulPredefFunctionTest, Min_int_int)
|
||||
{
|
||||
// Test that Min(int, int) returns the smaller of two values.
|
||||
EXPECT_EQ(C4VInt(0), RunExpr("Min(0, 1)"));
|
||||
EXPECT_EQ(C4VInt(0), RunExpr("Min(1, 0)"));
|
||||
|
||||
|
@ -53,8 +54,39 @@ TEST_F(AulPredefFunctionTest, Min)
|
|||
EXPECT_EQ(C4VInt(0), RunExpr("Min(0, 2147483647)"));
|
||||
}
|
||||
|
||||
TEST_F(AulPredefFunctionTest, Max)
|
||||
TEST_F(AulPredefFunctionTest, Min_array)
|
||||
{
|
||||
// Test that Min(array<int>) returns the smallest array item.
|
||||
EXPECT_EQ(C4VNull, RunExpr("Min([])"));
|
||||
|
||||
EXPECT_EQ(C4VInt(0), RunExpr("Min([0, 1, 2])"));
|
||||
EXPECT_EQ(C4VInt(0), RunExpr("Min([2, 1, 0])"));
|
||||
|
||||
EXPECT_EQ(C4VInt(-1), RunExpr("Min([-1, 0, 1])"));
|
||||
EXPECT_EQ(C4VInt(-1), RunExpr("Min([1, 0, -1])"));
|
||||
|
||||
EXPECT_EQ(C4VINT_MIN, RunExpr("Min([-2147483648, 0, 2147483647])"));
|
||||
EXPECT_EQ(C4VINT_MIN, RunExpr("Min([2147483647, 0, -2147483648])"));
|
||||
}
|
||||
|
||||
TEST_F(AulPredefFunctionTest, Min_Invalid)
|
||||
{
|
||||
// Test that Min(array) fails if any item is not (convertible to) int.
|
||||
EXPECT_THROW(RunExpr("Min([[]])"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr("Min([0, []])"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr("Min([0, 1, {}])"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr(R"(Min([0, ""]))"), C4AulExecError);
|
||||
|
||||
// Test that Min(a, b) fails if a or b are not (convertible to) int.
|
||||
EXPECT_THROW(RunExpr("Min({}, 1)"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr("Min(0, {})"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr(R"(Min("", 1))"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr(R"(Min(0, ""))"), C4AulExecError);
|
||||
}
|
||||
|
||||
TEST_F(AulPredefFunctionTest, Max_int_int)
|
||||
{
|
||||
// Test that Max(int, int) returns the larger of two values.
|
||||
EXPECT_EQ(C4VInt(1), RunExpr("Max(0, 1)"));
|
||||
EXPECT_EQ(C4VInt(1), RunExpr("Max(1, 0)"));
|
||||
|
||||
|
@ -67,3 +99,33 @@ TEST_F(AulPredefFunctionTest, Max)
|
|||
EXPECT_EQ(C4VINT_MAX, RunExpr("Max(2147483647, 0)"));
|
||||
EXPECT_EQ(C4VINT_MAX, RunExpr("Max(0, 2147483647)"));
|
||||
}
|
||||
|
||||
TEST_F(AulPredefFunctionTest, Max_array)
|
||||
{
|
||||
// Test that Max(array<int>) returns the largest array item.
|
||||
EXPECT_EQ(C4VNull, RunExpr("Max([])"));
|
||||
|
||||
EXPECT_EQ(C4VInt(2), RunExpr("Max([0, 1, 2])"));
|
||||
EXPECT_EQ(C4VInt(2), RunExpr("Max([2, 1, 0])"));
|
||||
|
||||
EXPECT_EQ(C4VInt(1), RunExpr("Max([-1, 0, 1])"));
|
||||
EXPECT_EQ(C4VInt(1), RunExpr("Max([1, 0, -1])"));
|
||||
|
||||
EXPECT_EQ(C4VINT_MAX, RunExpr("Max([-2147483648, 0, 2147483647])"));
|
||||
EXPECT_EQ(C4VINT_MAX, RunExpr("Max([2147483647, 0, -2147483648])"));
|
||||
}
|
||||
|
||||
TEST_F(AulPredefFunctionTest, Max_Invalid)
|
||||
{
|
||||
// Test that Max(array) fails if any item is not (convertible to) int.
|
||||
EXPECT_THROW(RunExpr("Max([[]])"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr("Max([0, []])"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr("Max([0, 1, {}])"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr(R"(Max([0, ""]))"), C4AulExecError);
|
||||
|
||||
// Test that Max(a, b) fails if a or b are not (convertible to) int.
|
||||
EXPECT_THROW(RunExpr("Max({}, 1)"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr("Max(0, {})"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr(R"(Max("", 1))"), C4AulExecError);
|
||||
EXPECT_THROW(RunExpr(R"(Max(0, ""))"), C4AulExecError);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue