diff --git a/src/Attr.cc b/src/Attr.cc index 46d90ee2b9..d927af639c 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -40,6 +40,7 @@ const char* attr_name(AttrTag t) "&deprecated", "&is_assigned", "&is_used", + "&ordered", }; return attr_names[int(t)]; @@ -624,6 +625,11 @@ void Attributes::CheckAttr(Attr* a) break; } + case ATTR_ORDERED: + if ( type->Tag() != TYPE_TABLE ) + Error("&ordered only applicable to tables"); + break; + default: BadTag("Attributes::CheckAttr", attr_name(a->Tag())); } diff --git a/src/Attr.h b/src/Attr.h index 780c39ac47..68dde8a148 100644 --- a/src/Attr.h +++ b/src/Attr.h @@ -51,6 +51,7 @@ enum AttrTag ATTR_DEPRECATED, ATTR_IS_ASSIGNED, // to suppress usage warnings ATTR_IS_USED, // to suppress usage warnings + ATTR_ORDERED, // used to store tables in ordered mode NUM_ATTRS // this item should always be last }; diff --git a/src/Val.cc b/src/Val.cc index 610df6204c..67b4c94744 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1389,7 +1389,8 @@ static void find_nested_record_types(const TypePtr& t, std::set* fo TableVal::TableVal(TableTypePtr t, detail::AttributesPtr a) : Val(t) { - Init(std::move(t)); + bool ordered = (a != nullptr && a->Find(detail::ATTR_ORDERED) != nullptr); + Init(std::move(t), ordered); SetAttrs(std::move(a)); if ( ! run_state::is_parsing ) @@ -1408,7 +1409,7 @@ TableVal::TableVal(TableTypePtr t, detail::AttributesPtr a) : Val(t) } } -void TableVal::Init(TableTypePtr t) +void TableVal::Init(TableTypePtr t, bool ordered) { table_type = std::move(t); expire_func = nullptr; @@ -1423,7 +1424,11 @@ void TableVal::Init(TableTypePtr t) subnets = nullptr; table_hash = new detail::CompositeHash(table_type->GetIndices()); - table_val = new PDict; + if ( ordered ) + table_val = new PDict(DictOrder::ORDERED); + else + table_val = new PDict(DictOrder::UNORDERED); + table_val->SetDeleteFunc(table_entry_val_delete_func); } diff --git a/src/Val.h b/src/Val.h index 19798422c7..ab1eb46036 100644 --- a/src/Val.h +++ b/src/Val.h @@ -998,7 +998,7 @@ public: void EnableChangeNotifications() { in_change_func = false; } protected: - void Init(TableTypePtr t); + void Init(TableTypePtr t, bool ordered = false); using TableRecordDependencies = std::unordered_map>; diff --git a/src/parse.y b/src/parse.y index 5735c7beaf..b194ced9c0 100644 --- a/src/parse.y +++ b/src/parse.y @@ -5,7 +5,7 @@ // Switching parser table type fixes ambiguity problems. %define lr.type ielr -%expect 199 +%expect 205 %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF @@ -29,7 +29,7 @@ %token TOK_ATTR_BROKER_STORE_ALLOW_COMPLEX TOK_ATTR_BACKEND %token TOK_ATTR_PRIORITY TOK_ATTR_LOG TOK_ATTR_ERROR_HANDLER %token TOK_ATTR_TYPE_COLUMN TOK_ATTR_DEPRECATED -%token TOK_ATTR_IS_ASSIGNED TOK_ATTR_IS_USED +%token TOK_ATTR_IS_ASSIGNED TOK_ATTR_IS_USED TOK_ATTR_ORDERED %token TOK_DEBUG @@ -1730,6 +1730,8 @@ attr: $$ = new Attr(ATTR_DEPRECATED); } } + | TOK_ATTR_ORDERED + { $$ = new Attr(ATTR_ORDERED); } ; stmt: diff --git a/src/scan.l b/src/scan.l index c34979ddd9..0d19162615 100644 --- a/src/scan.l +++ b/src/scan.l @@ -330,6 +330,7 @@ when return TOK_WHEN; &broker_store return TOK_ATTR_BROKER_STORE; &broker_allow_complex_type return TOK_ATTR_BROKER_STORE_ALLOW_COMPLEX; &backend return TOK_ATTR_BACKEND; +&ordered return TOK_ATTR_ORDERED; @deprecated.* { auto num_files = file_stack.length(); diff --git a/testing/btest/Baseline/language.table-iteration/.stderr b/testing/btest/Baseline/language.table-iteration/.stderr new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/language.table-iteration/.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.table-iteration/out b/testing/btest/Baseline/language.table-iteration/out new file mode 100644 index 0000000000..1845af6a24 --- /dev/null +++ b/testing/btest/Baseline/language.table-iteration/out @@ -0,0 +1,7 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +2 +1 +3 +1 +2 +3 diff --git a/testing/btest/language/table-iteration.zeek b/testing/btest/language/table-iteration.zeek new file mode 100644 index 0000000000..f17b791210 --- /dev/null +++ b/testing/btest/language/table-iteration.zeek @@ -0,0 +1,27 @@ +# @TEST-EXEC: zeek -b %INPUT >out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff .stderr + +global tbl: table[count] of count; +global tbl2: table[count] of count &ordered; + +event zeek_init() +{ + local i = 0; + while ( i < 3 ) + { + ++i; + tbl[i] = i; + tbl2[i] = i; + } + + for ( [k], v in tbl ) + { + print(v); + } + + for ( [k], v in tbl2 ) + { + print(v); + } +}