diff --git a/src/Val.cc b/src/Val.cc index e3eb35002f..b98408e551 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -3241,7 +3241,7 @@ ValPtr TypeVal::DoClone(CloneState* state) VectorVal::VectorVal(VectorTypePtr t) : Val(t) { - vector_val = new vector(); + vector_val = new vector>(); yield_type = t->Yield(); auto y_tag = yield_type->Tag(); @@ -3255,14 +3255,19 @@ VectorVal::~VectorVal() { int n = yield_types->size(); for ( auto i = 0; i < n; ++i ) - ZVal::DeleteIfManaged((*vector_val)[i], (*yield_types)[i]); + { + auto& elem = (*vector_val)[i]; + if ( elem ) + ZVal::DeleteIfManaged(*elem, (*yield_types)[i]); + } delete yield_types; } else if ( managed_yield ) { for ( auto& elem : *vector_val ) - ZVal::DeleteManagedType(elem); + if ( elem ) + ZVal::DeleteManagedType(*elem); } delete vector_val; @@ -3320,7 +3325,9 @@ bool VectorVal::Assign(unsigned int index, ValPtr element) if ( index >= n ) { - AddHoles(index - n); + if ( index > n ) + AddHoles(index - n); + vector_val->resize(index + 1); if ( yield_types ) yield_types->resize(index + 1); @@ -3330,14 +3337,21 @@ bool VectorVal::Assign(unsigned int index, ValPtr element) { const auto& t = element->GetType(); (*yield_types)[index] = t; - ZVal::DeleteIfManaged((*vector_val)[index], t); - (*vector_val)[index] = ZVal(std::move(element), t); + auto& elem = (*vector_val)[index]; + if ( elem ) + ZVal::DeleteIfManaged(*elem, t); + elem = ZVal(std::move(element), t); } else { - if ( managed_yield ) - ZVal::DeleteManagedType((*vector_val)[index]); - (*vector_val)[index] = ZVal(std::move(element), yield_type); + auto& elem = (*vector_val)[index]; + if ( managed_yield && elem ) + ZVal::DeleteManagedType(*elem); + + if ( element ) + elem = ZVal(std::move(element), yield_type); + else + elem = std::nullopt; } Modified(); @@ -3361,7 +3375,7 @@ bool VectorVal::Insert(unsigned int index, ValPtr element) if ( ! CheckElementType(element) ) return false; - vector::iterator it; + vector>::iterator it; vector::iterator types_it; auto n = vector_val->size(); @@ -3371,28 +3385,36 @@ bool VectorVal::Insert(unsigned int index, ValPtr element) it = std::next(vector_val->begin(), index); if ( yield_types ) { - ZVal::DeleteIfManaged(*it, element->GetType()); + if ( *it ) + ZVal::DeleteIfManaged(**it, element->GetType()); types_it = std::next(yield_types->begin(), index); } else if ( managed_yield ) - ZVal::DeleteManagedType(*it); + ZVal::DeleteManagedType(**it); } else { it = vector_val->end(); if ( yield_types ) types_it = yield_types->end(); - AddHoles(index - n); + + if ( index > n ) + AddHoles(index - n); } - if ( yield_types ) + if ( element ) { - const auto& t = element->GetType(); - yield_types->insert(types_it, t); - vector_val->insert(it, ZVal(std::move(element), t)); + if ( yield_types ) + { + const auto& t = element->GetType(); + yield_types->insert(types_it, t); + vector_val->insert(it, ZVal(std::move(element), t)); + } + else + vector_val->insert(it, ZVal(std::move(element), yield_type)); } else - vector_val->insert(it, ZVal(std::move(element), yield_type)); + vector_val->insert(it, std::nullopt); Modified(); return true; @@ -3405,7 +3427,7 @@ void VectorVal::AddHoles(int nholes) fill_t = base_type(TYPE_ANY); for ( auto i = 0; i < nholes; ++i ) - vector_val->emplace_back(ZVal(fill_t)); + vector_val->emplace_back(std::nullopt); } bool VectorVal::Remove(unsigned int index) @@ -3418,12 +3440,13 @@ bool VectorVal::Remove(unsigned int index) if ( yield_types ) { auto types_it = std::next(yield_types->begin(), index); - ZVal::DeleteIfManaged(*it, *types_it); + if ( *it ) + ZVal::DeleteIfManaged(**it, *types_it); yield_types->erase(types_it); } else if ( managed_yield ) - ZVal::DeleteManagedType(*it); + ZVal::DeleteManagedType(**it); vector_val->erase(it); @@ -3460,33 +3483,33 @@ ValPtr VectorVal::At(unsigned int index) const if ( index >= vector_val->size() ) return Val::nil; + auto& elem = (*vector_val)[index]; + if ( ! elem ) + return Val::nil; + const auto& t = yield_types ? (*yield_types)[index] : yield_type; - return (*vector_val)[index].ToVal(t); + return elem->ToVal(t); } static Func* sort_function_comp = nullptr; // Used for indirect sorting to support order(). -static std::vector index_map; +static std::vector*> index_map; // The yield type of the vector being sorted. static TypePtr sort_type; -static bool sort_type_is_managed = false; -static bool sort_function(const ZVal& a, const ZVal& b) +static bool sort_function(const std::optional& a, const std::optional& b) { - // Missing values are only applicable for managed types. - if ( sort_type_is_managed ) - { - if ( ! a.ManagedVal() ) - return 0; - if ( ! b.ManagedVal() ) - return 1; - } + if ( ! a ) + return false; - auto a_v = a.ToVal(sort_type); - auto b_v = b.ToVal(sort_type); + if ( ! b ) + return true; + + auto a_v = a->ToVal(sort_type); + auto b_v = b->ToVal(sort_type); auto result = sort_function_comp->Invoke(a_v, b_v); int int_result = result->CoerceToInt(); @@ -3494,19 +3517,37 @@ static bool sort_function(const ZVal& a, const ZVal& b) return int_result < 0; } -static bool signed_sort_function (const ZVal& a, const ZVal& b) +static bool signed_sort_function(const std::optional& a, const std::optional& b) { - return a.AsInt() < b.AsInt(); + if ( ! a ) + return false; + + if ( ! b ) + return true; + + return a->AsInt() < b->AsInt(); } -static bool unsigned_sort_function (const ZVal& a, const ZVal& b) +static bool unsigned_sort_function(const std::optional& a, const std::optional& b) { - return a.AsCount() < b.AsCount(); + if ( ! a ) + return false; + + if ( ! b ) + return true; + + return a->AsCount() < b->AsCount(); } -static bool double_sort_function (const ZVal& a, const ZVal& b) +static bool double_sort_function(const std::optional& a, const std::optional& b) { - return a.AsDouble() < b.AsDouble(); + if ( ! a ) + return false; + + if ( ! b ) + return true; + + return a->AsDouble() < b->AsDouble(); } static bool indirect_sort_function(size_t a, size_t b) @@ -3535,9 +3576,8 @@ void VectorVal::Sort(Func* cmp_func) reporter->RuntimeError(GetLocationInfo(), "cannot sort a vector-of-any"); sort_type = yield_type; - sort_type_is_managed = ZVal::IsManagedType(sort_type); - bool (*sort_func)(const ZVal&, const ZVal&); + bool (*sort_func)(const std::optional&, const std::optional&); if ( cmp_func ) { @@ -3572,7 +3612,6 @@ VectorValPtr VectorVal::Order(Func* cmp_func) } sort_type = yield_type; - sort_type_is_managed = ZVal::IsManagedType(sort_type); bool (*sort_func)(size_t, size_t); @@ -3666,8 +3705,9 @@ ValPtr VectorVal::DoClone(CloneState* state) for ( auto i = 0; i < n; ++i ) { - auto vc = At(i)->Clone(state); - vv->Append(std::move(vc)); + auto elem = At(i); + if ( elem ) + vv->Assign(i, elem->Clone(state)); } return vv; diff --git a/src/Val.h b/src/Val.h index 4bdd1b9dbc..2f3fb29e21 100644 --- a/src/Val.h +++ b/src/Val.h @@ -1505,10 +1505,6 @@ public: */ bool Assign(unsigned int index, ValPtr element); - // Note: the following nullptr method can also go upon removing the above. - void Assign(unsigned int index, std::nullptr_t) - { Assign(index, ValPtr{}); } - /** * Assigns a given value to multiple indices in the vector. * @param index The starting index to assign to. @@ -1581,18 +1577,19 @@ public: /** * Returns the given element in a given underlying representation. * Enables efficient vector access. Caller must ensure that the - * index lies within the vector's range. + * index lies within the vector's range, and does not point to + * a "hole". * @param index The position in the vector of the element to return. * @return The element's underlying value. */ bro_uint_t CountAt(unsigned int index) const - { return (*vector_val)[index].uint_val; } + { return (*vector_val)[index]->uint_val; } const RecordVal* RecordValAt(unsigned int index) const - { return (*vector_val)[index].record_val; } + { return (*vector_val)[index]->record_val; } bool BoolAt(unsigned int index) const - { return static_cast((*vector_val)[index].uint_val); } + { return static_cast((*vector_val)[index]->uint_val); } const StringVal* StringValAt(unsigned int index) const - { return (*vector_val)[index].string_val; } + { return (*vector_val)[index]->string_val; } const String* StringAt(unsigned int index) const { return StringValAt(index)->AsString(); } @@ -1601,7 +1598,7 @@ protected: * Returns the element at a given index or nullptr if it does not exist. * @param index The position in the vector of the element to return. * @return The element at the given index or nullptr if the index - * does not exist (it's greater than or equal to vector's current size). + * does not exist. * * Protected to ensure callers pick one of the differentiated accessors * above, as appropriate, with ValAt() providing the original semantics. @@ -1624,7 +1621,7 @@ private: // Add the given number of "holes" to the end of a vector. void AddHoles(int nholes); - std::vector* vector_val; + std::vector>* vector_val; // For homogeneous vectors (the usual case), the type of the // elements. Will be TYPE_VOID for empty vectors created using