&on_change working for removals from tables.

Insertions and changes are still noops.
This commit is contained in:
Johanna Amann 2020-01-13 15:28:56 -08:00
parent 5b5d36cd83
commit b343cf9bb7
2 changed files with 73 additions and 11 deletions

View file

@ -1927,16 +1927,61 @@ ListVal* TableVal::RecoverIndex(const HashKey* k) const
return table_hash->RecoverVals(k); 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) Val* TableVal::Delete(const Val* index)
{ {
HashKey* k = ComputeHash(index); HashKey* k = ComputeHash(index);
if ( k && change_func )
{
auto el = AsTable()->Lookup(k);
if ( el )
{
}
}
TableEntryVal* v = k ? AsNonConstTable()->RemoveEntry(k) : 0; TableEntryVal* v = k ? AsNonConstTable()->RemoveEntry(k) : 0;
Val* va = v ? (v->Value() ? v->Value() : this->Ref()) : 0; Val* va = v ? (v->Value() ? v->Value() : this->Ref()) : 0;
@ -1947,6 +1992,10 @@ Val* TableVal::Delete(const Val* index)
delete v; delete v;
Modified(); Modified();
if ( change_func )
CallChangeFunc(index, va->Ref(), element_removed);
return va; return va;
} }
@ -1966,6 +2015,13 @@ Val* TableVal::Delete(const HashKey* k)
delete v; delete v;
Modified(); Modified();
if ( change_func )
{
auto index = table_hash->RecoverVals(k);
CallChangeFunc(index, va->Ref(), element_removed);
}
return va; return va;
} }

View file

@ -879,10 +879,10 @@ public:
void InitTimer(double delay); void InitTimer(double delay);
void DoExpire(double t); void DoExpire(double t);
// If the &default attribute is not a function, or the functon has // If the &default attribute is not a function, or the functon has
// already been initialized, this does nothing. Otherwise, evaluates // already been initialized, this does nothing. Otherwise, evaluates
// the function in the frame allowing it to capture its closure. // the function in the frame allowing it to capture its closure.
void InitDefaultFunc(Frame* f); void InitDefaultFunc(Frame* f);
unsigned int MemoryAllocation() const override; unsigned int MemoryAllocation() const override;
@ -922,6 +922,12 @@ protected:
// takes ownership of the reference. // takes ownership of the reference.
double CallExpireFunc(Val *idx); 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; Val* DoClone(CloneState* state) override;
TableType* table_type; TableType* table_type;