Browse Source

Added legacy BlitzMax support.

woollybah 9 years ago
parent
commit
5d559dc464

+ 1 - 1
mojo2.mod/examples/rendertoimage/rendertoimage.bmx

@@ -24,7 +24,7 @@ While Not KeyDown(key_escape)
 	For Local x:Int=0 Until 16
 		For Local y:Int=0 Until 16
 			If (x~y)&1
-				icanvas.SetColor Sin( MilliSecs*.1 )*.5+.5,Cos( MilliSecs*.1 )*.5+.5,.5
+				icanvas.SetColor Sin( MilliSecs()*.1 )*.5+.5,Cos( MilliSecs()*.1 )*.5+.5,.5
 			Else
 				icanvas.SetColor 1,1,0
 			EndIf

+ 77 - 47
mojo2.mod/graphics.bmx

@@ -134,16 +134,16 @@ Function InitVbos()
 	glBufferData GL_ARRAY_BUFFER,PRIM_VBO_SIZE,Null,VBO_USAGE
 	
 	glEnableVertexAttribArray 0
-	glVertexAttribPointer 0,2,GL_FLOAT,False,BYTES_PER_VERTEX,0
+	glVertexAttribPointer 0,2,GL_FLOAT,False,BYTES_PER_VERTEX,Byte Ptr(0)
 	
 	glEnableVertexAttribArray 1
-	glVertexAttribPointer 1,2,GL_FLOAT,False,BYTES_PER_VERTEX,8
+	glVertexAttribPointer 1,2,GL_FLOAT,False,BYTES_PER_VERTEX,Byte Ptr(8)
 	
 	glEnableVertexAttribArray 2
-	glVertexAttribPointer 2,2,GL_FLOAT,False,BYTES_PER_VERTEX,16
+	glVertexAttribPointer 2,2,GL_FLOAT,False,BYTES_PER_VERTEX,Byte Ptr(16)
 	
 	glEnableVertexAttribArray 3
-	glVertexAttribPointer 3,4,GL_UNSIGNED_BYTE,True,BYTES_PER_VERTEX,24
+	glVertexAttribPointer 3,4,GL_UNSIGNED_BYTE,True,BYTES_PER_VERTEX,Byte Ptr(24)
 	
 	glGenBuffers(1, Varptr rs_ibo)
 	glBindBuffer GL_ELEMENT_ARRAY_BUFFER,rs_ibo
@@ -165,10 +165,10 @@ End Function
 
 Function BindVbos()
 	glBindBuffer( GL_ARRAY_BUFFER,rs_vbo )
-	glEnableVertexAttribArray( 0 ) ; glVertexAttribPointer 0,2,GL_FLOAT,False,BYTES_PER_VERTEX, 0
-	glEnableVertexAttribArray( 1 ) ; glVertexAttribPointer 1,2,GL_FLOAT,False,BYTES_PER_VERTEX, 8
-	glEnableVertexAttribArray( 2 ) ; glVertexAttribPointer 2,2,GL_FLOAT,False,BYTES_PER_VERTEX, 16
-	glEnableVertexAttribArray( 3 ) ; glVertexAttribPointer 3,4,GL_UNSIGNED_BYTE,True,BYTES_PER_VERTEX, 24
+	glEnableVertexAttribArray( 0 ) ; glVertexAttribPointer 0,2,GL_FLOAT,False,BYTES_PER_VERTEX, Byte Ptr(0)
+	glEnableVertexAttribArray( 1 ) ; glVertexAttribPointer 1,2,GL_FLOAT,False,BYTES_PER_VERTEX, Byte Ptr(8)
+	glEnableVertexAttribArray( 2 ) ; glVertexAttribPointer 2,2,GL_FLOAT,False,BYTES_PER_VERTEX, Byte Ptr(16)
+	glEnableVertexAttribArray( 3 ) ; glVertexAttribPointer 3,4,GL_UNSIGNED_BYTE,True,BYTES_PER_VERTEX, Byte Ptr(24)
 
 	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,rs_ibo )
 End Function
@@ -493,9 +493,9 @@ Type TTexture Extends TRefCounted
 		If Not _flat _flat=Color( $ff888888 )
 		Return _flat
 	End Function
-	
+?bmxng	
 	Private
-	
+?
 	Field _seq:Int
 	Field _width:Int
 	Field _height:Int
@@ -802,8 +802,11 @@ The following material properties are supported:
 	
 	Field _vsource:String
 	Field _fsource:String
+?bmxng
 	Field _uniforms:TStringMap=New TStringMap
-	
+?Not bmxng
+	Field _uniforms:TMap=New TMap
+?	
 	Field _glPrograms:TGLProgram[MAX_LIGHTS+1]
 	
 	Field _defaultMaterial:TMaterial
@@ -881,7 +884,7 @@ The following material properties are supported:
 
 		Local vars:TMap=New TMap
 		
-		While p.Toke
+		While p.Toke()
 		
 			If p.CParse( "uniform" )
 				'uniform decl
@@ -1091,9 +1094,21 @@ Type TMaterial Extends TRefCounted
 	Rem
 	bbdoc: Gets vector shader parameter.
 	End Rem
+?bmxng
 	Method GetVector:Float[]( param:String,defValue:Float[]=[1.0,1.0,1.0,1.0] )
 		If Not _vectors.Contains( param ) Return defValue
 		Return _vectors.ValueForKey( param )
+?Not bmxng
+	Method GetVector:Float[]( param:String,defValue:Float[]=Null )
+		If Not _vectors.Contains( param ) Then
+			If defValue Then
+				Return defValue
+			Else
+				Return [1.0,1.0,1.0,1.0]
+			End If
+		End If
+		Return Float[](_vectors.ValueForKey( param ))
+?
 	End Method
 	
 	Rem
@@ -1132,7 +1147,7 @@ Type TMaterial Extends TRefCounted
 	
 		Local material:TMaterial=New TMaterial.Create( shader )
 
-		material=material.Shader.OnLoadMaterial( material,path,texFlags )
+		material=material.Shader().OnLoadMaterial( material,path,texFlags )
 		
 		Return material
 	End Function
