From b343cf9bb73555bb2ec119d428ad86ec762348c8 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Mon, 13 Jan 2020 15:28:56 -0800 Subject: [PATCH] &on_change working for removals from tables. Insertions and changes are still noops. --- src/Val.cc | 70 ++++++++++++++++++++++++++++++++++++++++++++++++------ src/Val.h | 14 +++++++---- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/src/Val.cc b/src/Val.cc index 7f38c8f3fa..46e8f68766 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1927,16 +1927,61 @@ ListVal* TableVal::RecoverIndex(const HashKey* k) const return table_hash->RecoverVals(k); } +void TableVal::CallChangeFunc(const Val* index, Val* old_value, OnChangeType tpe) + { + if ( ! change_func ) + { + Unref(old_value); + return; + } + + try + { + Val* thefunc = change_func->Eval(0); + + if ( ! thefunc ) + { + return; + } + + if ( thefunc->Type()->Tag() != TYPE_FUNC ) + { + thefunc->Error("not a function"); + Unref(thefunc); + Unref(old_value); + return; + } + + const Func* f = thefunc->AsFunc(); + val_list vl { Ref() }; + EnumVal* type; + switch ( tpe ) + { + case element_new: + type = BifType::Enum::TableChange->GetVal(BifEnum::TableChange::TABLE_ELEMENT_NEW); + case element_changed: + type = BifType::Enum::TableChange->GetVal(BifEnum::TableChange::TABLE_ELEMENT_CHANGED); + case element_removed: + type = BifType::Enum::TableChange->GetVal(BifEnum::TableChange::TABLE_ELEMENT_REMOVED); + } + vl.append(type); + + for ( const auto& v : *index->AsListVal()->Vals() ) + vl.append(v->Ref()); + + vl.append(old_value); + + f->Call(&vl); + Unref(thefunc); + } + catch ( InterpreterException& e ) + { + } + } + Val* TableVal::Delete(const Val* index) { HashKey* k = ComputeHash(index); - if ( k && change_func ) - { - auto el = AsTable()->Lookup(k); - if ( el ) - { - } - } TableEntryVal* v = k ? AsNonConstTable()->RemoveEntry(k) : 0; Val* va = v ? (v->Value() ? v->Value() : this->Ref()) : 0; @@ -1947,6 +1992,10 @@ Val* TableVal::Delete(const Val* index) delete v; Modified(); + + if ( change_func ) + CallChangeFunc(index, va->Ref(), element_removed); + return va; } @@ -1966,6 +2015,13 @@ Val* TableVal::Delete(const HashKey* k) delete v; Modified(); + + if ( change_func ) + { + auto index = table_hash->RecoverVals(k); + CallChangeFunc(index, va->Ref(), element_removed); + } + return va; } diff --git a/src/Val.h b/src/Val.h index 88719171b8..64c5265cab 100644 --- a/src/Val.h +++ b/src/Val.h @@ -879,10 +879,10 @@ public: void InitTimer(double delay); void DoExpire(double t); - // If the &default attribute is not a function, or the functon has - // already been initialized, this does nothing. Otherwise, evaluates - // the function in the frame allowing it to capture its closure. - void InitDefaultFunc(Frame* f); + // If the &default attribute is not a function, or the functon has + // already been initialized, this does nothing. Otherwise, evaluates + // the function in the frame allowing it to capture its closure. + void InitDefaultFunc(Frame* f); unsigned int MemoryAllocation() const override; @@ -922,6 +922,12 @@ protected: // takes ownership of the reference. double CallExpireFunc(Val *idx); + // Enum for the different kinds of changes an &on_change handler can see + enum OnChangeType { element_new, element_changed, element_removed }; + + // Calls &change_func. Takes ownership of old_value. + void CallChangeFunc(const Val* index, Val* old_value, OnChangeType tpe); + Val* DoClone(CloneState* state) override; TableType* table_type;