From 59f7b26b5129414712600d4cfb3bd22d7aaf054b Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Wed, 12 Jul 2023 12:20:38 -0700 Subject: [PATCH 1/3] Add std::move for a couple of variables passed by value --- src/Expr.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Expr.cc b/src/Expr.cc index 96bbefaa76..15028fcb59 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3703,7 +3703,7 @@ void TableConstructorExpr::ExprDescribe(ODesc* d) const SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> arg_attrs, TypePtr arg_type, AttributesPtr arg_attrs2) - : UnaryExpr(EXPR_SET_CONSTRUCTOR, expand_op(constructor_list, arg_type)) + : UnaryExpr(EXPR_SET_CONSTRUCTOR, expand_op(std::move(constructor_list), arg_type)) { if ( IsError() ) return; @@ -3737,7 +3737,7 @@ SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list, if ( arg_attrs ) SetAttrs(make_intrusive(std::move(*arg_attrs), type, false, false)); else - SetAttrs(arg_attrs2); + SetAttrs(std::move(arg_attrs2)); const auto& indices = type->AsTableType()->GetIndices()->GetTypes(); ExprPList& cle = op->AsListExpr()->Exprs(); From af9e852c283519d26f540bf8aa5d89cb35b468ea Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 14 Jul 2023 13:35:26 -0700 Subject: [PATCH 2/3] Add conversion between set and vector using 'as' keyword --- NEWS | 5 ++ src/Val.cc | 73 +++++++++++++++++++ .../.stderr | 4 + .../out | 1 + .../language.vector-set-conversions/.stderr | 1 + .../language.vector-set-conversions/out | 25 +++++++ .../vector-set-conversions-errors.zeek | 24 ++++++ .../language/vector-set-conversions.zeek | 24 ++++++ 8 files changed, 157 insertions(+) create mode 100644 testing/btest/Baseline/language.vector-set-conversions-errors/.stderr create mode 100644 testing/btest/Baseline/language.vector-set-conversions-errors/out create mode 100644 testing/btest/Baseline/language.vector-set-conversions/.stderr create mode 100644 testing/btest/Baseline/language.vector-set-conversions/out create mode 100644 testing/btest/language/vector-set-conversions-errors.zeek create mode 100644 testing/btest/language/vector-set-conversions.zeek diff --git a/NEWS b/NEWS index a009088290..83bd36cd91 100644 --- a/NEWS +++ b/NEWS @@ -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 --------------------- diff --git a/src/Val.cc b/src/Val.cc index d95e217fc6..d1f50a578e 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -4262,9 +4262,74 @@ ValPtr cast_value_to_type(Val* v, Type* t) return static_cast(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(); + auto indices = set_type->GetIndices(); + + if ( indices->GetTypes().size() > 1 || ! indices->IsPure() ) + return nullptr; + + auto ret_type = IntrusivePtr{NewRef{}, t->AsVectorType()}; + auto ret = make_intrusive(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{NewRef{}, t->AsSetType()}; + auto ret = make_intrusive(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(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; } diff --git a/testing/btest/Baseline/language.vector-set-conversions-errors/.stderr b/testing/btest/Baseline/language.vector-set-conversions-errors/.stderr new file mode 100644 index 0000000000..42446a02a8 --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions-errors/.stderr @@ -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) diff --git a/testing/btest/Baseline/language.vector-set-conversions-errors/out b/testing/btest/Baseline/language.vector-set-conversions-errors/out new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions-errors/out @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/language.vector-set-conversions/.stderr b/testing/btest/Baseline/language.vector-set-conversions/.stderr new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions/.stderr @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/language.vector-set-conversions/out b/testing/btest/Baseline/language.vector-set-conversions/out new file mode 100644 index 0000000000..4e2d52d393 --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions/out @@ -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] diff --git a/testing/btest/language/vector-set-conversions-errors.zeek b/testing/btest/language/vector-set-conversions-errors.zeek new file mode 100644 index 0000000000..20d199269a --- /dev/null +++ b/testing/btest/language/vector-set-conversions-errors.zeek @@ -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); diff --git a/testing/btest/language/vector-set-conversions.zeek b/testing/btest/language/vector-set-conversions.zeek new file mode 100644 index 0000000000..3b6080fae9 --- /dev/null +++ b/testing/btest/language/vector-set-conversions.zeek @@ -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); From fe9926e538186194cbf07e55451934e78a04455f Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 10 Aug 2023 13:42:23 -0700 Subject: [PATCH 3/3] Fix conversion with record types --- src/Val.cc | 24 ++++++++++++------- .../language.vector-set-conversions/out | 14 +++++++++++ .../language/vector-set-conversions.zeek | 18 ++++++++++++++ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/Val.cc b/src/Val.cc index d1f50a578e..2068cc2190 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -4268,17 +4268,23 @@ ValPtr cast_value_to_type(Val* v, Type* t) auto set_type = v->GetType(); auto indices = set_type->GetIndices(); - if ( indices->GetTypes().size() > 1 || ! indices->IsPure() ) + if ( indices->GetTypes().size() > 1 ) return nullptr; auto ret_type = IntrusivePtr{NewRef{}, t->AsVectorType()}; auto ret = make_intrusive(ret_type); - auto lv = v->AsTableVal()->ToPureListVal(); - auto n = lv->Length(); - - for ( int i = 0; i < n; ++i ) - ret->Assign(i, lv->Idx(i)); + auto* table = v->AsTable(); + auto* tval = v->AsTableVal(); + int index = 0; + for ( const auto& te : *table ) + { + auto k = te.GetHashKey(); + auto lv = tval->RecreateIndex(*k); + ValPtr entry_key = lv->Length() == 1 ? lv->Idx(0) : lv; + ret->Assign(index, entry_key); + index++; + } return ret; } @@ -4320,11 +4326,11 @@ static bool can_cast_set_and_vector(const Type* t1, const Type* t2) if ( st && vt ) { - auto set_indices = st->GetIndices(); - if ( set_indices->GetTypes().size() > 1 || ! set_indices->IsPure() ) + auto set_indices = st->GetIndices()->GetTypes(); + if ( set_indices.size() > 1 ) return false; - return same_type(set_indices->GetPureType(), vt->Yield()); + return same_type(set_indices[0], vt->Yield()); } return false; diff --git a/testing/btest/Baseline/language.vector-set-conversions/out b/testing/btest/Baseline/language.vector-set-conversions/out index 4e2d52d393..85e5403a77 100644 --- a/testing/btest/Baseline/language.vector-set-conversions/out +++ b/testing/btest/Baseline/language.vector-set-conversions/out @@ -23,3 +23,17 @@ set to vector (port) 21/tcp } [23/tcp, 21/tcp] + +set to vector (record) +{ +[a=a, b=b], +[a=a1, b=b1] +} +{ +[a=a, b=b], +[a=a1, b=b1] +} + +vector to set (record) +[[a=a, b=b], [a=a1, b=b1]] +[[a=a, b=b], [a=a1, b=b1]] diff --git a/testing/btest/language/vector-set-conversions.zeek b/testing/btest/language/vector-set-conversions.zeek index 3b6080fae9..5efa2e4c6d 100644 --- a/testing/btest/language/vector-set-conversions.zeek +++ b/testing/btest/language/vector-set-conversions.zeek @@ -3,6 +3,11 @@ # @TEST-EXEC: btest-diff out # @TEST-EXEC: btest-diff .stderr +type r: record { + a: string; + b: string; +}; + print("vector to set"); local v1 = vector(1, 1, 1, 2, 2, 3, 3, 4); local s1 = v1 as set[count]; @@ -22,3 +27,16 @@ local s3 = set(21/tcp, 23/tcp); local v3 = s3 as vector of port; print(s3); print(v3); + +local s: set[r] = set([$a="a", $b="b"], [$a="a1", $b="b1"]); +local v: vector of r = vector([$a="a", $b="b"], [$a="a1", $b="b1"]); + +print(""); +print("set to vector (record)"); +print s; +print v as set[r]; + +print(""); +print("vector to set (record)"); +print v; +print s as vector of r;