You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
996 lines
30 KiB
996 lines
30 KiB
ANTLR_BEGIN_NAMESPACE()
|
|
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE TrieEntry<ImplTraits, DataType>::TrieEntry(const DataType& data, TrieEntry* next)
|
|
:m_data(data)
|
|
{
|
|
m_next = next;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE DataType& TrieEntry<ImplTraits, DataType>::get_data()
|
|
{
|
|
return m_data;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE const DataType& TrieEntry<ImplTraits, DataType>::get_data() const
|
|
{
|
|
return m_data;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE TrieEntry<ImplTraits, DataType>* TrieEntry<ImplTraits, DataType>::get_next() const
|
|
{
|
|
return m_next;
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE void TrieEntry<ImplTraits, DataType>::set_next( TrieEntry* next )
|
|
{
|
|
m_next = next;
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE ANTLR_UINT32 IntTrieNode<ImplTraits, DataType>::get_bitNum() const
|
|
{
|
|
return m_bitNum;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE ANTLR_INTKEY IntTrieNode<ImplTraits, DataType>::get_key() const
|
|
{
|
|
return m_key;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE typename IntTrieNode<ImplTraits, DataType>::BucketsType* IntTrieNode<ImplTraits, DataType>::get_buckets() const
|
|
{
|
|
return m_buckets;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE IntTrieNode<ImplTraits, DataType>* IntTrieNode<ImplTraits, DataType>::get_leftN() const
|
|
{
|
|
return m_leftN;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE IntTrieNode<ImplTraits, DataType>* IntTrieNode<ImplTraits, DataType>::get_rightN() const
|
|
{
|
|
return m_rightN;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE void IntTrieNode<ImplTraits, DataType>::set_bitNum( ANTLR_UINT32 bitNum )
|
|
{
|
|
m_bitNum = bitNum;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE void IntTrieNode<ImplTraits, DataType>::set_key( ANTLR_INTKEY key )
|
|
{
|
|
m_key = key;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE void IntTrieNode<ImplTraits, DataType>::set_buckets( BucketsType* buckets )
|
|
{
|
|
m_buckets = buckets;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE void IntTrieNode<ImplTraits, DataType>::set_leftN( IntTrieNode* leftN )
|
|
{
|
|
m_leftN = leftN;
|
|
}
|
|
template< class ImplTraits, class DataType >
|
|
ANTLR_INLINE void IntTrieNode<ImplTraits, DataType>::set_rightN( IntTrieNode* rightN )
|
|
{
|
|
m_rightN = rightN;
|
|
}
|
|
|
|
ANTLR_INLINE const ANTLR_UINT8* IntTrieBase::get_bitIndex()
|
|
{
|
|
static ANTLR_UINT8 bitIndex[256] =
|
|
{
|
|
0, // 0 - Just for padding
|
|
0, // 1
|
|
1, 1, // 2..3
|
|
2, 2, 2, 2, // 4..7
|
|
3, 3, 3, 3, 3, 3, 3, 3, // 8+
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 16+
|
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 32+
|
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 64+
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 128+
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
|
|
};
|
|
return bitIndex;
|
|
}
|
|
|
|
ANTLR_INLINE const ANTLR_UINT64* IntTrieBase::get_bitMask()
|
|
{
|
|
static ANTLR_UINT64 bitMask[64] =
|
|
{
|
|
0x0000000000000001ULL, 0x0000000000000002ULL, 0x0000000000000004ULL, 0x0000000000000008ULL,
|
|
0x0000000000000010ULL, 0x0000000000000020ULL, 0x0000000000000040ULL, 0x0000000000000080ULL,
|
|
0x0000000000000100ULL, 0x0000000000000200ULL, 0x0000000000000400ULL, 0x0000000000000800ULL,
|
|
0x0000000000001000ULL, 0x0000000000002000ULL, 0x0000000000004000ULL, 0x0000000000008000ULL,
|
|
0x0000000000010000ULL, 0x0000000000020000ULL, 0x0000000000040000ULL, 0x0000000000080000ULL,
|
|
0x0000000000100000ULL, 0x0000000000200000ULL, 0x0000000000400000ULL, 0x0000000000800000ULL,
|
|
0x0000000001000000ULL, 0x0000000002000000ULL, 0x0000000004000000ULL, 0x0000000008000000ULL,
|
|
0x0000000010000000ULL, 0x0000000020000000ULL, 0x0000000040000000ULL, 0x0000000080000000ULL,
|
|
0x0000000100000000ULL, 0x0000000200000000ULL, 0x0000000400000000ULL, 0x0000000800000000ULL,
|
|
0x0000001000000000ULL, 0x0000002000000000ULL, 0x0000004000000000ULL, 0x0000008000000000ULL,
|
|
0x0000010000000000ULL, 0x0000020000000000ULL, 0x0000040000000000ULL, 0x0000080000000000ULL,
|
|
0x0000100000000000ULL, 0x0000200000000000ULL, 0x0000400000000000ULL, 0x0000800000000000ULL,
|
|
0x0001000000000000ULL, 0x0002000000000000ULL, 0x0004000000000000ULL, 0x0008000000000000ULL,
|
|
0x0010000000000000ULL, 0x0020000000000000ULL, 0x0040000000000000ULL, 0x0080000000000000ULL,
|
|
0x0100000000000000ULL, 0x0200000000000000ULL, 0x0400000000000000ULL, 0x0800000000000000ULL,
|
|
0x1000000000000000ULL, 0x2000000000000000ULL, 0x4000000000000000ULL, 0x8000000000000000ULL
|
|
};
|
|
|
|
return bitMask;
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
IntTrie<ImplTraits, DataType>::IntTrie( ANTLR_UINT32 depth )
|
|
{
|
|
/* Now we need to allocate the root node. This makes it easier
|
|
* to use the tree as we don't have to do anything special
|
|
* for the root node.
|
|
*/
|
|
m_root = new IntTrieNodeType;
|
|
|
|
/* Now we seed the root node with the index being the
|
|
* highest left most bit we want to test, which limits the
|
|
* keys in the trie. This is the trie 'depth'. The limit for
|
|
* this implementation is 63 (bits 0..63).
|
|
*/
|
|
m_root->set_bitNum( depth );
|
|
|
|
/* And as we have nothing in here yet, we set both child pointers
|
|
* of the root node to point back to itself.
|
|
*/
|
|
m_root->set_leftN( m_root );
|
|
m_root->set_rightN( m_root );
|
|
m_count = 0;
|
|
|
|
/* Finally, note that the key for this root node is 0 because
|
|
* we use calloc() to initialise it.
|
|
*/
|
|
m_allowDups = false;
|
|
m_current = NULL;
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
IntTrie<ImplTraits, DataType>::~IntTrie()
|
|
{
|
|
/* Descend from the root and free all the nodes
|
|
*/
|
|
delete m_root;
|
|
|
|
/* the nodes are all gone now, so we need only free the memory
|
|
* for the structure itself
|
|
*/
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
typename IntTrie<ImplTraits, DataType>::TrieEntryType* IntTrie<ImplTraits, DataType>::get( ANTLR_INTKEY key)
|
|
{
|
|
IntTrieNodeType* thisNode;
|
|
IntTrieNodeType* nextNode;
|
|
|
|
if (m_count == 0)
|
|
return NULL; /* Nothing in this trie yet */
|
|
|
|
/* Starting at the root node in the trie, compare the bit index
|
|
* of the current node with its next child node (starts left from root).
|
|
* When the bit index of the child node is greater than the bit index of the current node
|
|
* then by definition (as the bit index decreases as we descent the trie)
|
|
* we have reached a 'backward' pointer. A backward pointer means we
|
|
* have reached the only node that can be reached by the bits given us so far
|
|
* and it must either be the key we are looking for, or if not then it
|
|
* means the entry was not in the trie, and we return NULL. A backward pointer
|
|
* points back in to the tree structure rather than down (deeper) within the
|
|
* tree branches.
|
|
*/
|
|
thisNode = m_root; /* Start at the root node */
|
|
nextNode = thisNode->get_leftN(); /* Examine the left node from the root */
|
|
|
|
/* While we are descending the tree nodes...
|
|
*/
|
|
const ANTLR_UINT64* bitMask = this->get_bitMask();
|
|
while( thisNode->get_bitNum() > nextNode->get_bitNum() )
|
|
{
|
|
/* Next node now becomes the new 'current' node
|
|
*/
|
|
thisNode = nextNode;
|
|
|
|
/* We now test the bit indicated by the bitmap in the next node
|
|
* in the key we are searching for. The new next node is the
|
|
* right node if that bit is set and the left node it is not.
|
|
*/
|
|
if (key & bitMask[nextNode->get_bitNum()])
|
|
{
|
|
nextNode = nextNode->get_rightN(); /* 1 is right */
|
|
}
|
|
else
|
|
{
|
|
nextNode = nextNode->get_leftN(); /* 0 is left */
|
|
}
|
|
}
|
|
|
|
/* Here we have reached a node where the bitMap index is lower than
|
|
* its parent. This means it is pointing backward in the tree and
|
|
* must therefore be a terminal node, being the only point than can
|
|
* be reached with the bits seen so far. It is either the actual key
|
|
* we wanted, or if that key is not in the trie it is another key
|
|
* that is currently the only one that can be reached by those bits.
|
|
* That situation would obviously change if the key was to be added
|
|
* to the trie.
|
|
*
|
|
* Hence it only remains to test whether this is actually the key or not.
|
|
*/
|
|
if (nextNode->get_key() == key)
|
|
{
|
|
/* This was the key, so return the entry pointer
|
|
*/
|
|
return nextNode->get_buckets();
|
|
}
|
|
else
|
|
{
|
|
return NULL; /* That key is not in the trie (note that we set the pointer to -1 if no payload) */
|
|
}
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
bool IntTrie<ImplTraits, DataType>::del( ANTLR_INTKEY key)
|
|
{
|
|
IntTrieNodeType* p;
|
|
|
|
p = m_root;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
bool IntTrie<ImplTraits, DataType>::add( ANTLR_INTKEY key, const DataType& data )
|
|
{
|
|
IntTrieNodeType* thisNode;
|
|
IntTrieNodeType* nextNode;
|
|
IntTrieNodeType* entNode;
|
|
ANTLR_UINT32 depth;
|
|
TrieEntryType* newEnt;
|
|
TrieEntryType* nextEnt;
|
|
ANTLR_INTKEY xorKey;
|
|
|
|
/* Cache the bit depth of this trie, which is always the highest index,
|
|
* which is in the root node
|
|
*/
|
|
depth = m_root->get_bitNum();
|
|
|
|
thisNode = m_root; /* Start with the root node */
|
|
nextNode = m_root->get_leftN(); /* And assume we start to the left */
|
|
|
|
/* Now find the only node that can be currently reached by the bits in the
|
|
* key we are being asked to insert.
|
|
*/
|
|
const ANTLR_UINT64* bitMask = this->get_bitMask();
|
|
while (thisNode->get_bitNum() > nextNode->get_bitNum() )
|
|
{
|
|
/* Still descending the structure, next node becomes current.
|
|
*/
|
|
thisNode = nextNode;
|
|
|
|
if (key & bitMask[nextNode->get_bitNum()])
|
|
{
|
|
/* Bit at the required index was 1, so travers the right node from here
|
|
*/
|
|
nextNode = nextNode->get_rightN();
|
|
}
|
|
else
|
|
{
|
|
/* Bit at the required index was 0, so we traverse to the left
|
|
*/
|
|
nextNode = nextNode->get_leftN();
|
|
}
|
|
}
|
|
/* Here we have located the only node that can be reached by the
|
|
* bits in the requested key. It could in fact be that key or the node
|
|
* we need to use to insert the new key.
|
|
*/
|
|
if (nextNode->get_key() == key)
|
|
{
|
|
/* We have located an exact match, but we will only append to the bucket chain
|
|
* if this trie accepts duplicate keys.
|
|
*/
|
|
if (m_allowDups ==true)
|
|
{
|
|
/* Yes, we are accepting duplicates
|
|
*/
|
|
newEnt = new TrieEntryType(data, NULL);
|
|
|
|
/* We want to be able to traverse the stored elements in the order that they were
|
|
* added as duplicate keys. We might need to revise this opinion if we end up having many duplicate keys
|
|
* as perhaps reverse order is just as good, so long as it is ordered.
|
|
*/
|
|
nextEnt = nextNode->get_buckets();
|
|
while (nextEnt->get_next() != NULL)
|
|
{
|
|
nextEnt = nextEnt->get_next();
|
|
}
|
|
nextEnt->set_next(newEnt);
|
|
|
|
m_count++;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
/* We found the key is already there and we are not allowed duplicates in this
|
|
* trie.
|
|
*/
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Here we have discovered the only node that can be reached by the bits in the key
|
|
* but we have found that this node is not the key we need to insert. We must find the
|
|
* the leftmost bit by which the current key for that node and the new key we are going
|
|
* to insert, differ. While this nested series of ifs may look a bit strange, experimentation
|
|
* showed that it allows a machine code path that works well with predicated execution
|
|
*/
|
|
xorKey = (key ^ nextNode->get_key() ); /* Gives 1 bits only where they differ then we find the left most 1 bit*/
|
|
|
|
/* Most common case is a 32 bit key really
|
|
*/
|
|
const ANTLR_UINT8* bitIndex = this->get_bitIndex();
|
|
#ifdef ANTLR_USE_64BIT
|
|
if (xorKey & 0xFFFFFFFF00000000)
|
|
{
|
|
if (xorKey & 0xFFFF000000000000)
|
|
{
|
|
if (xorKey & 0xFF00000000000000)
|
|
{
|
|
depth = 56 + bitIndex[((xorKey & 0xFF00000000000000)>>56)];
|
|
}
|
|
else
|
|
{
|
|
depth = 48 + bitIndex[((xorKey & 0x00FF000000000000)>>48)];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xorKey & 0x0000FF0000000000)
|
|
{
|
|
depth = 40 + bitIndex[((xorKey & 0x0000FF0000000000)>>40)];
|
|
}
|
|
else
|
|
{
|
|
depth = 32 + bitIndex[((xorKey & 0x000000FF00000000)>>32)];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (xorKey & 0x00000000FFFF0000)
|
|
{
|
|
if (xorKey & 0x00000000FF000000)
|
|
{
|
|
depth = 24 + bitIndex[((xorKey & 0x00000000FF000000)>>24)];
|
|
}
|
|
else
|
|
{
|
|
depth = 16 + bitIndex[((xorKey & 0x0000000000FF0000)>>16)];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xorKey & 0x000000000000FF00)
|
|
{
|
|
depth = 8 + bitIndex[((xorKey & 0x0000000000000FF00)>>8)];
|
|
}
|
|
else
|
|
{
|
|
depth = bitIndex[xorKey & 0x00000000000000FF];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We have located the leftmost differing bit, indicated by the depth variable. So, we know what
|
|
* bit index we are to insert the new entry at. There are two cases, being where the two keys
|
|
* differ at a bit position that is not currently part of the bit testing, where they differ on a bit
|
|
* that is currently being skipped in the indexed comparisons, and where they differ on a bit
|
|
* that is merely lower down in the current bit search. If the bit index went bit 4, bit 2 and they differ
|
|
* at bit 3, then we have the "skipped" bit case. But if that chain was Bit 4, Bit 2 and they differ at bit 1
|
|
* then we have the easy bit <pun>.
|
|
*
|
|
* So, set up to descend the tree again, but this time looking for the insert point
|
|
* according to whether we skip the bit that differs or not.
|
|
*/
|
|
thisNode = m_root;
|
|
entNode = m_root->get_leftN();
|
|
|
|
/* Note the slight difference in the checks here to cover both cases
|
|
*/
|
|
while (thisNode->get_bitNum() > entNode->get_bitNum() && entNode->get_bitNum() > depth)
|
|
{
|
|
/* Still descending the structure, next node becomes current.
|
|
*/
|
|
thisNode = entNode;
|
|
|
|
if (key & bitMask[entNode->get_bitNum()])
|
|
{
|
|
/* Bit at the required index was 1, so traverse the right node from here
|
|
*/
|
|
entNode = entNode->get_rightN();
|
|
}
|
|
else
|
|
{
|
|
/* Bit at the required index was 0, so we traverse to the left
|
|
*/
|
|
entNode = entNode->get_leftN();
|
|
}
|
|
}
|
|
|
|
/* We have located the correct insert point for this new key, so we need
|
|
* to allocate our entry and insert it etc.
|
|
*/
|
|
nextNode = new IntTrieNodeType();
|
|
|
|
/* Build a new entry block for the new node
|
|
*/
|
|
newEnt = new TrieEntryType(data, NULL);
|
|
|
|
/* Install it
|
|
*/
|
|
nextNode->set_buckets(newEnt);
|
|
nextNode->set_key(key);
|
|
nextNode->set_bitNum( depth );
|
|
|
|
/* Work out the right and left pointers for this new node, which involve
|
|
* terminating with the current found node either right or left according
|
|
* to whether the current index bit is 1 or 0
|
|
*/
|
|
if (key & bitMask[depth])
|
|
{
|
|
nextNode->set_leftN(entNode); /* Terminates at previous position */
|
|
nextNode->set_rightN(nextNode); /* Terminates with itself */
|
|
}
|
|
else
|
|
{
|
|
nextNode->set_rightN(entNode); /* Terminates at previous position */
|
|
nextNode->set_leftN(nextNode); /* Terminates with itself */
|
|
}
|
|
|
|
/* Finally, we need to change the pointers at the node we located
|
|
* for inserting. If the key bit at its index is set then the right
|
|
* pointer for that node becomes the newly created node, otherwise the left
|
|
* pointer does.
|
|
*/
|
|
if (key & bitMask[thisNode->get_bitNum()] )
|
|
{
|
|
thisNode->set_rightN( nextNode );
|
|
}
|
|
else
|
|
{
|
|
thisNode->set_leftN(nextNode);
|
|
}
|
|
|
|
/* Et voila
|
|
*/
|
|
m_count++;
|
|
return true;
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
IntTrieNode<ImplTraits, DataType>::IntTrieNode()
|
|
{
|
|
m_bitNum = 0;
|
|
m_key = 0;
|
|
m_buckets = NULL;
|
|
m_leftN = NULL;
|
|
m_rightN = NULL;
|
|
}
|
|
|
|
template< class ImplTraits, class DataType >
|
|
IntTrieNode<ImplTraits, DataType>::~IntTrieNode()
|
|
{
|
|
TrieEntryType* thisEntry;
|
|
TrieEntryType* nextEntry;
|
|
|
|
/* If this node has a left pointer that is not a back pointer
|
|
* then recursively call to free this
|
|
*/
|
|
if ( m_bitNum > m_leftN->get_bitNum())
|
|
{
|
|
/* We have a left node that needs descending, so do it.
|
|
*/
|
|
delete m_leftN;
|
|
}
|
|
|
|
/* The left nodes from here should now be dealt with, so
|
|
* we need to descend any right nodes that are not back pointers
|
|
*/
|
|
if ( m_bitNum > m_rightN->get_bitNum() )
|
|
{
|
|
/* There are some right nodes to descend and deal with.
|
|
*/
|
|
delete m_rightN;
|
|
}
|
|
|
|
/* Now all the children are dealt with, we can destroy
|
|
* this node too
|
|
*/
|
|
thisEntry = m_buckets;
|
|
|
|
while (thisEntry != NULL)
|
|
{
|
|
nextEntry = thisEntry->get_next();
|
|
|
|
/* Now free the data for this bucket entry
|
|
*/
|
|
delete thisEntry;
|
|
thisEntry = nextEntry; /* See if there are any more to free */
|
|
}
|
|
|
|
/* The bucket entry is now gone, so we can free the memory for
|
|
* the entry itself.
|
|
*/
|
|
|
|
/* And that should be it for everything under this node and itself
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* Allocate and initialize a new ANTLR3 topological sorter, which can be
|
|
* used to define edges that identify numerical node indexes that depend on other
|
|
* numerical node indexes, which can then be sorted topologically such that
|
|
* any node is sorted after all its dependent nodes.
|
|
*
|
|
* Use:
|
|
*
|
|
* /verbatim
|
|
|
|
pANTLR3_TOPO topo;
|
|
topo = antlr3NewTopo();
|
|
|
|
if (topo == NULL) { out of memory }
|
|
|
|
topo->addEdge(topo, 3, 0); // Node 3 depends on node 0
|
|
topo->addEdge(topo, 0, 1); // Node - depends on node 1
|
|
topo->sortVector(topo, myVector); // Sort the vector in place (node numbers are the vector entry numbers)
|
|
|
|
* /verbatim
|
|
*/
|
|
template<class ImplTraits>
|
|
Topo<ImplTraits>::Topo()
|
|
{
|
|
// Initialize variables
|
|
//
|
|
m_visited = NULL; // Don't know how big it is yet
|
|
m_limit = 1; // No edges added yet
|
|
m_edges = NULL; // No edges added yet
|
|
m_sorted = NULL; // Nothing sorted at the start
|
|
m_cycle = NULL; // No cycles at the start
|
|
m_cycleMark = 0; // No cycles at the start
|
|
m_hasCycle = false; // No cycle at the start
|
|
}
|
|
|
|
// Topological sorter
|
|
//
|
|
template<class ImplTraits>
|
|
void Topo<ImplTraits>::addEdge(ANTLR_UINT32 edge, ANTLR_UINT32 dependency)
|
|
{
|
|
ANTLR_UINT32 i;
|
|
ANTLR_UINT32 maxEdge;
|
|
BitsetType* edgeDeps;
|
|
|
|
if (edge>dependency)
|
|
{
|
|
maxEdge = edge;
|
|
}
|
|
else
|
|
{
|
|
maxEdge = dependency;
|
|
}
|
|
// We need to add an edge to says that the node indexed by 'edge' is
|
|
// dependent on the node indexed by 'dependency'
|
|
//
|
|
|
|
// First see if we have enough room in the edges array to add the edge?
|
|
//
|
|
if ( m_edges == NULL)
|
|
{
|
|
// We don't have any edges yet, so create an array to hold them
|
|
//
|
|
m_edges = AllocPolicyType::alloc0(sizeof(BitsetType*) * (maxEdge + 1));
|
|
|
|
// Set the limit to what we have now
|
|
//
|
|
m_limit = maxEdge + 1;
|
|
}
|
|
else if (m_limit <= maxEdge)
|
|
{
|
|
// WE have some edges but not enough
|
|
//
|
|
m_edges = AllocPolicyType::realloc(m_edges, sizeof(BitsetType*) * (maxEdge + 1));
|
|
|
|
// Initialize the new bitmaps to ;indicate we have no edges defined yet
|
|
//
|
|
for (i = m_limit; i <= maxEdge; i++)
|
|
{
|
|
*((m_edges) + i) = NULL;
|
|
}
|
|
|
|
// Set the limit to what we have now
|
|
//
|
|
m_limit = maxEdge + 1;
|
|
}
|
|
|
|
// If the edge was flagged as depending on itself, then we just
|
|
// do nothing as it means this routine was just called to add it
|
|
// in to the list of nodes.
|
|
//
|
|
if (edge == dependency)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Pick up the bit map for the requested edge
|
|
//
|
|
edgeDeps = *((m_edges) + edge);
|
|
|
|
if (edgeDeps == NULL)
|
|
{
|
|
// No edges are defined yet for this node
|
|
//
|
|
edgeDeps = new BitsetType(0);
|
|
*((m_edges) + edge) = edgeDeps;
|
|
}
|
|
|
|
// Set the bit in the bitmap that corresponds to the requested
|
|
// dependency.
|
|
//
|
|
edgeDeps->add(dependency);
|
|
|
|
// And we are all set
|
|
//
|
|
return;
|
|
|
|
}
|
|
|
|
/**
|
|
* Given a starting node, descend its dependent nodes (ones that it has edges
|
|
* to) until we find one without edges. Having found a node without edges, we have
|
|
* discovered the bottom of a depth first search, which we can then ascend, adding
|
|
* the nodes in order from the bottom, which gives us the dependency order.
|
|
*/
|
|
template<class ImplTraits>
|
|
void Topo<ImplTraits>::DFS(ANTLR_UINT32 node)
|
|
{
|
|
BitsetType* edges;
|
|
|
|
// Guard against a revisit and check for cycles
|
|
//
|
|
if (m_hasCycle == true)
|
|
{
|
|
return; // We don't do anything else if we found a cycle
|
|
}
|
|
|
|
if ( m_visited->isMember(node))
|
|
{
|
|
// Check to see if we found a cycle. To do this we search the
|
|
// current cycle stack and see if we find this node already in the stack.
|
|
//
|
|
ANTLR_UINT32 i;
|
|
|
|
for (i=0; i< m_cycleMark; i++)
|
|
{
|
|
if ( m_cycle[i] == node)
|
|
{
|
|
// Stop! We found a cycle in the input, so rejig the cycle
|
|
// stack so that it only contains the cycle and set the cycle flag
|
|
// which will tell the caller what happened
|
|
//
|
|
ANTLR_UINT32 l;
|
|
|
|
for (l = i; l < m_cycleMark; l++)
|
|
{
|
|
m_cycle[l - i] = m_cycle[l]; // Move to zero base in the cycle list
|
|
}
|
|
|
|
// Recalculate the limit
|
|
//
|
|
m_cycleMark -= i;
|
|
|
|
// Signal disaster
|
|
//
|
|
m_hasCycle = true;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// So far, no cycles have been found and we have not visited this node yet,
|
|
// so this node needs to go into the cycle stack before we continue
|
|
// then we will take it out of the stack once we have descended all its
|
|
// dependencies.
|
|
//
|
|
m_cycle[m_cycleMark++] = node;
|
|
|
|
// First flag that we have visited this node
|
|
//
|
|
m_visited->add(node);
|
|
|
|
// Now, if this node has edges, then we want to ensure we visit
|
|
// them all before we drop through and add this node into the sorted
|
|
// list.
|
|
//
|
|
edges = *((m_edges) + node);
|
|
if (edges != NULL)
|
|
{
|
|
// We have some edges, so visit each of the edge nodes
|
|
// that have not already been visited.
|
|
//
|
|
ANTLR_UINT32 numBits; // How many bits are in the set
|
|
ANTLR_UINT32 i;
|
|
ANTLR_UINT32 range;
|
|
|
|
numBits = edges->numBits();
|
|
range = edges->size(); // Number of set bits
|
|
|
|
// Stop if we exahust the bit list or have checked the
|
|
// number of edges that this node refers to (so we don't
|
|
// check bits at the end that cannot possibly be set).
|
|
//
|
|
for (i=0; i<= numBits && range > 0; i++)
|
|
{
|
|
if (edges->isMember(i))
|
|
{
|
|
range--; // About to check another one
|
|
|
|
// Found an edge, make sure we visit and descend it
|
|
//
|
|
this->DFS(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// At this point we will have visited all the dependencies
|
|
// of this node and they will be ordered (even if there are cycles)
|
|
// So we just add the node into the sorted list at the
|
|
// current index position.
|
|
//
|
|
m_sorted[m_limit++] = node;
|
|
|
|
// Remove this node from the cycle list if we have not detected a cycle
|
|
//
|
|
if (m_hasCycle == false)
|
|
{
|
|
m_cycleMark--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
template<class ImplTraits>
|
|
ANTLR_UINT32* Topo<ImplTraits>::sortToArray()
|
|
{
|
|
ANTLR_UINT32 v;
|
|
ANTLR_UINT32 oldLimit;
|
|
|
|
// Guard against being called with no edges defined
|
|
//
|
|
if (m_edges == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
// First we need a vector to populate with enough
|
|
// entries to accomodate the sorted list and another to accomodate
|
|
// the maximum cycle we could detect which is all nodes such as 0->1->2->3->0
|
|
//
|
|
m_sorted = AllocPolicyType::alloc( m_limit * sizeof(ANTLR_UINT32) );
|
|
m_cycle = AllocPolicyType::alloc( m_limit * sizeof(ANTLR_UINT32));
|
|
|
|
// Next we need an empty bitset to show whether we have visited a node
|
|
// or not. This is the bit that gives us linear time of course as we are essentially
|
|
// dropping through the nodes in depth first order and when we get to a node that
|
|
// has no edges, we pop back up the stack adding the nodes we traversed in reverse
|
|
// order.
|
|
//
|
|
m_visited = new BitsetType(0);
|
|
|
|
// Now traverse the nodes as if we were just going left to right, but
|
|
// then descend each node unless it has already been visited.
|
|
//
|
|
oldLimit = m_limit; // Number of nodes to traverse linearly
|
|
m_limit = 0; // Next entry in the sorted table
|
|
|
|
for (v = 0; v < oldLimit; v++)
|
|
{
|
|
// If we did not already visit this node, then descend it until we
|
|
// get a node without edges or arrive at a node we have already visited.
|
|
//
|
|
if (m_visited->isMember(v) == false)
|
|
{
|
|
// We have not visited this one so descend it
|
|
//
|
|
this->DFS(v);
|
|
}
|
|
|
|
// Break the loop if we detect a cycle as we have no need to go any
|
|
// further
|
|
//
|
|
if (m_hasCycle == true)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Reset the limit to the number we recorded as if we hit a
|
|
// cycle, then limit will have stopped at the node where we
|
|
// discovered the cycle, but in order to free the edge bitmaps
|
|
// we need to know how many we may have allocated and traverse them all.
|
|
//
|
|
m_limit = oldLimit;
|
|
|
|
// Having traversed all the nodes we were given, we
|
|
// are guaranteed to have ordered all the nodes or detected a
|
|
// cycle.
|
|
//
|
|
return m_sorted;
|
|
}
|
|
|
|
template<class ImplTraits>
|
|
template<typename DataType>
|
|
void Topo<ImplTraits>::sortVector( typename ImplTraits::template VectorType<DataType>& v )
|
|
{
|
|
// To sort a vector, we first perform the
|
|
// sort to an array, then use the results to reorder the vector
|
|
// we are given. This is just a convenience routine that allows you to
|
|
// sort the children of a tree node into topological order before or
|
|
// during an AST walk. This can be useful for optimizations that require
|
|
// dag reorders and also when the input stream defines thigns that are
|
|
// interdependent and you want to walk the list of the generated trees
|
|
// for those things in topological order so you can ignore the interdependencies
|
|
// at that point.
|
|
//
|
|
ANTLR_UINT32 i;
|
|
|
|
// Used as a lookup index to find the current location in the vector of
|
|
// the vector entry that was originally at position [0], [1], [2] etc
|
|
//
|
|
ANTLR_UINT32* vIndex;
|
|
|
|
// Sort into an array, then we can use the array that is
|
|
// stored in the topo
|
|
//
|
|
if (this->sortToArray() == 0)
|
|
{
|
|
return; // There were no edges
|
|
}
|
|
|
|
if (m_hasCycle == true)
|
|
{
|
|
return; // Do nothing if we detected a cycle
|
|
}
|
|
|
|
// Ensure that the vector we are sorting is at least as big as the
|
|
// the input sequence we were adsked to sort. It does not matter if it is
|
|
// bigger as thaat probably just means that nodes numbered higher than the
|
|
// limit had no dependencies and so can be left alone.
|
|
//
|
|
if (m_limit > v.size() )
|
|
{
|
|
// We can only sort the entries that we have dude! The caller is
|
|
// responsible for ensuring the vector is the correct one and is the
|
|
// correct size etc.
|
|
//
|
|
m_limit = v.size();
|
|
}
|
|
// We need to know the locations of each of the entries
|
|
// in the vector as we don't want to duplicate them in a new vector. We
|
|
// just use an indirection table to get the vector entry for a particular sequence
|
|
// acording to where we moved it last. Then we can just swap vector entries until
|
|
// we are done :-)
|
|
//
|
|
vIndex = AllocPolicyType::alloc(m_limit * sizeof(ANTLR_UINT32));
|
|
|
|
// Start index, each vector entry is located where you think it is
|
|
//
|
|
for (i = 0; i < m_limit; i++)
|
|
{
|
|
vIndex[i] = i;
|
|
}
|
|
|
|
// Now we traverse the sorted array and moved the entries of
|
|
// the vector around according to the sort order and the indirection
|
|
// table we just created. The index telsl us where in the vector the
|
|
// original element entry n is now located via vIndex[n].
|
|
//
|
|
for (i=0; i < m_limit; i++)
|
|
{
|
|
ANTLR_UINT32 ind;
|
|
|
|
// If the vector entry at i is already the one that it
|
|
// should be, then we skip moving it of course.
|
|
//
|
|
if (vIndex[m_sorted[i]] == i)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// The vector entry at i, should be replaced with the
|
|
// vector entry indicated by topo->sorted[i]. The vector entry
|
|
// at topo->sorted[i] may have already been swapped out though, so we
|
|
// find where it is now and move it from there to i.
|
|
//
|
|
ind = vIndex[m_sorted[i]];
|
|
std::swap( v[i], v[ind] );
|
|
|
|
// Update our index. The element at i is now the one we wanted
|
|
// to be sorted here and the element we swapped out is now the
|
|
// element that was at i just before we swapped it. If you are lost now
|
|
// don't worry about it, we are just reindexing on the fly is all.
|
|
//
|
|
vIndex[m_sorted[i]] = i;
|
|
vIndex[i] = ind;
|
|
}
|
|
|
|
// Having traversed all the entries, we have sorted the vector in place.
|
|
//
|
|
AllocPolicyType::free(vIndex);
|
|
return;
|
|
}
|
|
|
|
template<class ImplTraits>
|
|
Topo<ImplTraits>::~Topo()
|
|
{
|
|
ANTLR_UINT32 i;
|
|
|
|
// Free the result vector
|
|
//
|
|
if (m_sorted != NULL)
|
|
{
|
|
AllocPolicyType::free(m_sorted);
|
|
}
|
|
|
|
// Free the visited map
|
|
//
|
|
if (m_visited != NULL)
|
|
{
|
|
delete m_visited;
|
|
}
|
|
|
|
// Free any edgemaps
|
|
//
|
|
if (m_edges != NULL)
|
|
{
|
|
Bitset<AllocPolicyType>* edgeList;
|
|
|
|
for (i=0; i<m_limit; i++)
|
|
{
|
|
edgeList = *((m_edges) + i);
|
|
if (edgeList != NULL)
|
|
{
|
|
delete edgeList;
|
|
}
|
|
}
|
|
|
|
AllocPolicyType::free( m_edges );
|
|
}
|
|
m_edges = NULL;
|
|
|
|
// Free any cycle map
|
|
//
|
|
if (m_cycle != NULL)
|
|
{
|
|
AllocPolicyType::free(m_cycle);
|
|
}
|
|
}
|
|
|
|
|
|
ANTLR_END_NAMESPACE()
|