@@ -1142,8 +1157,13 @@ Type TMaterial Extends TRefCounted
 	Field _shader:TShader
 	Field _colorTexture:TTexture
 	Field _scalars:TStringFloatMap=New TStringFloatMap
+?bmxng
 	Field _vectors:TStringMap=New TStringMap
 	Field _textures:TStringMap=New TStringMap
+?Not bmxng
+	Field _vectors:TMap=New TMap
+	Field _textures:TMap=New TMap
+?
 	Field _inited:Int
 	
 	Method Bind:Int()
@@ -1292,8 +1312,8 @@ TImage.Managed consumes more memory, and slows down image rendering somewhat so
 		If Not texture Throw "Material has no ColorTexture"
 		_material=material
 		_material.Retain
-		_width=_material.Width
-		_height=_material.Height
+		_width=_material.Width()
+		_height=_material.Height()
 		SetHandle xhandle,yhandle
 		Return Self
 	End Method
@@ -1399,10 +1419,10 @@ TImage.Managed consumes more memory, and slows down image rendering somewhat so
 		_x1=Float(_width)*(1-xhandle)
 		_y0=Float(_height)*-yhandle
 		_y1=Float(_height)*(1-yhandle)
-		_s0=Float(_x)/Float(_material.Width)
-		_t0=Float(_y)/Float(_material.Height)
-		_s1=Float(_x+_width)/Float(_material.Width)
-		_t1=Float(_y+_height)/Float(_material.Height)
+		_s0=Float(_x)/Float(_material.Width())
+		_t0=Float(_y)/Float(_material.Height())
+		_s1=Float(_x+_width)/Float(_material.Width())
+		_t1=Float(_y+_height)/Float(_material.Height())
 	End Method
 	
 	Rem
@@ -1426,7 +1446,7 @@ TImage.Managed consumes more memory, and slows down image rendering somewhat so
 	End Method
 	
 	Function ImagesLoading:Int()
-		Return TTexture.TexturesLoading>0
+		Return TTexture.TexturesLoading()>0
 	End Function
 	
 	Rem
@@ -1464,8 +1484,8 @@ TImage.Managed consumes more memory, and slows down image rendering somewhat so
 		Local material:TMaterial=TMaterial.Load( path,flags|TTexture.ClampST,shader )
 		If Not material Return Null
 		
-		Local cellWidth:Int=material.Width/numFrames
-		Local cellHeight:Int=material.Height
+		Local cellWidth:Int=material.Width()/numFrames
+		Local cellHeight:Int=material.Height()
 		
 		Local x:Int=0
 		Local width:Int=cellWidth
@@ -1542,7 +1562,12 @@ Type TFont
 	End Rem
 	Method TextWidth:Float( Text:String )
 		Local w:Float=0.0
+?bmxng
 		For Local char:Int=EachIn Text
+?Not bmxng
+		For Local i:Int=0 Until Text.length
+			Local char:Int = Text[i]
+?
 			Local glyph:TGlyph=GetGlyph( char )
 			If Not glyph Continue
 			w:+glyph.advance
@@ -1567,13 +1592,13 @@ Type TFont
 		Local image:TImage=TImage.Load( path )
 		If Not image Return Null
 		
-		Local cellWidth:Int=image.Width/numChars
-		Local cellHeight:Int=image.Height
+		Local cellWidth:Int=image.Width()/numChars
+		Local cellHeight:Int=image.Height()
 		Local glyphX:Int=0,glyphY:Int=0,glyphWidth:Int=cellWidth,glyphHeight:Int=cellHeight
 		If padded glyphX:+1;glyphY:+1;glyphWidth:-2;glyphHeight:-2
 
-		Local w:Int=image.Width/cellWidth
-		Local h:Int=image.Height/cellHeight
+		Local w:Int=image.Width()/cellWidth
+		Local h:Int=image.Height()/cellHeight
 
 		Local glyphs:TGlyph[]=New TGlyph[numChars]
 		
@@ -1593,8 +1618,8 @@ Type TFont
 		Local image:TImage=TImage.Load( path )
 		If Not image Return Null
 
-		Local w:Int=image.Width/cellWidth
-		Local h:Int=image.Height/cellHeight
+		Local w:Int=image.Width()/cellWidth
+		Local h:Int=image.Height()/cellHeight
 
 		Local glyphs:TGlyph[]=New TGlyph[numChars]
 		
@@ -2085,10 +2110,10 @@ Type TDrawList
 	end rem
 	Method DrawRectImageSourceSize( x0:Float,y0:Float,width:Float,height:Float,image:TImage,sourceX:Int,sourceY:Int,sourceWidth:Int,sourceHeight:Int )
 		Local material:TMaterial=image._material
-		Local s0:Float=Float(image._x+sourceX)/Float(material.Width)
-		Local t0:Float=Float(image._y+sourceY)/Float(material.Height)
-		Local s1:Float=Float(image._x+sourceX+sourceWidth)/Float(material.Width)
-		Local t1:Float=Float(image._y+sourceY+sourceHeight)/Float(material.Height)
+		Local s0:Float=Float(image._x+sourceX)/Float(material.Width())
+		Local t0:Float=Float(image._y+sourceY)/Float(material.Height())
+		Local s1:Float=Float(image._x+sourceX+sourceWidth)/Float(material.Width())
+		Local t1:Float=Float(image._y+sourceY+sourceHeight)/Float(material.Height())
 		DrawRect x0,y0,width,height,material,s0,t0,s1,t1
 	End Method
 	
@@ -2171,7 +2196,12 @@ Type TDrawList
 	Method DrawText( Text:String,x:Float,y:Float,xhandle:Float=0,yhandle:Float=0 )
 		x:-_font.TextWidth( Text )*xhandle
 		y:-_font.TextHeight( Text )*yhandle
+?bmxng
 		For Local char:Int=EachIn Text
+?Not bmxng
+		For Local i:Int=0 Until Text.length
+			Local char:Int = Text[i]
+?
 			Local glyph:TGlyph=_font.GetGlyph( char )
 			If Not glyph Continue
 			DrawRectImageSource x,y,glyph.image,glyph.x,glyph.y,glyph.width,glyph.height
@@ -2337,7 +2367,7 @@ Type TDrawList
 		Case 3
 			glDrawArrays GL_TRIANGLES,index,count
 		Case 4
