Add conversion between set and vector using 'as' keyword

This commit is contained in:
Tim Wojtulewicz 2023-07-14 13:35:26 -07:00
parent 59f7b26b51
commit af9e852c28
8 changed files with 157 additions and 0 deletions

5
NEWS
View file

@ -43,6 +43,11 @@ New Functionality
modules by prefixing their names with ``::``. Previously, these required an
explicit ``GLOBAL::`` prefix to be used. Using ``GLOBAL::`` has been deprecated.
- The ``as`` keyword now supports casting between ``set`` and ``vector`` values
with the same element type. Converting ``set`` values with multiple index
values is not supported. We plan to extend the use of the ``as`` keyword to
support more type conversions in the future.
Changed Functionality
---------------------

View file

@ -4262,9 +4262,74 @@ ValPtr cast_value_to_type(Val* v, Type* t)
return static_cast<Broker::detail::DataVal*>(dv.get())->castTo(t);
}
// Allow casting between sets and vectors if the yield types are the same.
if ( v->GetType()->IsSet() && IsVector(t->Tag()) )
{
auto set_type = v->GetType<SetType>();
auto indices = set_type->GetIndices();
if ( indices->GetTypes().size() > 1 || ! indices->IsPure() )
return nullptr;
auto ret_type = IntrusivePtr<VectorType>{NewRef{}, t->AsVectorType()};
auto ret = make_intrusive<VectorVal>(ret_type);
auto lv = v->AsTableVal()->ToPureListVal();
auto n = lv->Length();
for ( int i = 0; i < n; ++i )
ret->Assign(i, lv->Idx(i));
return ret;
}
else if ( IsVector(v->GetType()->Tag()) && t->IsSet() )
{
auto ret_type = IntrusivePtr<TableType>{NewRef{}, t->AsSetType()};
auto ret = make_intrusive<TableVal>(ret_type);
auto vv = v->AsVectorVal();
size_t size = vv->Size();
for ( size_t i = 0; i < size; i++ )
{
auto ve = vv->ValAt(i);
ret->Assign(std::move(ve), nullptr);
}
return ret;
}
return nullptr;
}
static bool can_cast_set_and_vector(const Type* t1, const Type* t2)
{
const TableType* st = nullptr;
const VectorType* vt = nullptr;
if ( t1->IsSet() && IsVector(t2->Tag()) )
{
st = t1->AsSetType();
vt = t2->AsVectorType();
}
else if ( IsVector(t1->Tag()) && t2->IsSet() )
{
st = t2->AsSetType();
vt = t1->AsVectorType();
}
if ( st && vt )
{
auto set_indices = st->GetIndices();
if ( set_indices->GetTypes().size() > 1 || ! set_indices->IsPure() )
return false;
return same_type(set_indices->GetPureType(), vt->Yield());
}
return false;
}
bool can_cast_value_to_type(const Val* v, Type* t)
{
// Note: when changing this function, adapt all three of
@ -4288,6 +4353,10 @@ bool can_cast_value_to_type(const Val* v, Type* t)
return static_cast<const Broker::detail::DataVal*>(dv.get())->canCastTo(t);
}
// Allow casting between sets and vectors if the yield types are the same.
if ( can_cast_set_and_vector(v->GetType().get(), t) )
return true;
return false;
}
@ -4307,6 +4376,10 @@ bool can_cast_value_to_type(const Type* s, Type* t)
// will.
return true;
// Allow casting between sets and vectors if the yield types are the same.
if ( can_cast_set_and_vector(s, t) )
return true;
return false;
}

View file

@ -0,0 +1,4 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/vector-set-conversions-errors.zeek, line 8: cast not supported (v1 as set[addr])
error in <...>/vector-set-conversions-errors.zeek, line 15: cast not supported (s2 as vector of addr)
error in <...>/vector-set-conversions-errors.zeek, line 22: cast not supported (s3 as vector of port)

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -0,0 +1,25 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
vector to set
[1, 1, 1, 2, 2, 3, 3, 4]
{
4,
2,
3,
1
}
set to vector (count)
{
4,
2,
3,
1
}
[4, 2, 3, 1]
set to vector (port)
{
23/tcp,
21/tcp
}
[23/tcp, 21/tcp]

View file

@ -0,0 +1,24 @@
# @TEST-DOC: Test error cases while converting between sets and vectorswith the 'as' keyword
# @TEST-EXEC-FAIL: zeek -b %INPUT > out
# @TEST-EXEC: btest-diff out
# @TEST-EXEC: TEST_DIFF_CANONIFIER="$SCRIPTS/diff-remove-abspath" btest-diff .stderr
print("vector to set: type mismatch");
local v1 = vector(1, 1, 1, 2, 2, 3, 3, 4);
local s1 = v1 as set[addr];
print(v1);
print(s1);
print("");
print("set to vector: type mismatch");
local s2 = set(1, 2, 3, 4);
local v2 = s2 as vector of addr;
print(s2);
print(v2);
print("");
print("set to vector: multiple indices");
local s3: set[port,string] = { [21/tcp, "ftp"], [23/tcp, "telnet"] };
local v3 = s3 as vector of port;
print(s3);
print(v3);

View file

@ -0,0 +1,24 @@
# @TEST-DOC: Tests converting between sets and vectors with the 'as' keyword
# @TEST-EXEC: zeek -b %INPUT > out
# @TEST-EXEC: btest-diff out
# @TEST-EXEC: btest-diff .stderr
print("vector to set");
local v1 = vector(1, 1, 1, 2, 2, 3, 3, 4);
local s1 = v1 as set[count];
print(v1);
print(s1);
print("");
print("set to vector (count)");
local s2 = set(1, 2, 3, 4);
local v2 = s2 as vector of count;
print(s2);
print(v2);
print("");
print("set to vector (port)");
local s3 = set(21/tcp, 23/tcp);
local v3 = s3 as vector of port;
print(s3);
print(v3);