mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-11-26 22:11:52 +00:00
4597b03873
Opens in Android Studio but haven't even tried to build it yet (it won't.. I know that much!)
1626 lines
46 KiB
C++
1626 lines
46 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2000 - 2013, Raven Software, Inc.
|
|
Copyright (C) 2001 - 2013, Activision, Inc.
|
|
Copyright (C) 2013 - 2015, OpenJK contributors
|
|
|
|
This file is part of the OpenJK source code.
|
|
|
|
OpenJK is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License version 2 as
|
|
published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
===========================================================================
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
|
// (c) 2002 Activision
|
|
//
|
|
//
|
|
// Map
|
|
// ---
|
|
// This map is based on a red black tree, which guarentees balanced data, no mater what
|
|
// order elements are added. The map uses a memory pool for storage of node data.
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
#if !defined(RATL_MAP_VS_INC)
|
|
#define RATL_MAP_VS_INC
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
#if defined(RA_DEBUG_LINKING)
|
|
#pragma message("...including map_vs.h")
|
|
#endif
|
|
#if !defined(RATL_COMMON_INC)
|
|
#include "ratl_common.h"
|
|
#endif
|
|
#if !defined(RATL_POOL_VS_INC)
|
|
#include "pool_vs.h"
|
|
#endif
|
|
namespace ratl
|
|
{
|
|
|
|
|
|
// this is private to the set, but you have no access to it, soooo..
|
|
|
|
class tree_node
|
|
{
|
|
int mParent;
|
|
int mLeft;
|
|
int mRight;
|
|
public:
|
|
enum
|
|
{
|
|
RED_BIT = 0x40000000, // to save space we are putting the red bool in a high bit
|
|
// this is in the parent only
|
|
NULL_NODE = 0x3fffffff, // this must not have the red bit set
|
|
};
|
|
void init()
|
|
{
|
|
mLeft = NULL_NODE;
|
|
mRight = NULL_NODE;
|
|
mParent = NULL_NODE | RED_BIT;
|
|
}
|
|
int left() const
|
|
{
|
|
return mLeft;
|
|
}
|
|
int right() const
|
|
{
|
|
return mRight;
|
|
}
|
|
int parent() const
|
|
{
|
|
return mParent & (~RED_BIT);
|
|
}
|
|
bool red() const
|
|
{
|
|
return !!(mParent & RED_BIT);
|
|
}
|
|
void set_left(int l)
|
|
{
|
|
mLeft = l;
|
|
}
|
|
void set_right(int r)
|
|
{
|
|
mRight = r;
|
|
}
|
|
void set_parent(int p)
|
|
{
|
|
mParent &= RED_BIT;
|
|
mParent |= p;
|
|
}
|
|
void set_red(bool isRed)
|
|
{
|
|
if (isRed)
|
|
{
|
|
mParent |= RED_BIT;
|
|
}
|
|
else
|
|
{
|
|
mParent &= ~RED_BIT;
|
|
}
|
|
}
|
|
};
|
|
|
|
//fixme void *, comparison function pointer-ize this for code bloat.
|
|
|
|
template<class T, int IS_MULTI>
|
|
class tree_base
|
|
{
|
|
public:
|
|
typedef T TStorageTraits;
|
|
typedef typename T::TValue TTValue;
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Capacity Enum
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
static const int CAPACITY = T::CAPACITY;
|
|
|
|
private:
|
|
pool_base<TStorageTraits> mPool; // The Allocation Data Pool
|
|
int mRoot;
|
|
int mLastAdd;
|
|
|
|
|
|
void link_left(int node,int left)
|
|
{
|
|
T::node(mPool[node]).set_left(left);
|
|
if (left!=tree_node::NULL_NODE)
|
|
{
|
|
T::node(mPool[left]).set_parent(node);
|
|
}
|
|
}
|
|
|
|
void link_right(int node,int right)
|
|
{
|
|
T::node(mPool[node]).set_right(right);
|
|
if (right!=tree_node::NULL_NODE)
|
|
{
|
|
T::node(mPool[right]).set_parent(node);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive find function - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int find_internal(const TTValue &key, int at) const
|
|
{
|
|
|
|
// FAIL TO FIND?
|
|
//---------------
|
|
if (at==tree_node::NULL_NODE)
|
|
{
|
|
return tree_node::NULL_NODE;
|
|
}
|
|
|
|
// Should We Search Left?
|
|
//------------------------
|
|
if (key<mPool[at])
|
|
{
|
|
return find_internal(key, T::node(mPool[at]).left());
|
|
}
|
|
|
|
// Should We Search Right?
|
|
//------------------------
|
|
else if (mPool[at]<key)
|
|
{
|
|
return find_internal(key, T::node(mPool[at]).right());
|
|
}
|
|
|
|
// FOUND!
|
|
//--------
|
|
return at;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive find function - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int find_internal(const TTValue &key, int target, int at, int& parent) const
|
|
{
|
|
// FAIL TO FIND?
|
|
//---------------
|
|
if (at==tree_node::NULL_NODE)
|
|
{
|
|
parent = tree_node::NULL_NODE;
|
|
return tree_node::NULL_NODE;
|
|
}
|
|
|
|
// FOUND!
|
|
//--------
|
|
if (at==target)
|
|
{
|
|
if (at==mRoot)
|
|
{
|
|
parent = tree_node::NULL_NODE;
|
|
}
|
|
return at;
|
|
}
|
|
|
|
// Should We Search Left?
|
|
//------------------------
|
|
if (key<mPool[at])
|
|
{
|
|
parent = at;
|
|
return find_internal(key, target, T::node(mPool[at]).left(), parent);
|
|
}
|
|
|
|
parent = at;
|
|
return find_internal(key, target, T::node(mPool[at]).right(), parent);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive insertion - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int insert_internal(const TTValue &key, int &at)
|
|
{
|
|
// If At Is A NULL_NODE, We Have Found A Leaf.
|
|
//----------------------------------------------
|
|
if (at==tree_node::NULL_NODE)
|
|
{
|
|
if (mRoot==tree_node::NULL_NODE)
|
|
{
|
|
mRoot = mLastAdd;
|
|
}
|
|
return tree_node::NULL_NODE; // There Are No Excess Red Children (No Childeren At All, Actually)
|
|
}
|
|
|
|
|
|
int nxtChild; // The Child We Will Eventually Add Underneath
|
|
//int altChild; // The "other" Child
|
|
bool nxtRotateLeft;
|
|
int excessRedChild; // If The Insert Results In An Excess Red Child, This Will Be It
|
|
|
|
|
|
// Choose Which Side To Add The New Node Under
|
|
//---------------------------------------------
|
|
if (key < mPool[at]) // The Key Classes Must Support A < Operator
|
|
{
|
|
int tmp=T::node(mPool[at]).left();
|
|
excessRedChild = insert_internal(key,tmp);
|
|
link_left(at,tmp);//T::node(mPool[at]).set_left(tmp);
|
|
|
|
if (tmp==tree_node::NULL_NODE)
|
|
{
|
|
|
|
link_left(at,mLastAdd);//T::node(mPool[at]).set_left(mLastAdd); // If mLeft Of The Current Node Is NULL, We Must Have Added DIRECTLY Below nAt
|
|
}
|
|
nxtChild = T::node(mPool[at]).left();
|
|
//altChild = T::node(mPool[at]).right();
|
|
nxtRotateLeft = false;
|
|
}
|
|
else if (mPool[at] < key)
|
|
{
|
|
int tmp=T::node(mPool[at]).right();
|
|
excessRedChild = insert_internal(key,tmp);
|
|
link_right(at,tmp); // T::node(mPool[at]).set_right(tmp);
|
|
|
|
if (tmp==tree_node::NULL_NODE)
|
|
{
|
|
link_right(at,mLastAdd); // T::node(mPool[at]).set_right(mLastAdd); // If mRight Of The Current Node Is NULL, We Must Have Added DIRECTLY Below nAt
|
|
}
|
|
nxtChild = T::node(mPool[at]).right();
|
|
//altChild = T::node(mPool[at]).left();
|
|
nxtRotateLeft = true;
|
|
}
|
|
|
|
// Exact Match
|
|
//-------------
|
|
else
|
|
{
|
|
// the node of interest is at
|
|
return tree_node::NULL_NODE;
|
|
}
|
|
|
|
|
|
// If The Add Resulted In An Excess Red Child, We Need To Change Colors And Rotate
|
|
//---------------------------------------------------------------------------------
|
|
if (excessRedChild!=tree_node::NULL_NODE)
|
|
{
|
|
// If Both Childeren Are Red, Just Switch And Be Done
|
|
//----------------------------------------------------
|
|
if (T::node(mPool[at]).right()!=tree_node::NULL_NODE &&
|
|
T::node(mPool[at]).left()!=tree_node::NULL_NODE &&
|
|
T::node(mPool[T::node(mPool[at]).right()]).red() &&
|
|
T::node(mPool[T::node(mPool[at]).left()]).red())
|
|
{
|
|
set_colors(T::node(mPool[at]), true, false);
|
|
}
|
|
else
|
|
{
|
|
int excessRedChildCompare =
|
|
(nxtRotateLeft)?(T::node(mPool[nxtChild]).right()):(T::node(mPool[nxtChild]).left());
|
|
if (excessRedChild==excessRedChildCompare)
|
|
{
|
|
// Single Rotation
|
|
//-----------------
|
|
rotate(at, nxtRotateLeft);
|
|
}
|
|
else
|
|
{
|
|
if (nxtRotateLeft)
|
|
{
|
|
int nxt=T::node(mPool[at]).right();
|
|
rotate(nxt, false);
|
|
link_right(at,nxt); // T::node(mPool[at]).set_right(nxt);
|
|
}
|
|
else
|
|
{
|
|
int nxt=T::node(mPool[at]).left();
|
|
rotate(nxt,true);
|
|
link_left(at,nxt); // T::node(mPool[at]).set_left(nxt);
|
|
}
|
|
rotate(at, nxtRotateLeft);
|
|
}
|
|
|
|
set_colors(T::node(mPool[at]), false, true);
|
|
}
|
|
}
|
|
|
|
if (T::node(mPool[at]).red())
|
|
{
|
|
if (T::node(mPool[at]).left()!=tree_node::NULL_NODE &&
|
|
T::node(mPool[T::node(mPool[at]).left()]).red())
|
|
{
|
|
return T::node(mPool[at]).left();
|
|
}
|
|
if (T::node(mPool[at]).right()!=tree_node::NULL_NODE &&
|
|
T::node(mPool[T::node(mPool[at]).right()]).red())
|
|
{
|
|
return T::node(mPool[at]).right();
|
|
}
|
|
}
|
|
return tree_node::NULL_NODE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive erase - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
bool erase_internal(const TTValue &key, int& at)
|
|
{
|
|
// If At Is A NULL_NODE, We Have Found A Leaf.
|
|
//---------------------------------------------
|
|
if (at==tree_node::NULL_NODE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//==============================================================================
|
|
// Now The Question Is, Do We Need To Continue Searching?
|
|
//==============================================================================
|
|
|
|
|
|
// Recurse To The Left?
|
|
//----------------------
|
|
if (key < mPool[at])
|
|
{
|
|
int a=T::node(mPool[at]).left();
|
|
bool r=erase_internal(key, a);
|
|
link_left(at,a); // T::node(mPool[at]).set_left(a);
|
|
if (!r) // If It Was Not Red, We Need To Rebalance
|
|
{
|
|
return rebalance(at, true);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Recurse To The Right?
|
|
//-----------------------
|
|
if (mPool[at] < key)
|
|
{
|
|
int a=T::node(mPool[at]).right();
|
|
bool r=erase_internal(key, a);
|
|
link_right(at,a); // T::node(mPool[at]).set_right(a);
|
|
if (!r) // If It Was Not Red, We Need To Rebalance
|
|
{
|
|
return rebalance(at, false);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//==============================================================================
|
|
// At This Point, We Must Have Discovered An Exact Match For Our Key
|
|
//==============================================================================
|
|
|
|
|
|
// Are There Any Open Childeren Slots?
|
|
//-------------------------------------
|
|
if (T::node(mPool[at]).left()==tree_node::NULL_NODE || T::node(mPool[at]).right()==tree_node::NULL_NODE)
|
|
{
|
|
bool atWasRed = T::node(mPool[at]).red();
|
|
int oldAt = at;
|
|
|
|
at = (T::node(mPool[at]).left()==tree_node::NULL_NODE)?(T::node(mPool[at]).right()):(T::node(mPool[at]).left()); // If Left Is Null, At Goes Right
|
|
|
|
// Actually Free It!
|
|
//-------------------
|
|
mPool.free(oldAt);
|
|
|
|
// If We Are Now At A Null Node, Just Return
|
|
//-------------------------------------------
|
|
if (at==tree_node::NULL_NODE)
|
|
{
|
|
return atWasRed;
|
|
}
|
|
|
|
// Otherwise, Mark The New Child As Red, And Return That Fact Up
|
|
//---------------------------------------------------------------
|
|
T::node(mPool[at]).set_red(false);
|
|
return true;
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// There Are No Childeren To Link With, We Are In The Middle Of The Tree.
|
|
// We Need To Find An Open Leaf, Swap Data With That Leaf, and Then Go Find It
|
|
//==============================================================================
|
|
|
|
// Find A Successor Leaf
|
|
//-----------------------
|
|
int at_parent = T::node(mPool[at]).parent();
|
|
int successor = T::node(mPool[at]).right();
|
|
|
|
int parent_successor=-1;
|
|
while(T::node(mPool[successor]).left()!=tree_node::NULL_NODE)
|
|
{
|
|
parent_successor=successor;
|
|
successor = T::node(mPool[successor]).left();
|
|
}
|
|
|
|
int successor_right = T::node(mPool[successor]).right();
|
|
|
|
|
|
link_left(successor,T::node(mPool[at]).left());
|
|
|
|
bool red=T::node(mPool[successor]).red();
|
|
T::node(mPool[successor]).set_red(T::node(mPool[at]).red());
|
|
T::node(mPool[at]).set_red(red);
|
|
|
|
if (parent_successor!=-1)
|
|
{
|
|
|
|
link_right(successor,T::node(mPool[at]).right());
|
|
link_left(parent_successor,at);
|
|
}
|
|
else
|
|
{
|
|
link_right(successor,at);
|
|
}
|
|
|
|
if (at_parent!=tree_node::NULL_NODE)
|
|
{
|
|
if (T::node(mPool[at_parent]).left()==at)
|
|
{
|
|
//my parents left child
|
|
link_left(at_parent,successor);
|
|
}
|
|
else
|
|
{
|
|
assert(T::node(mPool[at_parent]).right()==at); // better be my parents right child then
|
|
link_right(at_parent,successor);
|
|
}
|
|
}
|
|
|
|
link_left(at,tree_node::NULL_NODE);
|
|
link_right(at,successor_right);
|
|
|
|
at=successor;
|
|
int a=T::node(mPool[at]).right();
|
|
bool r=erase_internal(key, a);
|
|
link_right(at,a); // T::node(mPool[at]).set_right(a);
|
|
// And Keep Going
|
|
//----------------
|
|
if (!r) // If It Was Not Red, We Need To Rebalance
|
|
{
|
|
return rebalance(at, false);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// HELPER: Change the color of a node and children
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void set_colors(tree_node& at, bool red, bool childRed)
|
|
{
|
|
at.set_red(red);
|
|
if (at.left()!=tree_node::NULL_NODE)
|
|
{
|
|
T::node(mPool[at.left()]).set_red(childRed);
|
|
}
|
|
if (at.right()!=tree_node::NULL_NODE)
|
|
{
|
|
T::node(mPool[at.right()]).set_red(childRed);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// HELPER: Rotate node located at (at) either left or right
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void rotate(int& at, bool left)
|
|
{
|
|
int t;
|
|
if (left)
|
|
{
|
|
assert(T::node(mPool[at]).right()!=tree_node::NULL_NODE);
|
|
|
|
t = T::node(mPool[at]).right();
|
|
link_right(at,T::node(mPool[t]).left()); // T::node(mPool[at]).set_right(T::node(mPool[t]).left());
|
|
link_left(t,at); // T::node(mPool[t]).set_left(at);
|
|
at = t;
|
|
}
|
|
else
|
|
{
|
|
assert(T::node(mPool[at]).left()!=tree_node::NULL_NODE);
|
|
|
|
t = T::node(mPool[at]).left();
|
|
link_left(at,T::node(mPool[t]).right()); // T::node(mPool[at]).set_left(T::node(mPool[t]).right());
|
|
link_right(t,at); //T::node(mPool[t]).set_right(at);
|
|
at = t;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// HELPER: Localally rebalance the tree here
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
bool rebalance(int& at, bool left)
|
|
{
|
|
// Decide Which Child, Left Or Right?
|
|
//------------------------------------
|
|
int w = (left)?(T::node(mPool[at]).right()):(T::node(mPool[at]).left()); // w is the child of at
|
|
if (w==tree_node::NULL_NODE)
|
|
{
|
|
bool atWasRed = T::node(mPool[at]).red(); // Remember what mPool[at] WAS
|
|
T::node(mPool[at]).set_red(false); // Mark mPool[at] as BLACK
|
|
return atWasRed; // Return what it used to be
|
|
}
|
|
|
|
|
|
// Get A Reference To The Child W, And Record It's Children x And y
|
|
//------------------------------------------------------------------
|
|
tree_node& wAt = T::node(mPool[w]);
|
|
int x = (left)?(wAt.left()):(wAt.right());// x and y are the grand children of at
|
|
int y = (left)?(wAt.right()):(wAt.left());
|
|
|
|
|
|
// Is The Child Black?
|
|
//---------------------
|
|
if (!wAt.red())
|
|
{
|
|
// If Both X and Y are Empty, Or Both Are Red
|
|
//--------------------------------------------
|
|
if ((x==tree_node::NULL_NODE || !T::node(mPool[x]).red()) &&
|
|
(y==tree_node::NULL_NODE || !T::node(mPool[y]).red()))
|
|
{
|
|
bool atWasRed = T::node(mPool[at]).red(); // Remember what mPool[at] WAS
|
|
T::node(mPool[at]).set_red(false); // Mark mPool[at] as BLACK
|
|
wAt.set_red(true); // Mark The Child As RED
|
|
return atWasRed; // Return what it used to be
|
|
}
|
|
|
|
// If Y Is Valid
|
|
//---------------
|
|
if (y!=tree_node::NULL_NODE && T::node(mPool[y]).red())
|
|
{
|
|
wAt.set_red(T::node(mPool[at]).red());
|
|
rotate(at, left);
|
|
T::node(mPool[T::node(mPool[at]).left()]).set_red(false);
|
|
T::node(mPool[T::node(mPool[at]).right()]).set_red(false);
|
|
return true;
|
|
}
|
|
|
|
// X Must Be Valid
|
|
//-----------------
|
|
T::node(mPool[x]).set_red(T::node(mPool[at]).red());
|
|
T::node(mPool[at]).set_red(false);
|
|
|
|
if (left)
|
|
{
|
|
int r=T::node(mPool[at]).right();
|
|
rotate(r,false);
|
|
link_right(at,r); // T::node(mPool[at]).set_right(r);
|
|
}
|
|
else
|
|
{
|
|
int r=T::node(mPool[at]).left();
|
|
rotate(r,true);
|
|
link_left(at,r); // T::node(mPool[at]).set_left(r);
|
|
}
|
|
rotate(at, left);
|
|
|
|
return true;
|
|
}
|
|
|
|
// The Child Must Have Been Red
|
|
//------------------------------
|
|
wAt.set_red(T::node(mPool[at]).red()); // Switch Child Color
|
|
T::node(mPool[at]).set_red(true);
|
|
rotate(at, left); // Rotate At
|
|
|
|
// Select The Next Rebalance Child And Recurse
|
|
//----------------------------------------------
|
|
if (left)
|
|
{
|
|
int r=T::node(mPool[at]).left();
|
|
rebalance(r,true);
|
|
link_left(at,r); // T::node(mPool[at]).set_left(r);
|
|
}
|
|
else
|
|
{
|
|
int r=T::node(mPool[at]).right();
|
|
rebalance(r,false);
|
|
link_right(at,r); //T::node(mPool[at]).set_right(r);
|
|
}
|
|
return true;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive front function - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int front(int at) const
|
|
{
|
|
if (at!=tree_node::NULL_NODE &&
|
|
T::node(mPool[at]).left()!=tree_node::NULL_NODE)
|
|
{
|
|
return front(T::node(mPool[at]).left());
|
|
}
|
|
return at;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive back function - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int back(int at) const
|
|
{
|
|
if (at!=tree_node::NULL_NODE && T::node(mPool[at]).right()!=tree_node::NULL_NODE)
|
|
{
|
|
return back(T::node(mPool[at]).right());
|
|
}
|
|
return at;
|
|
}
|
|
protected:
|
|
int front() const
|
|
{
|
|
return front(mRoot);
|
|
}
|
|
|
|
int back() const
|
|
{
|
|
return back(mRoot);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive next function - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int next(int at) const
|
|
{
|
|
assert(at!=tree_node::NULL_NODE);
|
|
const TTValue& kAt = mPool[at];
|
|
const tree_node& nAt = T::node(kAt);
|
|
if (nAt.right()!=tree_node::NULL_NODE)
|
|
{
|
|
return front(nAt.right());
|
|
}
|
|
|
|
int child = at;
|
|
int parent = tree_node::NULL_NODE;
|
|
find_internal(kAt, at, mRoot, parent);
|
|
|
|
while(parent!=tree_node::NULL_NODE && (child==T::node(mPool[parent]).right()))
|
|
{
|
|
child = parent;
|
|
find_internal(mPool[parent], parent, mRoot, parent);
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// This is the map internal recursive previous function - do not use externally
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int previous(int at) const
|
|
{
|
|
assert(at!=tree_node::NULL_NODE);
|
|
const TTValue& kAt = mPool[at];
|
|
const tree_node& nAt = T::node(mPool[at]);
|
|
if (kAt.left()!=tree_node::NULL_NODE)
|
|
{
|
|
return back(kAt.left());
|
|
}
|
|
|
|
int child = at;
|
|
int parent = tree_node::NULL_NODE;
|
|
find_internal(nAt, at, mRoot, parent);
|
|
|
|
while(parent!=tree_node::NULL_NODE && (child==T::node(mPool[parent]).left()))
|
|
{
|
|
child = parent;
|
|
find_internal(mPool[parent], parent, mRoot, parent);
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Constructor
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
tree_base() : mRoot(tree_node::NULL_NODE), mLastAdd(-1)
|
|
{
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// How Many Objects Are In This Map
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int size() const
|
|
{
|
|
return (mPool.size());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Are There Any Objects In This Map?
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
bool empty() const
|
|
{
|
|
return (mPool.empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Is This Map Filled?
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
bool full() const
|
|
{
|
|
return (mPool.full());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Clear All Data From The Map
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void clear()
|
|
{
|
|
mRoot = tree_node::NULL_NODE;
|
|
mPool.clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Adds Element Value At Location Key - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void alloc_key(const TTValue &key)
|
|
{
|
|
|
|
//fixme handle duplicates more sensibly?
|
|
assert(!full());
|
|
mLastAdd = mPool.alloc(key); // Grab A New One
|
|
T::node(mPool[mLastAdd]).init(); // Initialize Our Data And Color
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Allocs an item, when filled, call insert_alloced
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TTValue & alloc_key()
|
|
{
|
|
assert(!full());
|
|
mLastAdd = mPool.alloc(); // Grab A New One
|
|
T::node(mPool[mLastAdd]).init(); // Initialize Our Data And Color
|
|
return mPool[mLastAdd];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Allocs an item (raw), when constucted, call insert_alloced
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TRatlNew *alloc_key_raw()
|
|
{
|
|
assert(!full());
|
|
TRatlNew *ret=mPool.alloc_raw(); // Grab A New One
|
|
mLastAdd = mPool.pointer_to_index(ret);
|
|
T::node(mPool[mLastAdd]).init(); // Initialize Our Data And Color
|
|
return ret;
|
|
}
|
|
template<class CAST_TO>
|
|
CAST_TO *verify_alloc_key(CAST_TO *p) const
|
|
{
|
|
return mPool.verify_alloc(p);
|
|
}
|
|
|
|
void insert_alloced_key()
|
|
{
|
|
assert(mLastAdd>=0&&mLastAdd<CAPACITY);
|
|
assert(!IS_MULTI || find_index(mPool[mLastAdd])!=tree_node::NULL_NODE); //fixme handle duplicates more sensibly?
|
|
|
|
insert_internal(mPool[mLastAdd],mRoot);
|
|
assert(mRoot!=tree_node::NULL_NODE);
|
|
T::node(mPool[mRoot]).set_red(false);
|
|
T::node(mPool[mRoot]).set_parent(tree_node::NULL_NODE);
|
|
}
|
|
|
|
int index_of_alloced_key() const
|
|
{
|
|
assert(mLastAdd>=0&&mLastAdd<CAPACITY);
|
|
return mLastAdd;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Removes The Element Pointed To At (it) And Decrements (it) - O((log n)^2)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void erase_index(int i)
|
|
{
|
|
assert(i>=0&&i<CAPACITY);
|
|
assert(mRoot!=tree_node::NULL_NODE);
|
|
|
|
//fixme this is lame to have to look by key to erase
|
|
erase_internal(mPool[i],mRoot);
|
|
if (mRoot!=tree_node::NULL_NODE)
|
|
{
|
|
T::node(mPool[mRoot]).set_red(false);
|
|
T::node(mPool[mRoot]).set_parent(tree_node::NULL_NODE);
|
|
}
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Seach For A Given Key. Will Return -1 if Failed - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
int find_index(const TTValue &key) const
|
|
{
|
|
return find_internal(key, mRoot);
|
|
}
|
|
const TTValue &index_to_key(int i) const
|
|
{
|
|
assert(i>=0&&i<CAPACITY);
|
|
return mPool[i];
|
|
}
|
|
|
|
//fixme lower bound, upper bound, equal range
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T,int IS_MULTI>
|
|
class set_base : public tree_base<T,IS_MULTI>
|
|
{
|
|
|
|
public:
|
|
typedef T TStorageTraits;
|
|
typedef typename T::TValue TTValue;
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Capacity Enum
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
static const int CAPACITY = T::CAPACITY;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Adds Element Value At Location Key - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void insert(const TTValue &key)
|
|
{
|
|
|
|
assert(!IS_MULTI || find_index(key)==tree_node::NULL_NODE); //fixme handle duplicates more sensibly?
|
|
|
|
alloc_key(key);
|
|
tree_base<T, IS_MULTI>::insert_alloced_key();
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Allocs an item, when filled, call insert_alloced
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TTValue & alloc()
|
|
{
|
|
return tree_base<T, IS_MULTI>::alloc_key();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Allocs an item (raw), when constucted, call insert_alloced
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TRatlNew *alloc_raw()
|
|
{
|
|
return tree_base<T, IS_MULTI>::alloc_key_raw();
|
|
}
|
|
template<class CAST_TO>
|
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
|
{
|
|
return verify_alloc_key(p);
|
|
}
|
|
|
|
void insert_alloced()
|
|
{
|
|
tree_base<T, IS_MULTI>::insert_alloced_key();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Removes The First Element With Key (key) - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void erase(const TTValue &key)
|
|
{
|
|
//fixme this is a double search currently
|
|
int i=find_index(key);
|
|
if (i!=tree_node::NULL_NODE)
|
|
{
|
|
tree_base<T, IS_MULTI>::erase_index(i);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Iterator
|
|
//
|
|
// A map is sorted in ascending order on the KEY type. ++ and -- are both
|
|
// O((log n)^2) operations
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
class iterator
|
|
{
|
|
friend class set_base<TStorageTraits,IS_MULTI>;
|
|
friend class const_iterator;
|
|
|
|
int mLoc;
|
|
set_base<TStorageTraits,IS_MULTI>* mOwner;
|
|
|
|
public:
|
|
iterator(set_base<TStorageTraits,IS_MULTI> *owner=0, int loc=tree_node::NULL_NODE) :
|
|
mOwner(owner),
|
|
mLoc(loc)
|
|
{
|
|
}
|
|
iterator(const iterator &o) :
|
|
mOwner(o.mOwner),
|
|
mLoc(o.mLoc)
|
|
{
|
|
}
|
|
|
|
void operator=(const iterator &o)
|
|
{
|
|
mOwner=o.mOwner;
|
|
mLoc=o.mLoc;
|
|
}
|
|
|
|
iterator operator++() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->next(mLoc);
|
|
return *this;
|
|
}
|
|
iterator operator++(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
iterator old(*this);
|
|
mLoc=mOwner->next(mLoc);
|
|
return old;
|
|
}
|
|
|
|
iterator operator--() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return *this;
|
|
}
|
|
iterator operator--(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
iterator old(*this);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return old;
|
|
}
|
|
|
|
bool operator!=(const iterator p) const {return (mLoc!=p.mLoc || mOwner!=p.mOwner);}
|
|
bool operator==(const iterator p) const {return (mLoc==p.mLoc && mOwner==p.mOwner);}
|
|
|
|
const TTValue & operator*() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->index_to_key(mLoc);
|
|
}
|
|
const TTValue * operator->() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return &mOwner->index_to_key(mLoc);
|
|
}
|
|
};
|
|
class const_iterator
|
|
{
|
|
friend class set_base<TStorageTraits,IS_MULTI>;
|
|
|
|
int mLoc;
|
|
|
|
const set_base<TStorageTraits,IS_MULTI>* mOwner;
|
|
|
|
public:
|
|
const_iterator(const set_base<TStorageTraits,IS_MULTI> *owner=0, int loc=tree_node::NULL_NODE) :
|
|
mOwner(owner),
|
|
mLoc(loc)
|
|
{
|
|
}
|
|
const_iterator(const const_iterator &o) :
|
|
mOwner(o.mOwner),
|
|
mLoc(o.mLoc)
|
|
{
|
|
}
|
|
const_iterator(const iterator &o) :
|
|
mOwner(o.mOwner),
|
|
mLoc(o.mLoc)
|
|
{
|
|
}
|
|
void operator=(const const_iterator &o)
|
|
{
|
|
mOwner=o.mOwner;
|
|
mLoc=o.mLoc;
|
|
}
|
|
void operator=(const iterator &o)
|
|
{
|
|
mOwner=o.mOwner;
|
|
mLoc=o.mLoc;
|
|
}
|
|
|
|
|
|
const_iterator operator++() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->next(mLoc);
|
|
return *this;
|
|
}
|
|
const_iterator operator++(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
const_iterator old(*this);
|
|
mLoc=mOwner->next(mLoc);
|
|
return old;
|
|
}
|
|
|
|
const_iterator operator--() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return *this;
|
|
}
|
|
const_iterator operator--(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
const_iterator old(*this);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return old;
|
|
}
|
|
|
|
bool operator!=(const const_iterator p) const {return (mLoc!=p.mLoc || mOwner!=p.mOwner);}
|
|
bool operator==(const const_iterator p) const {return (mLoc==p.mLoc && mOwner==p.mOwner);}
|
|
bool operator!=(const iterator p) const {return (mLoc!=p.mLoc || mOwner!=p.mOwner);}
|
|
bool operator==(const iterator p) const {return (mLoc==p.mLoc && mOwner==p.mOwner);}
|
|
|
|
const TTValue & operator*() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->index_to_key(mLoc);
|
|
}
|
|
const TTValue * operator->() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return &mOwner->index_to_key(mLoc);
|
|
}
|
|
};
|
|
friend class iterator;
|
|
friend class const_iterator;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Seach For A Given Key. Will Return end() if Failed - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator find(const TTValue &key)
|
|
{
|
|
return iterator(this,find_index(key));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An Iterator To The Smallest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator begin()
|
|
{
|
|
return iterator(this, tree_base<T, IS_MULTI>::front());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An Iterator To The Largest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator rbegin()
|
|
{
|
|
return iterator(this, tree_base<T, IS_MULTI>::back());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// The Invalid Iterator, Use As A Stop Condition In Your For Loops - O(1)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator end()
|
|
{
|
|
return iterator(this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Seach For A Given Key. Will Return end() if Failed - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator find(const TTValue &key) const
|
|
{
|
|
return const_iterator(this, find_index(key));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An const_iterator To The Smallest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator begin() const
|
|
{
|
|
return const_iterator(this, tree_base<T, IS_MULTI>::front());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An const_iterator To The Largest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator rbegin() const
|
|
{
|
|
return const_iterator(this, tree_base<T, IS_MULTI>::back());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// The Invalid const_iterator, Use As A Stop Condition In Your For Loops - O(1)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator end() const
|
|
{
|
|
return const_iterator(this);
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Removes The Element Pointed To At (it) And Decrements (it) - O((log n)^2)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void erase(const iterator &it)
|
|
{
|
|
assert(it.mOwner==this && it.mLoc>=0&&it.mLoc<CAPACITY);
|
|
erase_index(it.mLoc);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator lower_bound(const TTValue &key)
|
|
{
|
|
return iterator(this, find_index(key));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator upper_bound(const TTValue &key)
|
|
{
|
|
// fixme, this don't work
|
|
iterator ubound(this, find_index(key));
|
|
++ubound;
|
|
return ubound;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, int ARG_CAPACITY>
|
|
class set_vs : public set_base<storage::value_semantics_node<T,ARG_CAPACITY,tree_node>,0 >
|
|
{
|
|
public:
|
|
typedef typename storage::value_semantics_node<T,ARG_CAPACITY,tree_node> TStorageTraits;
|
|
typedef typename TStorageTraits::TValue TTValue;
|
|
static const int CAPACITY = ARG_CAPACITY;
|
|
set_vs() {}
|
|
};
|
|
|
|
template<class T, int ARG_CAPACITY>
|
|
class set_os : public set_base<storage::object_semantics_node<T,ARG_CAPACITY,tree_node>,0 >
|
|
{
|
|
public:
|
|
typedef typename storage::object_semantics_node<T,ARG_CAPACITY,tree_node> TStorageTraits;
|
|
typedef typename TStorageTraits::TValue TTValue;
|
|
static const int CAPACITY = ARG_CAPACITY;
|
|
set_os() {}
|
|
};
|
|
|
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
|
class set_is : public set_base<storage::virtual_semantics_node<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE,tree_node>,0 >
|
|
{
|
|
public:
|
|
typedef typename storage::virtual_semantics_node<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE,tree_node> TStorageTraits;
|
|
typedef typename TStorageTraits::TValue TTValue;
|
|
static const int CAPACITY = ARG_CAPACITY;
|
|
static const int MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE;
|
|
set_is() {}
|
|
};
|
|
|
|
|
|
template<class K,class V,int IS_MULTI>
|
|
class map_base : public tree_base<K,IS_MULTI>
|
|
{
|
|
public:
|
|
typedef K TKeyStorageTraits;
|
|
typedef typename K::TValue TKTValue;
|
|
|
|
typedef V TValueStorageTraits;
|
|
typedef typename V::TValue TVTValue;
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Capacity Enum
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
static const int CAPACITY = K::CAPACITY;
|
|
private:
|
|
array_base<TValueStorageTraits> mValues;
|
|
public:
|
|
map_base()
|
|
{
|
|
compile_assert<K::CAPACITY==V::CAPACITY>();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
tree_base<K,IS_MULTI>::clear();
|
|
mValues.clear();
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Adds Element Value At Location Key - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void insert(const TKTValue &key,const TVTValue &value)
|
|
{
|
|
assert(!IS_MULTI || (tree_base<K,IS_MULTI>::find_index(key)==tree_node::NULL_NODE)); //fixme handle duplicates more sensibly?
|
|
|
|
tree_base<K,IS_MULTI>::alloc_key(key);
|
|
tree_base<K,IS_MULTI>::insert_alloced_key();
|
|
assert(check_validity());
|
|
mValues.construct(tree_base<K,IS_MULTI>::index_of_alloced_key(),value);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Adds Element Value At Location Key returns a reference
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TVTValue &insert(const TKTValue &key)
|
|
{
|
|
|
|
assert(!IS_MULTI || (tree_base<K,IS_MULTI>::find_index(key)==tree_node::NULL_NODE)); //fixme handle duplicates more sensibly?
|
|
|
|
tree_base<K,IS_MULTI>::alloc_key(key);
|
|
tree_base<K,IS_MULTI>::insert_alloced_key();
|
|
|
|
int idx=tree_base<K,IS_MULTI>::index_of_alloced_key();
|
|
assert(check_validity());
|
|
mValues.construct(idx);
|
|
return mValues[idx];
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Adds Element Value At Location Key returns a rew pointer for placement new
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TRatlNew *insert_raw(const TKTValue &key)
|
|
{
|
|
|
|
assert(!IS_MULTI || (tree_base<K,IS_MULTI>::find_index(key)==tree_node::NULL_NODE)); //fixme handle duplicates more sensibly?
|
|
|
|
tree_base<K,IS_MULTI>::alloc_key(key);
|
|
tree_base<K,IS_MULTI>::insert_alloced_key();
|
|
assert(check_validity());
|
|
return mValues.alloc_raw(tree_base<K,IS_MULTI>::index_of_alloced_key());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// After calling alloc_key*, you may call this to alloc the value
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TVTValue &alloc_value()
|
|
{
|
|
mValues.construct(tree_base<K,IS_MULTI>::index_of_alloced_key());
|
|
return mValues[tree_base<K,IS_MULTI>::index_of_alloced_key()];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// After calling alloc_key*, you may call this to alloc_raw the value
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
TRatlNew *alloc_value_raw()
|
|
{
|
|
return mValues.alloc_raw(tree_base<K,IS_MULTI>::index_of_alloced_key());
|
|
}
|
|
|
|
template<class CAST_TO>
|
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
|
{
|
|
return mValues.verify_alloc(p);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Removes The First Element With Key (key) - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void erase(const TKTValue &key)
|
|
{
|
|
//fixme this is a double search currently
|
|
int i=tree_base<K,IS_MULTI>::find_index(key);
|
|
if (i!=tree_node::NULL_NODE)
|
|
{
|
|
tree_base<K,IS_MULTI>::erase_index(i);
|
|
mValues.destruct(i);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Iterator
|
|
//
|
|
// A map is sorted in ascending order on the KEY type. ++ and -- are both
|
|
// O((log n)^2) operations
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
class const_iterator;
|
|
class iterator
|
|
{
|
|
friend class map_base<K,V, IS_MULTI>;
|
|
friend class const_iterator;
|
|
|
|
int mLoc;
|
|
map_base<K,V, IS_MULTI>* mOwner;
|
|
|
|
public:
|
|
iterator(map_base<K,V, IS_MULTI> *owner=0, int loc=tree_node::NULL_NODE) :
|
|
mLoc(loc),
|
|
mOwner(owner)
|
|
{
|
|
}
|
|
iterator(const iterator &o) :
|
|
mLoc(o.mLoc),
|
|
mOwner(o.mOwner)
|
|
{
|
|
}
|
|
|
|
void operator=(const iterator &o)
|
|
{
|
|
mOwner=o.mOwner;
|
|
mLoc=o.mLoc;
|
|
}
|
|
|
|
iterator operator++() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->next(mLoc);
|
|
return *this;
|
|
}
|
|
iterator operator++(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
iterator old(*this);
|
|
mLoc=mOwner->next(mLoc);
|
|
return old;
|
|
}
|
|
|
|
iterator operator--() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return *this;
|
|
}
|
|
iterator operator--(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
iterator old(*this);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return old;
|
|
}
|
|
|
|
bool operator!=(const iterator &p) const {return (mLoc!=p.mLoc || mOwner!=p.mOwner);}
|
|
bool operator==(const iterator &p) const {return (mLoc==p.mLoc && mOwner==p.mOwner);}
|
|
|
|
TVTValue & operator*() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->mValues[mLoc];
|
|
}
|
|
const TKTValue & key() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->index_to_key(mLoc);
|
|
}
|
|
TVTValue & value() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->mValues[mLoc];
|
|
}
|
|
TVTValue * operator->() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return &mOwner->mValues[mLoc];
|
|
}
|
|
};
|
|
class const_iterator
|
|
{
|
|
friend class map_base<K,V,IS_MULTI>;
|
|
|
|
int mLoc;
|
|
const map_base<K,V,IS_MULTI>* mOwner;
|
|
|
|
public:
|
|
const_iterator(const map_base<K,V,IS_MULTI> *owner=0, int loc=tree_node::NULL_NODE) :
|
|
mOwner(owner),
|
|
mLoc(loc)
|
|
{
|
|
}
|
|
const_iterator(const const_iterator &o) :
|
|
mOwner(o.mOwner),
|
|
mLoc(o.mLoc)
|
|
{
|
|
}
|
|
const_iterator(const iterator &o) :
|
|
mOwner(o.mOwner),
|
|
mLoc(o.mLoc)
|
|
{
|
|
}
|
|
void operator=(const const_iterator &o)
|
|
{
|
|
mOwner=o.mOwner;
|
|
mLoc=o.mLoc;
|
|
}
|
|
void operator=(const iterator &o)
|
|
{
|
|
mOwner=o.mOwner;
|
|
mLoc=o.mLoc;
|
|
}
|
|
|
|
|
|
const_iterator operator++() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->next(mLoc);
|
|
return *this;
|
|
}
|
|
const_iterator operator++(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
const_iterator old(*this);
|
|
mLoc=mOwner->next(mLoc);
|
|
return old;
|
|
}
|
|
|
|
const_iterator operator--() //prefix
|
|
{
|
|
assert(mOwner);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return *this;
|
|
}
|
|
const_iterator operator--(int) //postfix
|
|
{
|
|
assert(mOwner);
|
|
const_iterator old(*this);
|
|
mLoc=mOwner->previous(mLoc);
|
|
return old;
|
|
}
|
|
|
|
bool operator!=(const const_iterator &p) const {return (mLoc!=p.mLoc || mOwner!=p.mOwner);}
|
|
bool operator==(const const_iterator &p) const {return (mLoc==p.mLoc && mOwner==p.mOwner);}
|
|
bool operator!=(const iterator &p) const {return (mLoc!=p.mLoc || mOwner!=p.mOwner);}
|
|
bool operator==(const iterator &p) const {return (mLoc==p.mLoc && mOwner==p.mOwner);}
|
|
|
|
const TVTValue & operator*() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->mValues[mLoc];
|
|
}
|
|
const TKTValue & key() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->index_to_key(mLoc);
|
|
}
|
|
const TVTValue & value() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return mOwner->mValues[mLoc];
|
|
}
|
|
const TVTValue * operator->() const
|
|
{
|
|
assert(mOwner);
|
|
assert(mLoc>=0&&mLoc<CAPACITY); // deferencing end()?
|
|
return &mOwner->mValues[mLoc];
|
|
}
|
|
};
|
|
friend class iterator;
|
|
friend class const_iterator;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Seach For A Given Key. Will Return end() if Failed - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator find(const TKTValue &key)
|
|
{
|
|
return iterator(this,tree_base<K, IS_MULTI>::find_index(key));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An Iterator To The Smallest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator begin()
|
|
{
|
|
return iterator(this, tree_base<K,IS_MULTI>::front());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An Iterator To The Largest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator rbegin()
|
|
{
|
|
return iterator(this, tree_base<K,IS_MULTI>::back());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// The Invalid Iterator, Use As A Stop Condition In Your For Loops - O(1)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
iterator end()
|
|
{
|
|
return iterator(this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Seach For A Given Key. Will Return end() if Failed - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator find(const TKTValue &key) const
|
|
{
|
|
return const_iterator(this, find_index(key));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An const_iterator To The Smallest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator begin() const
|
|
{
|
|
return const_iterator(this, tree_base<K,IS_MULTI>::front());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Get An const_iterator To The Largest Element - O(log n)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator rbegin() const
|
|
{
|
|
return const_iterator(this, tree_base<K,IS_MULTI>::back());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// The Invalid const_iterator, Use As A Stop Condition In Your For Loops - O(1)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
const_iterator end() const
|
|
{
|
|
return const_iterator(this);
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Removes The Element Pointed To At (it) And Decrements (it) - O((log n)^2)
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
void erase(const iterator &it)
|
|
{
|
|
assert(it.mOwner==this && it.mLoc>=0&&it.mLoc<CAPACITY);
|
|
erase_index(it.mLoc);
|
|
mValues.destruct(it.mLoc);
|
|
}
|
|
private:
|
|
bool check_validity()
|
|
{
|
|
#if (0)
|
|
int cnt=0;
|
|
iterator it=begin();
|
|
for (;it!=end();it++)
|
|
{
|
|
cnt++;
|
|
}
|
|
// assert(cnt==size());
|
|
return cnt==size();
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
};
|
|
|
|
template<class K,class V, int ARG_CAPACITY>
|
|
class map_vs : public map_base<
|
|
storage::value_semantics_node<K,ARG_CAPACITY,tree_node>,
|
|
storage::value_semantics<V,ARG_CAPACITY>,
|
|
0 >
|
|
{
|
|
public:
|
|
typedef typename storage::value_semantics<V,ARG_CAPACITY> VStorageTraits;
|
|
typedef typename VStorageTraits::TValue TTValue;
|
|
static const int CAPACITY = ARG_CAPACITY;
|
|
map_vs() {}
|
|
};
|
|
|
|
template<class K,class V, int ARG_CAPACITY>
|
|
class map_os : public map_base<
|
|
storage::value_semantics_node<K,ARG_CAPACITY,tree_node>,
|
|
storage::object_semantics<V,ARG_CAPACITY>,
|
|
0 >
|
|
{
|
|
public:
|
|
typedef typename storage::object_semantics<V,ARG_CAPACITY> VStorageTraits;
|
|
typedef typename VStorageTraits::TValue TTValue;
|
|
static const int CAPACITY = ARG_CAPACITY;
|
|
map_os() {}
|
|
};
|
|
|
|
template<class K,class V, int ARG_CAPACITY,int ARG_MAX_CLASS_SIZE>
|
|
class map_is : public map_base<
|
|
storage::value_semantics_node<K,ARG_CAPACITY,tree_node>,
|
|
storage::virtual_semantics<V,ARG_CAPACITY,ARG_MAX_CLASS_SIZE>,
|
|
0 >
|
|
{
|
|
public:
|
|
typedef typename storage::virtual_semantics<V,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> VStorageTraits;
|
|
typedef typename VStorageTraits::TValue TTValue;
|
|
static const int CAPACITY = ARG_CAPACITY;
|
|
static const int MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE;
|
|
map_is() {}
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|