-			glDrawElements GL_TRIANGLES,count/4*6,GL_UNSIGNED_SHORT,(index/4*6 + (index&3)*MAX_QUAD_INDICES)*2
+			glDrawElements GL_TRIANGLES,count/4*6,GL_UNSIGNED_SHORT,Byte Ptr((index/4*6 + (index&3)*MAX_QUAD_INDICES)*2)
 		Default
 			Local j:Int=0
 			While j<count
@@ -2513,8 +2543,8 @@ Type TDrawList
 	End Method
 	
 	Method PrimVert( x0:Float,y0:Float,s0:Float,t0:Float ) Final
-		Local df:Float Ptr = (_data._buf + _next)
-		Local di:Int Ptr = (_data._buf + _next)
+		Local df:Float Ptr = Float Ptr(_data._buf + _next)
+		Local di:Int Ptr = Int Ptr(_data._buf + _next)
 		df[0] = x0 * _ix + y0 * _jx + _tx
 		df[1] = x0 * _iy + y0 * _jy + _ty
 		df[2] = s0
@@ -2562,23 +2592,23 @@ Type TCanvas Extends TDrawList
 		Else If TImage( target )
 		
 			_image=TImage( target )
-			_texture=_image.Material.ColorTexture
-			If Not (_texture.Flags & TTexture.RenderTarget) Throw "Texture is not a render target texture"
-			_width=_image.Width
-			_height=_image.Height
-			_twidth=_texture.Width
-			_theight=_texture.Height
+			_texture=_image.Material().ColorTexture()
+			If Not (_texture.Flags() & TTexture.RenderTarget) Throw "Texture is not a render target texture"
+			_width=_image.Width()
+			_height=_image.Height()
+			_twidth=_texture.Width()
+			_theight=_texture.Height()
 			
 		Else If TTexture( target )
 		
 			_image=Null
 			_texture=TTexture( target )
 
-			If Not (_texture.Flags & TTexture.RenderTarget) Throw "Texture is not a render target texture"
-			_width=_texture.Width
-			_height=_texture.Height
-			_twidth=_texture.Width
-			_theight=_texture.Height
+			If Not (_texture.Flags() & TTexture.RenderTarget) Throw "Texture is not a render target texture"
+			_width=_texture.Width()
+			_height=_texture.Height()
+			_twidth=_texture.Width()
+			_theight=_texture.Height()
 			
 		Else
 		
@@ -2955,7 +2985,7 @@ Type TCanvas Extends TDrawList
 	End Method
 
 	Method FlushPrims()
-		If Super.IsEmpty Return
+		If Super.IsEmpty() Return
 		Validate
 		Super.Flush
 	End Method

+ 3 - 0
mojo2.mod/maps.bmx

@@ -20,6 +20,9 @@
 Strict
 
 Import "maps.c"
+?Not bmxng
+Import "tree/tree.c"
+?
 
 Extern
 	Function bmx_map_stringfloatmap_clear(root:Byte Ptr Ptr)

+ 4 - 0
mojo2.mod/maps.c

@@ -20,7 +20,11 @@ freely, subject to the following restrictions:
 
 */
 #include "brl.mod/blitz.mod/blitz.h"
+#ifdef BMX_NG
 #include "brl.mod/blitz.mod/tree/tree.h"
+#else
+#include "tree/tree.h"
+#endif
 
 #define generic_compare(x, y) (((x) > (y)) - ((x) < (y)))
 

+ 22 - 0
mojo2.mod/renderer.bmx

@@ -35,6 +35,7 @@ Global tvector:Float[4]
 
 Public
 
+?bmxng
 Interface ILight
 
 	Method LightMatrix:Float[]()
@@ -54,6 +55,27 @@ Interface ILayer
 	Method OnRenderLayer( drawLists:TDrawListStack )
 	
 End Interface
+?Not bmxng
+Type ILight
+
+	Method LightMatrix:Float[]() Abstract
+	Method LightType:Int() Abstract
+	Method LightColor:Float[]() Abstract
+	Method LightRange:Float() Abstract
+	Method LightImage:TImage() Abstract
+	
+End Type
+
+Type ILayer
+
+	Method LayerMatrix:Float[]() Abstract
+	Method LayerFogColor:Float[]() Abstract
+	Method LayerLightMaskImage:TImage() Abstract
+	Method EnumLayerLights( lights:TILightStack ) Abstract
+	Method OnRenderLayer( drawLists:TDrawListStack ) Abstract
+	
+End Type
+?
 
 Type TRenderer
 

+ 785 - 0
mojo2.mod/tree/tree.c

