diff --git a/src/IntrusivePtr.h b/src/IntrusivePtr.h index 7d9578d29f..c94af83d16 100644 --- a/src/IntrusivePtr.h +++ b/src/IntrusivePtr.h @@ -28,10 +28,11 @@ struct NewRef }; /** - * This has to be forward declared and known here in order for us to be able - * cast this in the `Unref` function. + * These have to be forward-declared and known here in order for us to be able + * cast them in the `Unref` function. */ class OpaqueVal; +class TypeVal; /** * An intrusive, reference counting smart pointer implementation. Much like @@ -120,9 +121,10 @@ public: { if ( ptr_ ) { - // Specializing `OpaqueVal` as MSVC compiler does not detect it - // inheriting from `zeek::Obj` so we have to do that manually. - if constexpr ( std::is_same_v ) + // Specializing `Val` subclasses that the MSVC compiler + // does not detect as inheriting from `zeek::Obj` + // so we have to do that manually. + if constexpr ( std::is_same_v || std::is_same_v ) Unref(reinterpret_cast(ptr_)); else Unref(ptr_); diff --git a/src/Type.cc b/src/Type.cc index b1e1d55351..bd03096917 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -992,6 +992,9 @@ void TypeDecl::DescribeReST(ODesc* d, bool roles_only) const } } +namespace detail + { + // A record field initialization that directly assigns a fixed value ... class DirectFieldInit final : public FieldInit { @@ -1099,6 +1102,8 @@ private: VectorTypePtr init_type; }; + } // namespace detail + RecordType::RecordType(type_decl_list* arg_types) : Type(TYPE_RECORD) { types = arg_types; @@ -1149,7 +1154,7 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) if ( field_ids.count(td->id) != 0 ) { reporter->Error("duplicate field '%s' found in record definition", td->id); - deferred_inits.push_back(std::nullopt); + deferred_inits.push_back(nullptr); return; } @@ -1161,7 +1166,7 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) auto def_attr = a ? a->Find(detail::ATTR_DEFAULT) : nullptr; auto def_expr = def_attr ? def_attr->GetExpr() : nullptr; - std::optional> init; + std::unique_ptr init; if ( def_expr && ! IsErrorType(type->Tag()) ) { @@ -1171,14 +1176,14 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) auto zv = ZVal(v, type); if ( ZVal::IsManagedType(type) ) - init = std::make_unique(zv); + init = std::make_unique(zv); else - init = std::make_unique(zv); + init = std::make_unique(zv); } else { - auto efi = std::make_unique(def_expr, type); + auto efi = std::make_unique(def_expr, type); creation_inits.emplace_back(std::make_pair(field, std::move(efi))); } } @@ -1188,13 +1193,13 @@ void RecordType::AddField(unsigned int field, const TypeDecl* td) TypeTag tag = type->Tag(); if ( tag == TYPE_RECORD ) - init = std::make_unique(cast_intrusive(type)); + init = std::make_unique(cast_intrusive(type)); else if ( tag == TYPE_TABLE ) - init = std::make_unique(cast_intrusive(type), a); + init = std::make_unique(cast_intrusive(type), a); else if ( tag == TYPE_VECTOR ) - init = std::make_unique(cast_intrusive(type)); + init = std::make_unique(cast_intrusive(type)); } deferred_inits.push_back(std::move(init)); @@ -1392,6 +1397,18 @@ void RecordType::AddFieldsDirectly(const type_decl_list& others, bool add_log_at num_fields = types->length(); } +void RecordType::Create(std::vector>& r) const + { + for ( auto& di : deferred_inits ) + if ( di ) + r.push_back(di->Generate()); + else + r.push_back(std::nullopt); + + for ( auto& ci : creation_inits ) + r[ci.first] = ci.second->Generate(); + } + void RecordType::DescribeFields(ODesc* d) const { if ( d->IsReadable() ) diff --git a/src/Type.h b/src/Type.h index afab6ccf1e..6aa43b31b9 100644 --- a/src/Type.h +++ b/src/Type.h @@ -37,6 +37,16 @@ class ListExpr; class Attributes; using ListExprPtr = IntrusivePtr; +// The following tracks how to initialize a given record field. +class FieldInit + { +public: + virtual ~FieldInit() { } + + // Return the initialization value of the field. + virtual ZVal Generate() const = 0; + }; + } // namespace detail // Zeek types. @@ -601,17 +611,6 @@ public: using type_decl_list = PList; -// The following tracks how to initialize a given field. - -class FieldInit - { -public: - virtual ~FieldInit() { } - - // Return the initialization value of the field. - virtual ZVal Generate() const = 0; - }; - class RecordType final : public Type { public: @@ -690,6 +689,15 @@ public: void AddFieldsDirectly(const type_decl_list& types, bool add_log_attr = false); + /** + * + * Populates a new instance of the record with its initial values. + * @param r The record's underlying value vector. + */ + [[deprecated("Remove in v6.1. Construct a corresponding RecordVal and build vector from " + "GetFieldAs() calls.")]] void + Create(std::vector>& r) const; + void DescribeReST(ODesc* d, bool roles_only = false) const override; void DescribeFields(ODesc* d) const; void DescribeFieldsReST(ODesc* d, bool func_args) const; @@ -710,7 +718,7 @@ public: detail::TraversalCode Traverse(detail::TraversalCallback* cb) const override; -protected: +private: RecordType() { types = nullptr; } void AddField(unsigned int field, const TypeDecl* td); @@ -718,9 +726,9 @@ protected: void DoDescribe(ODesc* d) const override; // Field initializations that can be deferred to first access, - // beneficial for fields that are separately iniitialized prior - // to first access. - std::vector>> deferred_inits; + // beneficial for fields that are separately initialized prior + // to first access. Nil pointers mean "skip initializing the field". + std::vector> deferred_inits; // Field initializations that need to be done upon record creation, // rather than deferred. These are expressions whose value might @@ -728,7 +736,7 @@ protected: // // Such initializations are uncommon, so we represent them using // pairs. - std::vector>> creation_inits; + std::vector>> creation_inits; friend zeek::RecordVal; const auto& DeferredInits() const { return deferred_inits; } diff --git a/src/Val.cc b/src/Val.cc index 635a022ba1..6218beef98 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -2778,6 +2778,14 @@ RecordVal::RecordVal(RecordTypePtr t, bool init_fields) : Val(t), is_managed(t-> throw; } } + + // The following is just for testing the deprecated Create() + // call, and can be removed with 6.1. We leave it commented + // out so we don't get deprecation warnings when building. +#if 0 + std::vector> testing; + rt->Create(testing); +#endif } else diff --git a/src/Val.h b/src/Val.h index eb2b789bd6..7290a6eacd 100644 --- a/src/Val.h +++ b/src/Val.h @@ -1218,7 +1218,7 @@ public: if ( (*record_val)[field] ) return true; - return bool(rt->DeferredInits()[field]); + return rt->DeferredInits()[field] != nullptr; } /** @@ -1247,7 +1247,7 @@ public: if ( ! fi ) return nullptr; - fv = (*fi)->Generate(); + fv = fi->Generate(); } return fv->ToVal(rt->GetFieldType(field)); @@ -1458,7 +1458,7 @@ protected: { const auto& fi = rt->DeferredInits()[field]; if ( fi ) - f = (*fi)->Generate(); + f = fi->Generate(); } return f;