<tb@panthema.net>
<http://www.gnu.org/licenses/>
template <typename Comparator>
class LoserTree3Way
{
private:
static const uint32_t EqualMark = 0x80000000;
static const uint32_t DoneMark = 0x7FFFFFFF;
const Comparator& m_cmp;
unsigned int m_size;
std::vector<uint32_t> m_tree;
bool m_top_equal;
bool m_done;
public:
LoserTree3Way(const Comparator& cmp)
: m_cmp(cmp)
{
}
bool play_initial(unsigned int size)
{
m_size = size;
m_top_equal = false;
m_done = false;
unsigned int treesize = (1 << (int)(log2(size - 1) + 2)) - 1;
if (treesize == 0) treesize = 1;
m_tree.resize(treesize, DoneMark);
int levelput = m_tree.size() / 2;
for (unsigned int i = 0; i < m_size; ++i)
{
m_tree[levelput + i] = m_cmp.exists(i) ? i : DoneMark;
}
unsigned int levelsize = levelput + 1;
while ( levelsize > 1 )
{
levelsize = levelsize / 2;
int levelget = levelput;
levelput /= 2;
for (unsigned int i = 0; i < levelsize; ++i)
{
if ( m_tree[levelget + 2*i + 1] == DoneMark )
m_tree[levelput + i] = m_tree[levelget + 2*i] & ~EqualMark;
else if ( m_tree[levelget + 2*i] == DoneMark )
m_tree[levelput + i] = m_tree[levelget + 2*i + 1] & ~EqualMark;
else
{
int cmp = m_cmp( m_tree[levelget + 2*i] & ~EqualMark, m_tree[levelget + 2*i + 1] & ~EqualMark );
if (cmp < 0)
m_tree[levelput + i] = m_tree[levelget + 2*i] & ~EqualMark;
else if (cmp == 0)
m_tree[levelput + i] = m_tree[levelget + 2*i] | EqualMark;
else
m_tree[levelput + i] = m_tree[levelget + 2*i + 1] & ~EqualMark;
}
}
}
m_top_equal = false;
return (m_done = (m_tree[0] == DoneMark));
}
unsigned int top() const
{
return m_tree[0] & ~EqualMark;
}
bool top_equal() const
{
return m_top_equal;
}
bool replay()
{
m_top_equal = (m_tree[0] & EqualMark);
int top = m_tree[0] & ~EqualMark;
int p = (m_tree.size() / 2) + top;
if (!m_cmp.exists(top)) top = DoneMark;
while( p > 0 )
{
m_tree[p] = top;
p -= (p+1) % 2;
if (m_tree[p] == DoneMark)
top = m_tree[p+1] & ~EqualMark;
else if (m_tree[p+1] == DoneMark)
top = m_tree[p] & ~EqualMark;
else
if (m_tree[p/2] & EqualMark)
{
top = m_tree[p+1] & ~EqualMark;
}
else
{
int cmp = m_cmp( m_tree[p] & ~EqualMark, m_tree[p+1] & ~EqualMark );
if ( cmp < 0 )
top = m_tree[p] & ~EqualMark;
else if (cmp == 0)
top = m_tree[p] | EqualMark;
else
top = m_tree[p+1] & ~EqualMark;
}
p /= 2;
}
assert(p == 0);
m_tree[0] = top;
return (m_done = (m_tree[0] == DoneMark));
}
bool done() const
{
return m_done;
}
void print() const
{
unsigned int levelsize = 1;
unsigned int j = 0;
for (unsigned int i = 0; i < m_tree.size(); ++i)
{
if (i >= j + levelsize) {
std::cout << "\n";
j = i; levelsize *= 2;
}
std::cout << (m_tree[i] & ~EqualMark) << ((m_tree[i] & EqualMark) ? 'e' : ' ') << " ";
}
std::cout << "\n";
}
};