@@ -0,0 +1,785 @@
+/* The MIT License
+
+   Copyright (C) 2011, 2012 Zilong Tan ([email protected])
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+#include "tree.h"
+
+struct tree_root_np *
+tree_search(struct tree_root_np *entry,
+	    int (*compare)(const void *, const void *),
+	    struct tree_root_np *root)
+{
+	int sgn;
+	while (root) {
+		sgn = compare(entry, root);
+		if (sgn == 0)
+			return root;
+		if (sgn < 0)
+			root = root->left;
+		else
+			root = root->right;
+	}
+	return root;
+}
+
+struct tree_root_np *
+tree_min(struct tree_root_np *root)
+{
+	if (root) {
+		while (root->left)
+			root = root->left;
+	}
+	return root;
+}
+
+struct tree_root_np *
+tree_max(struct tree_root_np *root)
+{
+	if (root) {
+		while (root->right)
+			root = root->right;
+	}
+	return root;
+}
+
+struct tree_root *
+tree_successor(struct tree_root *entry)
+{
+	struct tree_root *succ = NULL;
+
+	if (entry) {
+		if (entry->right)
+			return (struct tree_root *)TREE_MIN(entry->right);
+		succ = entry->parent;
+		while (succ && entry == succ->right) {
+			entry = succ;
+			succ = succ->parent;
+		}
+	}
+	return succ;
+}
+
+struct tree_root *
+tree_predecessor(struct tree_root *entry)
+{
+	struct tree_root *pred = NULL;
+
+	if (entry) {
+		if (entry->left)
+			return (struct tree_root *)TREE_MAX(entry->left);
+		pred = entry->parent;
+		while (pred && entry == pred->left) {
+			entry = pred;
+			pred = pred->parent;
+		}
+	}
+	return pred;
+}
+
+static inline void
+__rotate_left(struct tree_root *entry, struct tree_root **root)
+{
+	struct tree_root *child;
+
+	child = entry->right;
+	entry->right = child->left;
+	if (child->left)
+		child->left->parent = entry;
+	child->parent = entry->parent;
+	if (entry->parent == NULL)
+		*root = child;
+	else if (entry == entry->parent->left)
+		entry->parent->left = child;
+	else
+		entry->parent->right = child;
+	child->left = entry;
+	entry->parent = child;
+}
+
+static inline void
+__rotate_right(struct tree_root *entry,
+	       struct tree_root **root)
+{
+	struct tree_root *child;
+
+	child = entry->left;
+	entry->left = child->right;
+	if (child->right)
+		child->right->parent = entry;
+
+	child->parent = entry->parent;
+
+	if (entry->parent == NULL)
+		*root = child;
+	else if (entry == entry->parent->left)
+		entry->parent->left = child;
+	else
+		entry->parent->right = child;
+	child->right = entry;
+	entry->parent = child;
+}
+
+void tree_add(struct tree_root *new,
+	      int (*compare)(const void *, const void *),
+	      struct tree_root **root)
+{
+	int sgn = 0;
+	struct tree_root *next = *root;
+	struct tree_root *cur  = NULL;
+
+	INIT_TREE_ROOT(new);
+
+	while (next) {
+		cur = next;
+		sgn = compare(new, next);
+		if (sgn < 0)
+			next = next->left;
+		else
+			next = next->right;
+	}
+
+	new->parent = cur;
+	if (cur == NULL)
+		*root = new;
+	else if (sgn < 0)
+		cur->left = new;
+	else
+		cur->right = new;
+}
+
+struct tree_root *
+tree_map(struct tree_root *new,
+	 int (*compare)(const void *, const void *),
+	 struct tree_root **root)
+{
+	int sgn = 0;
+	struct tree_root *next = *root;
+	struct tree_root *cur  = NULL;
+
+	INIT_TREE_ROOT(new);
+
+	while (next) {
+		cur = next;
+		sgn = compare(new, next);
+		if (sgn == 0)
+			return next;
+		else if (sgn < 0)
+			next = next->left;
+		else
+			next = next->right;
+	}
+
+	new->parent = cur;
+	if (cur == NULL)
+		*root = new;
+	else if (sgn < 0)
+		cur->left = new;
+	else
+		cur->right = new;
+	return new;
+}
+
+void
+tree_del(struct tree_root *entry, struct tree_root **root)
+{
+	struct tree_root *child;
+	struct tree_root *succ;
+
+	if (entry->left == NULL || entry->right == NULL)
+		succ = entry;
+	else
+		succ = TREE_SUCCESSOR(entry);
+	if (succ->left)
+		child = succ->left;
+	else
+		child = succ->right;
+
+	if (child)
+		child->parent = succ->parent;
+	if (succ->parent == NULL)
+		*root = child;
+	else if (succ == succ->parent->left)
+		succ->parent->left = child;
+	else
+		succ->parent->right = child;
+
+	if (succ != entry) {
+		succ->left = entry->left;
+		if (entry->left)
+			entry->left->parent = succ;
+		succ->right = entry->right;
+		if (entry->right)
+			entry->right->parent = succ;
+		succ->parent = entry->parent;
+		if (entry->parent == NULL)
+			*root = succ;
+		else if (entry == entry->parent->left)
+			entry->parent->left = succ;
+		else
+			entry->parent->right = succ;
+	}
+}
+
+#define SPLAY_ROTATE_RIGHT(entry, tmp) do {				\
+		(entry)->left = (tmp)->right;				\
+		if ((tmp)->right) (tmp)->right->parent = (entry);	\
+		(tmp)->right = (entry);					\
+		(tmp)->parent = (entry)->parent;			\
+		(entry)->parent = (tmp);				\
+		(entry) = (tmp);					\
+	} while (0)
+
+#define SPLAY_ROTATE_LEFT(entry, tmp) do {			\
+		(entry)->right = (tmp)->left;			\
+		if ((tmp)->left) (tmp)->left->parent = (entry);	\
+		(tmp)->left = (entry);				\
+		(tmp)->parent = (entry)->parent;		\
+		(entry)->parent = (tmp);			\
+		(entry) = (tmp);				\
+	} while (0)
+
+#define SPLAY_LINK_RIGHT(entry, large) do {	\
+		(large)->left = (entry);	\
+		(entry)->parent = (large);	\
+		(large) = (entry);		\
+		(entry) = (entry)->left;	\
+	} while (0)
+
+#define SPLAY_LINK_LEFT(entry, small) do {	\
+		(small)->right = (entry);	\
+		(entry)->parent = (small);	\
+		(small) = (entry);		\
+		(entry) = (entry)->right;	\
+	} while (0)
+
+#define SPLAY_ASSEMBLE(head, node, small, large) do {		\
+		(small)->right = (head)->left;			\
+		if ((head)->left)				\
+			(head)->left->parent = (small);		\
+		(large)->left = (head)->right;			\
+		if ((head)->right)				\
+			(head)->right->parent = (large);	\
+		(head)->left = (node)->right;			\
+		if ((node)->right)				\
+			(node)->right->parent = (head);		\
+		(head)->right = (node)->left;			\
+		if ((node)->left)				\
+			(node)->left->parent = (head);		\
+	} while (0)
+
+#define SPLAY_ROTATE_RIGHT_NP(entry, tmp) do {	\
+		(entry)->left = (tmp)->right;	\
+		(tmp)->right = (entry);		\
+		(entry) = (tmp);		\
+	} while (0)
+
+#define SPLAY_ROTATE_LEFT_NP(entry, tmp) do {	\
+		(entry)->right = (tmp)->left;	\
+		(tmp)->left = (entry);		\
+		(entry) = (tmp);		\
+	} while (0)
+
+#define SPLAY_LINK_RIGHT_NP(entry, large) do {	\
+		(large)->left = (entry);	\
+		(large) = (entry);		\
+		(entry) = (entry)->left;	\
+	} while (0)
+
+#define SPLAY_LINK_LEFT_NP(entry, small) do {	\
+		(small)->right = (entry);	\
+		(small) = (entry);		\
+		(entry) = (entry)->right;	\
+	} while (0)
+
+#define SPLAY_ASSEMBLE_NP(head, node, small, large) do {	\
+		(small)->right = (head)->left;			\
+		(large)->left = (head)->right;			\
+		(head)->left = (node)->right;			\
+		(head)->right = (node)->left;			\
+	} while (0)
+
+struct tree_root *
+splay_search(struct tree_root *entry,
+	     int (*compare)(const void *, const void *),
+	     struct tree_root **root)
+{
+	int cmp;
+	TREE_ROOT(node);  /* node for assembly use */
+	struct tree_root *small, *large, *head, *tmp;
+
+	head = *root;
+	small = large = &node;
+
+	while ((cmp = compare(entry, head)) != 0) {
+		if (cmp < 0) {
+			tmp = head->left;
+			if (tmp == NULL)
+				break;
+			if (compare(entry, tmp) < 0) {
+				SPLAY_ROTATE_RIGHT(head, tmp);
+				if (head->left == NULL)
+					break;
+			}
+			SPLAY_LINK_RIGHT(head, large);
+		} else {
+			tmp = head->right;
+			if (tmp == NULL)
+				break;
+			if (compare(entry, tmp) > 0) {
+				SPLAY_ROTATE_LEFT(head, tmp);
+				if (head->right == NULL)
+					break;
+			}
+			SPLAY_LINK_LEFT(head, small);
+		}
+	}
+	head->parent = NULL;
+	SPLAY_ASSEMBLE(head, &node, small, large);
+	*root = head;
+
+	if (cmp != 0)
+		return NULL;
+
+	return head;
+}
+
+struct tree_root *
+splay_map(struct tree_root *new,
+	  int (*compare)(const void *, const void *),
+	  struct tree_root **root)
+{
+	int cmp;
+	TREE_ROOT(node);  /* node for assembly use */
+	struct tree_root *small, *large, *head, *tmp;
+
+	INIT_TREE_ROOT(new);
+	small = large = &node;
+	head = *root;
+
+	while (head && (cmp = compare(new, head)) != 0) {
+		if (cmp < 0) {
+			tmp = head->left;
+			if (tmp == NULL) {
+				/* zig */
+				SPLAY_LINK_RIGHT(head, large);
+				break;
+			}
+			cmp = compare(new, tmp);
+			if (cmp < 0) {
+				/* zig-zig */
+				SPLAY_ROTATE_RIGHT(head, tmp);
+				SPLAY_LINK_RIGHT(head, large);
+			} else if (cmp > 0) {
+				/* zig-zag */
+				SPLAY_LINK_RIGHT(head, large);
+				SPLAY_LINK_LEFT(head, small);
+			} else {
+				/* zig */
+				SPLAY_LINK_RIGHT(head, large);
+				break;
+			}
+		} else {
+			tmp = head->right;
+			if (tmp == NULL) {
+				/* zag */
+				SPLAY_LINK_LEFT(head, small);
+				break;
+			}
+			cmp = compare(new, tmp);
+			if (cmp > 0) {
+				/* zag-zag */
+				SPLAY_ROTATE_LEFT(head, tmp);
+				SPLAY_LINK_LEFT(head, small);
+			} else if (cmp < 0) {
+				/* zag-zig */
+				SPLAY_LINK_LEFT(head, small);
+				SPLAY_LINK_RIGHT(head, large);
+			} else {
+				/* zag */
+				SPLAY_LINK_LEFT(head, small);
+				break;
+			}
+		}
+	}
+
+	if (head == NULL)
+		head = new;
+
+	head->parent = NULL;
+
+	SPLAY_ASSEMBLE(head, &node, small, large);
+
+	*root = head;
+
+	return head;
+}
+
+struct tree_root_np *
+splay_search_np(struct tree_root_np *entry,
+		int (*compare)(const void *, const void *),
+		struct tree_root_np **root)
+{
+	int cmp;
+	TREE_ROOT_NP(node);  /* node for assembly use */
+	struct tree_root_np *small, *large, *head, *tmp;
+
+	head = *root;
+	small = large = &node;
+
+	while ((cmp = compare(entry, head)) != 0) {
+		if (cmp < 0) {
+			tmp = head->left;
+			if (tmp == NULL)
+				break;
+			if (compare(entry, tmp) < 0) {
+				SPLAY_ROTATE_RIGHT_NP(head, tmp);
+				if (head->left == NULL)
+					break;
+			}
+			SPLAY_LINK_RIGHT_NP(head, large);
+		} else {
+			tmp = head->right;
+			if (tmp == NULL)
+				break;
+			if (compare(entry, tmp) > 0) {
+				SPLAY_ROTATE_LEFT_NP(head, tmp);
+				if (head->right == NULL)
+					break;
+			}
+			SPLAY_LINK_LEFT_NP(head, small);
+		}
+	}
+
+	SPLAY_ASSEMBLE_NP(head, &node, small, large);
+	*root = head;
+
+	if (cmp != 0)
+		return NULL;
+
+	return head;
+}
+
+struct tree_root_np *
+splay_map_np(struct tree_root_np *new,
+	     int (*compare)(const void *, const void *),
+	     struct tree_root_np **root)
+{
+	int cmp;
+	TREE_ROOT_NP(node);  /* node for assembly use */
+	struct tree_root_np *small, *large, *head, *tmp;
+
+	INIT_TREE_ROOT_NP(new);
+	small = large = &node;
+	head = *root;
+
+	while (head && (cmp = compare(new, head)) != 0) {
+		if (cmp < 0) {
+			tmp = head->left;
+			if (tmp == NULL) {
+				/* zig */
+				SPLAY_LINK_RIGHT_NP(head, large);
+				break;
+			}
+			cmp = compare(new, tmp);
+			if (cmp < 0) {
+				/* zig-zig */
+				SPLAY_ROTATE_RIGHT_NP(head, tmp);
+				SPLAY_LINK_RIGHT_NP(head, large);
+			} else if (cmp > 0) {
+				/* zig-zag */
+				SPLAY_LINK_RIGHT_NP(head, large);
+				SPLAY_LINK_LEFT_NP(head, small);
+			} else {
+				/* zig */
+				SPLAY_LINK_RIGHT_NP(head, large);
+				break;
+			}
+		} else {
+			tmp = head->right;
+			if (tmp == NULL) {
+				/* zag */
+				SPLAY_LINK_LEFT_NP(head, small);
+				break;
+			}
+			cmp = compare(new, tmp);
+			if (cmp > 0) {
+				/* zag-zag */
+				SPLAY_ROTATE_LEFT_NP(head, tmp);
+				SPLAY_LINK_LEFT_NP(head, small);
+			} else if (cmp < 0) {
+				/* zag-zig */
+				SPLAY_LINK_LEFT_NP(head, small);
+				SPLAY_LINK_RIGHT_NP(head, large);
+			} else {
+				/* zag */
+				SPLAY_LINK_LEFT_NP(head, small);
+				break;
+			}
+		}
+	}
+
+	if (head == NULL)
+		head = new;
+
+	SPLAY_ASSEMBLE_NP(head, &node, small, large);
+
+	*root = head;
+
+	return head;
+}
+
+static inline void
+__avl_balance(struct avl_root *new, struct avl_root **root)
+{
+	int balance = 0;
+	struct avl_root *child, *grandson;
+
+	while (new->parent && balance == 0) {
+		balance = new->parent->balance;
+		if (new == new->parent->left)
+			new->parent->balance--;
+		else
+			new->parent->balance++;
+		new = new->parent;
+	}
+
+	if (new->balance == -2) {
+		child = new->left;
+		if (child->balance == -1) {
+			__rotate_right((struct tree_root *)new,
+				       (struct tree_root **)root);
+			child->balance = 0;
+			new->balance = 0;
+		} else {
+			grandson = child->right;
+			__rotate_left((struct tree_root *)child,
+				      (struct tree_root **)root);
+			__rotate_right((struct tree_root *)new,
+				       (struct tree_root **)root);
+			if (grandson->balance == -1) {
+				child->balance = 0;
+				new->balance = 1;
+			} else if (grandson->balance == 0) {
+				child->balance = 0;
+				new->balance = 0;
+			} else {
+				child->balance = -1;
+				new->balance = 0;
+			}
+			grandson->balance = 0;
+		}
+	} else if (new->balance == 2) {
+		child = new->right;
+		if (child->balance == 1) {
+			__rotate_left((struct tree_root *)new,
+				      (struct tree_root **)root);
+			child->balance = 0;
+			new->balance = 0;
+		} else {
+			grandson = child->left;
+			__rotate_right((struct tree_root *)child,
+				       (struct tree_root **)root);
+			__rotate_left((struct tree_root *)new,
+				      (struct tree_root **)root);
+			if (grandson->balance == -1) {
+				child->balance = 1;
+				new->balance = 0;
+			} else if (grandson->balance == 0) {
+				child->balance = 0;
+				new->balance = 0;
+			} else {
+				child->balance = 0;
+				new->balance = -1;
+			}
+			grandson->balance = 0;
+		}
+	}
+}
+
+void avl_add(struct avl_root *new,
+	     int (*compare)(const void *, const void *),
+	     struct avl_root **root)
+{
+	new->balance = 0;
+	TREE_ADD(new, compare, root);
+	__avl_balance(new, root);
+}
+
+struct avl_root *
+avl_map(struct avl_root *new,
+	int (*compare)(const void *, const void *),
+	struct avl_root **root)
+{
+	struct avl_root *node;
+
+	new->balance = 0;
+	node = (struct avl_root *)TREE_MAP(new, compare, root);
+	if (node != new)
+		return node;
+	__avl_balance(new, root);
+
+	return new;
+}
+
+void avl_del(struct avl_root *entry, struct avl_root **root)
+{
+	int dir = 0;
+	int dir_next = 0;
+	struct avl_root *unbalanced, *child, *succ, *parent;
+
+	if (entry->right == NULL) {
+		/* Case 1: entry has no right child */
+		if (entry->left)
+			entry->left->parent = entry->parent;
+		if (entry->parent == NULL) {
+			*root = entry->left;
+			return;
+		} else if (entry == entry->parent->left) {
+			entry->parent->left = entry->left;
+			dir = 0;
+		} else {
+			entry->parent->right = entry->left;
+			dir = 1;
+		}
+		unbalanced = entry->parent;
+	} else if (entry->right->left == NULL) {
+		/* Case 2: entry's right child has no left child */
+		entry->right->left = entry->left;
+		if (entry->left)
+			entry->left->parent = entry->right;
+		entry->right->parent = entry->parent;
+		if (entry->parent == NULL)
+			*root = entry->right;
+		else if (entry == entry->parent->left)
+			entry->parent->left = entry->right;
+		else
+			entry->parent->right = entry->right;
+		entry->right->balance = entry->balance;
+		unbalanced = entry->right;
+		dir = 1;
+	} else {
+		/* Case 3: entry's right child has a left child */
+		succ = (struct avl_root *)TREE_SUCCESSOR(entry);
+		if (succ->right)
+			succ->right->parent = succ->parent;
+		succ->parent->left = succ->right;
+		unbalanced = succ->parent;
+		succ->left = entry->left;
+		entry->left->parent = succ;
+		succ->right = entry->right;
+		entry->right->parent = succ;
+		succ->parent = entry->parent;
+		if (entry->parent == NULL)
+			*root = succ;
+		else if (entry == entry->parent->left)
+			entry->parent->left = succ;
+		else
+			entry->parent->right = succ;
+		succ->balance = entry->balance;
+		dir = 0;
+	}
+
+	for (;;) {
+		parent = unbalanced->parent;
+		if (parent)
+			dir_next = (unbalanced == parent->right);
+		if (dir == 0) {
+			++unbalanced->balance;
+			if (unbalanced->balance == 1)
+				break;
+			if (unbalanced->balance == 2) {
+				child = unbalanced->right;
+				if (child->balance == -1) {
+					succ = child->left;
+					__rotate_right((struct tree_root *)child,
+						       (struct tree_root **)root);
+					__rotate_left((struct tree_root *)unbalanced,
+						      (struct tree_root **)root);
+					if (succ->balance == -1) {
+						child->balance = 1;
+						unbalanced->balance = 0;
+					} else if (succ->balance == 0) {
+						child->balance = 0;
+						unbalanced->balance = 0;
+					} else {
+						child->balance = 0;
+						unbalanced->balance = -1;
+					}
+					succ->balance = 0;
+				} else {
+					__rotate_left((struct tree_root *)unbalanced,
+						      (struct tree_root **)root);
+					if (child->balance == 0) {
+						child->balance = -1;
+						unbalanced->balance = 1;
+						break;
+					} else {
+						child->balance = 0;
+						unbalanced->balance = 0;
+					}
+				}
+			}
+		} else {
+			--unbalanced->balance;
+			if (unbalanced->balance == -1)
+				break;
+			if (unbalanced->balance == -2) {
+				child = unbalanced->left;
+				if (child->balance == 1) {
+					succ = child->right;
+					__rotate_left((struct tree_root *)child,
+						      (struct tree_root **)root);
+					__rotate_right((struct tree_root *)unbalanced,
+						       (struct tree_root **)root);
+					if (succ->balance == -1) {
+						child->balance = 0;
+						unbalanced->balance = 1;
+					} else if (succ->balance == 0) {
+						child->balance = 0;
+						unbalanced->balance = 0;
+					} else {
+						child->balance = -1;
+						unbalanced->balance = 0;
+					}
+					succ->balance = 0;
+				} else {
+					__rotate_right((struct tree_root *)unbalanced,
+						       (struct tree_root **)root);
+					if (child->balance == 0) {
+						child->balance = 1;
+						unbalanced->balance = -1;
+						break;
+					} else {
+						child->balance = 0;
+						unbalanced->balance = 0;
+					}
+				}
+			}
+		}
+		if (parent == NULL)
+			break;
+		dir = dir_next;
+		unbalanced = parent;
+	}
+}

