mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-15 15:11:32 +00:00
Added type conversion search routines
- PType::FindConversion() can find a path to convert one type to another. This is completely generic and can handle any number of conversion functions.
This commit is contained in:
parent
4bd5bf310b
commit
c7e817dfb9
2 changed files with 215 additions and 0 deletions
153
src/dobjtype.cpp
153
src/dobjtype.cpp
|
@ -213,6 +213,159 @@ PType::~PType()
|
|||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: AddConversion
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PType::AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &))
|
||||
{
|
||||
// Make sure a conversion hasn't already been registered
|
||||
for (unsigned i = 0; i < Conversions.Size(); ++i)
|
||||
{
|
||||
if (Conversions[i].TargetType == target)
|
||||
return false;
|
||||
}
|
||||
Conversions.Push(Conversion(target, convertconst));
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: FindConversion
|
||||
//
|
||||
// Returns <0 if there is no path to target. Otherwise, returns the distance
|
||||
// to target and fills slots (if non-NULL) with the necessary conversions
|
||||
// to get there. A result of 0 means this is the target.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int PType::FindConversion(PType *target, const PType::Conversion **slots, int numslots)
|
||||
{
|
||||
if (this == target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// The queue is implemented as a ring buffer
|
||||
VisitQueue queue;
|
||||
VisitedNodeSet visited;
|
||||
|
||||
// Use a breadth-first search to find the shortest path to the target.
|
||||
MarkPred(NULL, -1, -1);
|
||||
queue.Push(this);
|
||||
visited.Insert(this);
|
||||
while (!queue.IsEmpty())
|
||||
{
|
||||
PType *t = queue.Pop();
|
||||
if (t == target)
|
||||
{ // found it
|
||||
if (slots != NULL)
|
||||
{
|
||||
if (t->Distance >= numslots)
|
||||
{ // Distance is too far for the output
|
||||
return -2;
|
||||
}
|
||||
t->FillConversionPath(slots);
|
||||
}
|
||||
return t->Distance + 1;
|
||||
}
|
||||
for (unsigned i = 0; i < t->Conversions.Size(); ++i)
|
||||
{
|
||||
PType *succ = t->Conversions[i].TargetType;
|
||||
if (!visited.Check(succ))
|
||||
{
|
||||
succ->MarkPred(t, i, Distance + 1);
|
||||
visited.Insert(succ);
|
||||
queue.Push(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: FillConversionPath
|
||||
//
|
||||
// Traces backwards from the target type to the original type and fills in
|
||||
// the conversions necessary to get between them. slots must point to an
|
||||
// array large enough to contain the entire path.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::FillConversionPath(const PType::Conversion **slots)
|
||||
{
|
||||
for (PType *node = this; node->Distance >= 0; node = node->PredType)
|
||||
{
|
||||
assert(node->PredType != NULL);
|
||||
slots[node->Distance] = &node->PredType->Conversions[node->PredConv];
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitQueue :: Push
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::VisitQueue::Push(PType *type)
|
||||
{
|
||||
Queue[In] = type;
|
||||
Advance(In);
|
||||
assert(!IsEmpty() && "Queue overflowed");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitQueue :: Pop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PType *PType::VisitQueue::Pop()
|
||||
{
|
||||
if (IsEmpty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
PType *node = Queue[Out];
|
||||
Advance(Out);
|
||||
return node;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitedNodeSet :: Insert
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::VisitedNodeSet::Insert(PType *node)
|
||||
{
|
||||
assert(!Check(node) && "Node was already inserted");
|
||||
size_t buck = Hash(node) & (countof(Buckets) - 1);
|
||||
node->VisitNext = Buckets[buck];
|
||||
Buckets[buck] = node;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitedNodeSet :: Check
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PType::VisitedNodeSet::Check(const PType *node)
|
||||
{
|
||||
size_t buck = Hash(node) & (countof(Buckets) - 1);
|
||||
for (const PType *probe = Buckets[buck]; probe != NULL; probe = probe->VisitNext)
|
||||
{
|
||||
if (probe == node)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: SetValue
|
||||
|
|
|
@ -113,6 +113,7 @@ private:
|
|||
// Map * *
|
||||
// Prototype *+ *+
|
||||
|
||||
struct ZCC_ExprConstant;
|
||||
class PClassType;
|
||||
class PType : public DObject
|
||||
{
|
||||
|
@ -128,6 +129,15 @@ public:
|
|||
typedef PClassType MetaClass;
|
||||
MetaClass *GetClass() const;
|
||||
|
||||
struct Conversion
|
||||
{
|
||||
Conversion(PType *target, void (*convert)(ZCC_ExprConstant *, class FSharedStringArena &))
|
||||
: TargetType(target), ConvertConstant(convert) {}
|
||||
|
||||
PType *TargetType;
|
||||
void (*ConvertConstant)(ZCC_ExprConstant *val, class FSharedStringArena &strdump);
|
||||
};
|
||||
|
||||
unsigned int Size; // this type's size
|
||||
unsigned int Align; // this type's preferred alignment
|
||||
PType *HashNext; // next type in this type table
|
||||
|
@ -136,6 +146,10 @@ public:
|
|||
PType(unsigned int size, unsigned int align);
|
||||
virtual ~PType();
|
||||
|
||||
bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &));
|
||||
|
||||
int FindConversion(PType *target, const Conversion **slots, int numslots);
|
||||
|
||||
// Sets the value of a variable of this type at (addr)
|
||||
virtual void SetValue(void *addr, int val);
|
||||
|
||||
|
@ -163,6 +177,54 @@ public:
|
|||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
static void StaticInit();
|
||||
|
||||
private:
|
||||
// Stuff for type conversion searches
|
||||
class VisitQueue
|
||||
{
|
||||
public:
|
||||
VisitQueue() : In(0), Out(0) {}
|
||||
void Push(PType *type);
|
||||
PType *Pop();
|
||||
bool IsEmpty() { return In == Out; }
|
||||
|
||||
private:
|
||||
// This is a fixed-sized ring buffer.
|
||||
PType *Queue[64];
|
||||
int In, Out;
|
||||
|
||||
void Advance(int &ptr)
|
||||
{
|
||||
ptr = (ptr + 1) & (countof(Queue) - 1);
|
||||
}
|
||||
};
|
||||
|
||||
class VisitedNodeSet
|
||||
{
|
||||
public:
|
||||
VisitedNodeSet() { memset(Buckets, 0, sizeof(Buckets)); }
|
||||
void Insert(PType *node);
|
||||
bool Check(const PType *node);
|
||||
|
||||
private:
|
||||
PType *Buckets[32];
|
||||
|
||||
size_t Hash(const PType *type) { return size_t(type) >> 4; }
|
||||
};
|
||||
|
||||
TArray<Conversion> Conversions;
|
||||
PType *PredType;
|
||||
PType *VisitNext;
|
||||
short PredConv;
|
||||
short Distance;
|
||||
|
||||
void MarkPred(PType *pred, int conv, int dist)
|
||||
{
|
||||
PredType = pred;
|
||||
PredConv = conv;
|
||||
Distance = dist;
|
||||
}
|
||||
void FillConversionPath(const Conversion **slots);
|
||||
};
|
||||
|
||||
// Not-really-a-type types --------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue