C4Value: Implement some crude infinite recursion guard which happens solely inside C4Value::operator==

stable-5.4
Martin Plicht 2013-10-12 21:54:42 +02:00
parent 7789f9586a
commit d164a2d50a
1 changed files with 65 additions and 12 deletions

View File

@ -486,32 +486,85 @@ void C4ValueNumbers::CompileFunc(StdCompiler * pComp)
}
}
bool C4Value::operator == (const C4Value& Value2) const
inline bool ComparisonImpl(const C4Value &Value1, const C4Value &Value2)
{
switch (Type)
C4V_Type Type1 = Value1.GetType();
C4V_Data Data1 = Value1.GetData();
C4V_Type Type2 = Value2.GetType();
C4V_Data Data2 = Value2.GetData();
switch (Type1)
{
case C4V_Nil:
assert(!Data);
return Type == Value2.Type;
assert(!Data1);
return Type1 == Type2;
case C4V_Int:
case C4V_Bool:
return (Value2.Type == C4V_Int || Value2.Type == C4V_Bool) &&
Data.Int == Value2.Data.Int;
return (Type2 == C4V_Int || Type2 == C4V_Bool) &&
Data1.Int == Data2.Int;
case C4V_PropList:
return Type == Value2.Type && *Data.PropList == *Value2.Data.PropList;
return Type1 == Type2 && *Data1.PropList == *Data2.PropList;
case C4V_String:
return Type == Value2.Type && Data.Str == Value2.Data.Str;
return Type1 == Type2 && Data1.Str == Data2.Str;
case C4V_Array:
return Type == Value2.Type &&
(Data.Array == Value2.Data.Array || *(Data.Array) == *(Value2.Data.Array));
return Type1 == Type2 &&
(Data1.Array == Data2.Array || *(Data1.Array) == *(Data2.Array));
case C4V_Function:
return Type == Value2.Type && Data.Fn == Value2.Data.Fn;
return Type1 == Type2 && Data1.Fn == Data2.Fn;
default:
assert(!"Unexpected C4Value type (denumeration missing?)");
return Data == Value2.Data;
return Data1 == Data2;
}
}
bool C4Value::operator == (const C4Value& Value2) const
{
// recursion guard using a linked list of Seen structures on the stack
// NOT thread-safe
struct Seen
{
Seen *prev;
const C4Value *left;
const C4Value *right;
inline Seen(Seen *prev, const C4Value *left, const C4Value *right):
prev(prev), left(left), right(right) {}
inline bool operator == (const Seen& other)
{
return left == other.left && right == other.right;
}
inline bool recursion(Seen *new_top)
{
for (Seen *s = this; s; s = s->prev)
if (*s == *new_top)
return true;
return false;
}
inline Seen *first()
{
Seen *s = this;
while (s->prev) s = s->prev;
return s;
}
};
static Seen *top = NULL;
Seen here(top, this, &Value2);
bool recursion = top && top->recursion(&here);
if (recursion)
{
Seen *first = top->first();
// GetDataString is fine for recursive values since after
// some text length has been exceeded ... will be used instead of complete values
LogF("Caught infinite recursion comparing %s and %s",
first->left->GetDataString().getData(),
first->right->GetDataString().getData());
return false;
}
top = &here;
bool result = ComparisonImpl(*this, Value2);
top = here.prev;
return result;
}
bool C4Value::operator != (const C4Value& Value2) const
{
return !(*this == Value2);