+ 285 - 0
mojo2.mod/tree/tree.h

@@ -0,0 +1,285 @@
+/* The MIT License
+
+   Copyright (C) 2011, 2012 Zilong Tan ([email protected])
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+#ifndef _ULIB_TREE_H
+#define _ULIB_TREE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+#define new _new_
+#endif
+
+struct tree_root_np {
+	struct tree_root_np *left, *right;
+};
+
+struct tree_root {
+	struct tree_root *left, *right, *parent;
+};
+
+struct avl_root {
+	struct avl_root *left, *right, *parent;
+	int balance:3;
+};
+
+#define TREE_ROOT_NP_INIT { NULL, NULL }
+
+#define TREE_ROOT_NP(name)				\
+	struct tree_root_np name = TREE_ROOT_NP_INIT
+
+#define INIT_TREE_ROOT_NP(ptr) do {			\
+		(ptr)->left = (ptr)->right = NULL;	\
+	} while (0)
+
+#define TREE_ROOT_INIT { NULL, NULL, NULL }
+
+#define TREE_ROOT(name)				\
+	struct tree_root name = TREE_ROOT_INIT
+
+#define INIT_TREE_ROOT(ptr) do {		\
+		(ptr)->left   = NULL;		\
+		(ptr)->right  = NULL;		\
+		(ptr)->parent = NULL;		\
+	} while (0)
+
+#define AVL_ROOT_INIT { NULL, NULL, NULL, 0 }
+
+#define AVL_ROOT(name)				\
+	struct avl_root name = AVL_ROOT_INIT;
+
+#define INIT_AVL_ROOT(ptr) do {			\
+		INIT_TREE_ROOT(ptr);		\
+		(ptr)->balance = 0;		\
+	} while (0)
+
+#define TREE_NP_ISEMPTY(ptr)  ((ptr) == NULL)
+#define TREE_ISEMPTY(ptr)     TREE_NP_ISEMPTY(ptr)
+#define SPLAY_ISEMPTY(ptr)    TREE_NP_ISEMPTY(ptr)
+#define AVL_ISEMPTY(ptr)      TREE_NP_ISEMPTY(ptr)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct tree_root_np *
+tree_search(struct tree_root_np *entry,
+	    int (*compare)(const void *, const void *),
+	    struct tree_root_np *root);
+
+#define TREE_SEARCH(entry, comp, root)					\
+	tree_search((struct tree_root_np*)(entry),			\
+		    (int (*)(const void *, const void *))(comp),	\
+		    (struct tree_root_np*)(root))
+
+struct tree_root_np *
+tree_min(struct tree_root_np *root);
+
+#define TREE_MIN(root)				\
+	tree_min((struct tree_root_np*)(root))
+
+struct tree_root_np *
+tree_max(struct tree_root_np *root);
+
+#define TREE_MAX(root)				\
+	tree_max((struct tree_root_np*)(root))
+
+struct tree_root *
+tree_successor(struct tree_root *entry);
+
+#define TREE_SUCCESSOR(entry)				\
+	tree_successor((struct tree_root*)(entry))
+
+struct tree_root *
+tree_predecessor(struct tree_root *entry);
+
+#define TREE_PREDECESSOR(entry)				\
+	tree_predecessor((struct tree_root*)(entry))
+
+/* add a new entry ignoring any duplicates */
+void tree_add(struct tree_root *new,
+	      int (*compare)(const void *, const void *),
+	      struct tree_root **root);
+
+#define TREE_ADD(new, comp, root)				\
+	tree_add((struct tree_root*)(new),			\
+		 (int (*)(const void *, const void *))(comp),	\
+		 (struct tree_root**)(root))
+
+/* add a unique entry
+   if the entry already exists, return the old one; otherwise
+   the new entry will be returned. */
+struct tree_root *
+tree_map(struct tree_root *new,
+	 int (*compare)(const void *, const void *),
+	 struct tree_root **root);
+
+#define TREE_MAP(new, comp, root)				\
+	tree_map((struct tree_root*)(new),			\
+		 (int (*)(const void *, const void *))(comp),	\
+		 (struct tree_root**)(root))
+
+void tree_del(struct tree_root *entry, struct tree_root **root);
+
+#define TREE_DEL(entry, root)			\
+	tree_del((struct tree_root*)(entry),	\
+		 (struct tree_root**)(root))
+
+/* in addition to the tree_map, this operation splays the tree */
+struct tree_root *
+splay_map(struct tree_root *new,
+	  int (*compare)(const void *, const void *),
+	  struct tree_root **root);
+
+#define SPLAY_MAP(new, comp, root)				\
+	splay_map((struct tree_root*)(new),			\
+		  (int (*)(const void *, const void *))(comp),	\
+		  (struct tree_root**)(root))
+
+struct tree_root_np *
+splay_map_np(struct tree_root_np *new,
+	     int (*compare)(const void *, const void *),
+	     struct tree_root_np **root);
+
+#define SPLAY_MAP_NP(new, comp, root)					\
+	splay_map_np((struct tree_root_np*)(new),			\
+		     (int (*)(const void *, const void *))(comp),	\
+		     (struct tree_root_np**)(root))
+
+struct tree_root *
+splay_search(struct tree_root *entry,
+	     int (*compare)(const void *, const void *),
+	     struct tree_root **root);
+
+#define SPLAY_SEARCH(entry, comp, root)					\
+	splay_search((struct tree_root*)(entry),			\
+		     (int (*)(const void *, const void *))(comp),	\
+		     (struct tree_root**)(root))
+
+struct tree_root_np *
+splay_search_np(struct tree_root_np *entry,
+		int (*compare)(const void *, const void *),
+		struct tree_root_np **root);
+
+#define SPLAY_SEARCH_NP(entry, comp, root)				\
+	splay_search_np((struct tree_root_np*)(entry),			\
+			(int (*)(const void *, const void *))(comp),	\
+			(struct tree_root_np**)(root))
+
+void avl_add(struct avl_root *new,
+	     int (*compare)(const void *, const void *),
+	     struct avl_root **root);
+
+#define AVL_ADD(new, comp, root)				\
+	avl_add((struct avl_root*)(new),			\
+		(int (*)(const void *, const void *))(comp),	\
+		(struct avl_root**)(root))
+
+struct avl_root *
+avl_map(struct avl_root *new,
+	int (*compare)(const void *, const void *),
+	struct avl_root **root);
+
+#define AVL_MAP(new, comp, root)				\
+	avl_map((struct avl_root*)(new),			\
+		(int (*)(const void *, const void *))(comp),	\
+		(struct avl_root**)(root))
+
+void avl_del(struct avl_root *entry, struct avl_root **root);
+
+#define AVL_DEL(entry, root)			\
+	avl_del((struct avl_root*)(entry),	\
+		(struct avl_root**)(root))
+
+#ifdef __cplusplus
+}
+#endif
+
+/* retrieves the address of the host struct.
+ * @ptr is the pointer to the embedded struct of which the name is
+ * provided by @member, and @type indicates the host struct type. */
+#define tree_entry(ptr, type, member)					\
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define avl_entry(ptr, type, member) tree_entry(ptr, type, member)
+
+#define tree_for_each(pos, root)				\
+	for (pos = (typeof(pos))TREE_MIN(root); pos != NULL;	\
+	     pos = (typeof(pos))TREE_SUCCESSOR(pos))
+
+#define tree_for_each_prev(pos, root)				\
+	for (pos = (typeof(pos))TREE_MAX(root); pos != NULL;	\
+	     pos = (typeof(pos))TREE_PREDECESSOR(pos))
+
+#define tree_for_each_safe(pos, n, root)				\
+	for (pos = (typeof(pos))TREE_MIN(root), n = (typeof(n))TREE_SUCCESSOR(pos); \
+	     pos != NULL;						\
+	     pos = n, n = n? (typeof(n))TREE_SUCCESSOR(n): NULL)
+
+#define tree_for_each_entry(pos, root, member)				\
+	for (pos = tree_entry(TREE_MIN(root), typeof(*pos), member);	\
+	     &pos->member != NULL;					\
+	     pos = tree_entry(TREE_SUCCESSOR(&pos->member), typeof(*pos), member))
+
+#define tree_for_each_entry_safe(pos, n, root, member)			\
+	for (pos = tree_entry(TREE_MIN(root), typeof(*pos), member),	\
+		     n = tree_entry(TREE_SUCCESSOR(&pos->member), typeof(*pos), member); \
+	     &pos->member != NULL;					\
+	     pos = n, n = tree_entry(&n->member != NULL?		\
+				     TREE_SUCCESSOR(&n->member): NULL,	\
+				     typeof(*n), member))
+
+#define avl_for_each(pos, root)						\
+	for (pos = (struct avl_root *)TREE_MIN(root); pos != NULL;	\
+	     pos = (struct avl_root *)TREE_SUCCESSOR(pos))
+
+#define avl_for_each_prev(pos, root)					\
+	for (pos = (struct avl_root *)TREE_MAX(root); pos != NULL;	\
+	     pos = (struct avl_root *)TREE_PREDECESSOR(pos))
+
+#define avl_for_each_safe(pos, n, root)					\
+	for (pos = (struct avl_root *)TREE_MIN(root),			\
+		     n = (struct avl_root *)TREE_SUCCESSOR(pos);	\
+	     pos != NULL;						\
+	     pos = n, n = n != NULL? (struct avl_root *)TREE_SUCCESSOR(n): NULL)
+
+#define avl_for_each_entry(pos, root, member)				\
+	for (pos = tree_entry(TREE_MIN(root), typeof(*pos), member);	\
+	     &pos->member != NULL;					\
+	     pos = tree_entry(TREE_SUCCESSOR(&pos->member), typeof(*pos), member))
+
+#define avl_for_each_entry_safe(pos, n, root, member)			\
+	for (pos = tree_entry(TREE_MIN(root), typeof(*pos), member),	\
+		     n = tree_entry(TREE_SUCCESSOR(&pos->member), typeof(*pos), member); \
+	     &pos->member != NULL;					\
+	     pos = n, n = tree_entry(&n->member != NULL?		\
+				     TREE_SUCCESSOR(&n->member): NULL,	\
+				     typeof(*n), member))
+
+#ifdef __cplusplus
+#undef new
+#endif
+
+#endif	/* _ULIB_TREE_H */