Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

RBTREE.ASM

Red-black balanced tree


; =============================================================================
;
;                       Litos - Red-black balanced tree
;
; =============================================================================
; A red-black tree is a type of self-balancing binary search tree. Each node
; has a color attribute, the value of which is either red or black.
;
; Requirements:
;	1. Every node is either red or black
;	2. The root is alwys black
;	3. All leaves (dummy empty nodes NULL) are black
;	4. Both children of every red node are black
;	5. All paths from any given node to its leaf nodes contain the same
;	   number of black nodes
; =============================================================================

		CODE_SECTION	32

; ------------- Macro - initialized red-black tree root

%macro		RBTREE	0
		LISTHEAD		; list of entries
		db	RB_BLACK	; color of node
		db	RB_ROOT		; flags
		dw	0		; data WORD
		dd	0		; pointer to first node (0=none)
		dd	0		; number of nodes
%endmacro

; ------------- Macro - initialized red-black tree node

%macro		RBTREENODE 0
		LISTHEAD		; list of entries
		db	RB_BLACK	; color of node
		db	0		; flags
		dw	0		; data WORD
		dd	0		; parent node (NULL=root)
		dd	0		; left node (NULL=none)
		dd	0		; right node (NULL=none)
%endmacro

; ------------- Macro - set color of node to red (%1 = pointer to node)

%macro		SETRED	1
		mov	byte [%1+RB_Color],RB_RED
%endmacro

; ------------- Macro - set color of node to black (%1 = pointer to node)

%macro		SETBLK	1
		mov	byte [%1+RB_Color],RB_BLACK
%endmacro

; ------------- Macro - test color for red, ZY=is red (%1 = pointer to node)

%macro		CMPRED	1
		cmp	byte [%1+RB_Color],RB_RED
%endmacro

; ------------- Macro - test color for black, ZY=is black (%1=pointer to node)

%macro		CMPBLK	1
		cmp	byte [%1+RB_Color],RB_BLACK
%endmacro

; -----------------------------------------------------------------------------
;                   Initialize red-black balanced tree root
; -----------------------------------------------------------------------------
; INPUT:	EDX = pointer to root (RBROOT)
; -----------------------------------------------------------------------------

RBTreeInit:	LISTINIT edx		; initialize list of entries
		mov	dword [edx+RB_ColorFlags],RB_BLACK+(RB_ROOT<<8)
		and	dword [edx+RBR_Node],byte 0 ; no first node
		and	dword [edx+RBR_Count],byte 0 ; no entry
		ret

; -----------------------------------------------------------------------------
;          Get first node (in sort order) of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EDX = pointer to root (RBROOT)
; OUTPUT:	EBX = first node (NULL = none)
;		CY = no node found (EBX = NULL)
; -----------------------------------------------------------------------------

RBTreeFirst:	mov	ebx,[edx+LIST_Next]	; EBX <- first node
		test	byte [ebx+RB_Flags],RB_ROOT ; is it root?
		jz	RBTreeFirst2		; first node is valid
		xor	ebx,ebx			; EBX <- invalid node
		stc				; set error flag
RBTreeFirst2:	ret

; ------------- Get first node

;RBTreeFirst:	mov	ebx,[edx+RBR_Node]	; EBX <- first node
;		or	ebx,ebx			; any node?
;		stc				; set error flag
;		jz	RBTreeFirst8		; no node found

; ------------- Push registers

;		push	eax			; push EAX

; ------------- Find leftmost node

;		xchg	eax,ebx			; EAX <- first node
;RBTreeFirst4:	xchg	eax,ebx			; EBX <- next node
;		mov	eax,[ebx+RBN_Left]	; EAX <- next left node
;		or	eax,eax			; valid left node?
;		jnz	RBTreeFirst4		; get next node

; ------------- Pop registers

;		pop	eax			; pop EAX
;RBTreeFirst8:	ret

; -----------------------------------------------------------------------------
;           Get last node (in sort order) of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EDX = pointer to root (RBROOT)
; OUTPUT:	EBX = last node (NULL = none)
;		CY = no node found (EBX = NULL)
; -----------------------------------------------------------------------------

RBTreeLast:	mov	ebx,[edx+LIST_Prev]	; EBX <- last node
		test	byte [ebx+RB_Flags],RB_ROOT ; is it root?
		jz	RBTreeLast2		; last node is valid
		xor	ebx,ebx			; EBX <- invalid node
		stc				; set error flag
RBTreeLast2:	ret

; ------------- Get first node

;RBTreeLast:	mov	ebx,[edx+RBR_Node]	; EBX <- first node
;		or	ebx,ebx			; any node?
;		stc				; set error flag
;		jz	RBTreeLast8		; no node found

; ------------- Push registers

;		push	eax			; push EAX

; ------------- Find rightmost node

;		xchg	eax,ebx			; EAX <- first node
;RBTreeLast4:	xchg	eax,ebx			; EBX <- next node
;		mov	eax,[ebx+RBN_Right]	; EAX <- next right node
;		or	eax,eax			; valid right node?
;		jnz	RBTreeLast4		; get next node

; ------------- Pop registers

;		pop	eax			; pop EAX
;RBTreeLast8:	ret

; -----------------------------------------------------------------------------
;           Get next node (in sort order) of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to current node (RBNODE)
; OUTPUT:	EBX = next node (NULL = none)
;		CY = no other node (EBX = NULL)
; -----------------------------------------------------------------------------

RBTreeNext:	mov	ebx,[ebx+LIST_Next]	; EBX <- next node
		test	byte [ebx+RB_Flags],RB_ROOT ; is it root?
		jz	RBTreeNext2		; next node is valid
		xor	ebx,ebx			; EBX <- invalid node
		stc				; set error flag
RBTreeNext2:	ret

; ------------- Push registers

;RBTreeNext:	push	eax			; push EAX

; ------------- Get right node

;		mov	eax,[ebx+RBN_Right]	; EAX <- right node
;		or	eax,eax			; is right node valid?
;		jz	RBTreeNext4		; right node is not valid

; ------------- Find leftmost node of right branch

;RBTreeNext2:	xchg	eax,ebx			; EBX <- node is valid
;		mov	eax,[ebx+RBN_Left]	; EAX <- next left node
;		or	eax,eax			; is next left node valid?
;		jnz	RBTreeNext2		; get next left node
;		jmp	short RBTreeNext8	; end of chain

; ------------- Get next parent

;RBTreeNext4:	mov	eax,[ebx+RBN_Parent]	; EAX <- parent
;		or	eax,eax			; is parent valid?
;		xchg	eax,ebx			; EAX <- node, EBX <- parent
;		stc				; set error flag
;		jz	RBTreeNext8		; no other parent

; ------------- Check if this parent is on the right from current node

;		cmp	eax,[ebx+RBN_Left]	; is it left node?
;		jne	RBTreeNext4		; no, it is right node

; ------------- Pop registers

;RBTreeNext8:	pop	eax			; pop EAX
;		ret

; -----------------------------------------------------------------------------
;          Get previous node (in sort order) of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to current node (RBNODE)
; OUTPUT:	EBX = previous node (NULL = none)
;		CY = no other node (EBX = NULL)
; -----------------------------------------------------------------------------

RBTreePrev:	mov	ebx,[ebx+LIST_Prev]	; EBX <- previous node
		test	byte [ebx+RB_Flags],RB_ROOT ; is it root?
		jz	RBTreePrev2		; previous node is valid
		xor	ebx,ebx			; EBX <- invalid node
		stc				; set error flag
RBTreePrev2:	ret

; ------------- Push registers

;RBTreePrev:	push	eax			; push EAX

; ------------- Get left node

;		mov	eax,[ebx+RBN_Left]	; EAX <- left node
;		or	eax,eax			; is left node valid?
;		jz	RBTreePrev4		; left node is not valid

; ------------- Find rightmost node of left branch

;RBTreePrev2:	xchg	eax,ebx			; EBX <- node is valid
;		mov	eax,[ebx+RBN_Right]	; EAX <- next right node
;		or	eax,eax			; is next right node valid?
;		jnz	RBTreePrev2		; get next right node
;		jmp	short RBTreePrev8	; end of chain

; ------------- Get next parent

;RBTreePrev4:	mov	eax,[ebx+RBN_Parent]	; EAX <- next parent
;		or	eax,eax			; is parent valid?
;		xchg	eax,ebx			; EAX <- node, EBX <- parent
;		stc				; set error flag
;		jz	RBTreePrev8		; no other parent

; ------------- Check if this parent is on the left from current node

;		cmp	eax,[ebx+RBN_Right]	; is it right node?
;		jne	RBTreePrev4		; no, it is left node

; ------------- Pop registers

;RBTreePrev8:	pop	eax			; pop EAX
;		ret

; -----------------------------------------------------------------------------
;             Get absolute indexed node of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EAX = absolute index of node
;		EDX = pointer to root (RBROOT)
; OUTPUT:	EBX = node (NULL = none, index is not valid)
;		CY = node not found, index is not valid (EBX = NULL)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeIndex:	push	ecx			; push ECX

; ------------- Check index validity

		mov	ecx,[edx+RBR_Count]	; ECX <- number of nodes
		cmp	eax,ecx			; is index valid?
		cmc				; CY = index is not valid
		jc	RBTreeIndex8		; index is not valid

; ------------- Search node from begin or end of the list?

		shr	ecx,1			; ECX <- number of nodes/2
		cmp	eax,ecx			; is it upper half?
		jae	RBTreeIndex4		; it is upper half

; ------------- Search node in bottom half of the list

		mov	ecx,eax			; ECX <- required index
		call	RBTreeFirst		; get first node
		jecxz	RBTreeIndex8		; first node required
RBTreeIndex2:	call	RBTreeNext		; get next node
		loop	RBTreeIndex2		; next node
		jmp	short RBTreeIndex8

; ------------- Search node in upper half of the list

RBTreeIndex4:	mov	ecx,[edx+RBR_Count]	; ECX <- number of nodes
		sub	ecx,eax			; ECX <- remaining nodes
		dec	ecx			; ECX <- reverse index
		call	RBTreeLast		; get last node
		jecxz	RBTreeIndex8		; last node required
RBTreeIndex6:	call	RBTreePrev		; get previous node
		loop	RBTreeIndex6		; previous node

; ------------- Pop registers

RBTreeIndex8:	pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;              Get relative indexed node of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EAX = relative index of node (positive or negative)
;		EBX = pointer to current node
; OUTPUT:	EBX = node (NULL = none)
;		CY = node not found (EBX = NULL)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeIndexRel:	push	ecx			; push ECX

; ------------- Check if index is egative or positive

		or	eax,eax			; is index positive?
		mov	ecx,eax			; ECX <- relative index
		jz	RBTreeIndexRel9		; index is 0 (=this node)
		js	RBTreeIndexRel4		; index is negative

; ------------- Index is positive, find next node

RBTreeIndexRel2:call	RBTreeNext		; get next node
		jc	RBTreeIndexRel9		; no next node found
		loop	RBTreeIndexRel2		; next node
		jmp	short RBTreeIndexRel9

; ------------- Index is negative, find previous node

RBTreeIndexRel4:neg	ecx			; ECX <- relative index
RBTreeIndexRel6:call	RBTreePrev		; get previous node
		jc	RBTreeIndexRel9		; no previous node found
		loop	RBTreeIndexRel6		; previous node

; ------------- Pop registers

RBTreeIndexRel9:pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;              Find index of the node of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to node (RBNODE)
;		EDX = pointer to root (RBROOT)
; OUTPUT:	EAX = index of the node (or -1 = node not found)
;		CY = node not found (EAX = -1)
; NOTES: This function can be used as verification that tree contains the node.
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeFindInx:	push	ebx			; push EBX
		push	ecx			; push ECX
		mov	ecx,ebx			; ECX <- node to find

; ------------- Get last node

		mov	eax,[edx+RBR_Count]	; EAX <- number of nodes
		dec	eax			; EAX <- index of last node
		call	RBTreeLast		; get last node
		jc	RBTreeFindInx9		; no last node

; ------------- Search node

RBTreeFindInx2:	cmp	ecx,ebx			; is it searched node?
		je	RBTreeFindInx9		; node found
		dec	eax			; decrease node index
		call	RBTreePrev		; get previous node
		jnc	RBTreeFindInx2		; node found OK

; ------------- Pop registers

RBTreeFindInx9:	pop	ecx			; pop ECX
		pop	ebx			; pop EBX
		ret

; -----------------------------------------------------------------------------
;            Search node in red-black balanced tree with address
; -----------------------------------------------------------------------------
; INPUT:	EAX = address of node to find
;		EDX = pointer to root (RBROOT)
; OUTPUT:	CY = node not found
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeSrcAddr:	push	ebx			; push EBX
		push	ecx			; push ECX

; ------------- Get first node

		mov	ecx,[edx+RBR_Node]	; get first node
		jecxz	RBTreeSrcAddr6		; there is no node in tree

; ------------- Next node is valid

RBTreeSrcAddr2:	mov	ebx,ecx			; node is valid

; ------------- Compare data

		xor	ecx,ecx			; ECX <- 0
		cmp	eax,ebx			; test address
		je	RBTreeSrcAddr8		; node found OK

; ------------- Get next node

		seta	cl			; CL <- 1 (right), 0 (left)
		mov	ecx,[ebx+RBN_Left+ecx*(RBN_Right-RBN_Left)] ; next node
		or	ecx,ecx			; is next node valid?
		jnz	RBTreeSrcAddr2		; next node is valid

; ------------- Error, node not found

RBTreeSrcAddr6:	stc				; flag - node not found

; ------------- Pop registers

RBTreeSrcAddr8:	pop	ecx			; pop ECX
		pop	ebx			; pop EBX
		ret

; -----------------------------------------------------------------------------
;           Search node in red-black balanced tree with WORD data
; -----------------------------------------------------------------------------
; INPUT:	AX = data to find
;		EDX = pointer to root (RBROOT)
; OUTPUT:	CY = node not found (EBX = NULL)
;		EBX = pointer to found node (NULL = node not found)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeSrcW:	push	ecx			; push ECX

; ------------- Get first node

		mov	ecx,[edx+RBR_Node]	; get first node
		jecxz	RBTreeSrcW6		; there is no node in tree

; ------------- Next node is valid

RBTreeSrcW2:	mov	ebx,ecx			; node is valid

; ------------- Compare data

		xor	ecx,ecx			; ECX <- 0
		cmp	ax,[ebx+RB_DataW]	; test data
		je	RBTreeSrcW8		; node found OK

; ------------- Get next node

		seta	cl			; CL <- 1 (right), 0 (left)
		mov	ecx,[ebx+RBN_Left+ecx*(RBN_Right-RBN_Left)] ; next node
		or	ecx,ecx			; is next node valid?
		jnz	RBTreeSrcW2		; next node is valid

; ------------- Error, node not found

RBTreeSrcW6:	xor	ebx,ebx			; EBX <- 0, node not found
		stc				; flag - node not found

; ------------- Pop registers

RBTreeSrcW8:	pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;           Search node in red-black balanced tree with DWORD data
; -----------------------------------------------------------------------------
; INPUT:	EAX = data to find
;		EDX = pointer to root (RBROOT)
; OUTPUT:	CY = node not found (EBX = NULL)
;		EBX = pointer to found node (NULL = node not found)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeSrcDW:	push	ecx			; push ECX

; ------------- Get first node

		mov	ecx,[edx+RBR_Node]	; get first node
		jecxz	RBTreeSrcDW6		; there is no node in the tree

; ------------- Next node is valid

RBTreeSrcDW2:	mov	ebx,ecx			; EBX <- node is valid

; ------------- Compare data

		xor	ecx,ecx			; ECX <- 0
		cmp	eax,[ebx+RBN_Data]	; test data
		je	RBTreeSrcDW8		; node find OK

; ------------- Get next node

		seta	cl			; CL <- 1 (right), 0 (left)
		mov	ecx,[ebx+RBN_Left+ecx*(RBN_Right-RBN_Left)] ; next node
		or	ecx,ecx			; is next node valid?
		jnz	RBTreeSrcDW2		; next node is valid

; ------------- Error, node not found

RBTreeSrcDW6:	xor	ebx,ebx			; EBX <- 0, node not found
		stc				; flag - node not found

; ------------- Pop registers

RBTreeSrcDW8:	pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;     Search node in red-black balanced tree with callback compare function
; -----------------------------------------------------------------------------
; INPUT:	EAX = user data to find (or node with data)
;		EDX = pointer to root (RBROOT)
;		ESI = callback compare function
;			INPUT:	EAX = user data to find (or node with data)
;				EBX = node to test
;			OUTPUT:	ZY = equal, CY = EAX.Data < EBX.Data
;				(as CMP EAX.Data,EBX.Data)
; OUTPUT:	CY = node not found (EBX = NULL)
;		EBX = pointer to found node (NULL = node not found)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeSrcFnc:	push	ecx			; push ECX

; ------------- Get first node

		mov	ecx,[edx+RBR_Node]	; get first node
		jecxz	RBTreeSrcFnc6		; there is no node in the tree

; ------------- Next node is valid

RBTreeSrcFnc2:	mov	ebx,ecx			; EBX <- node is valid

; ------------- Compare data

		xor	ecx,ecx			; ECX <- 0
		call	esi			; test data
		je	RBTreeSrcFnc8		; node find OK

; ------------- Get next node

		seta	cl			; CL <- 1 (right), 0 (left)
		mov	ecx,[ebx+RBN_Left+ecx*(RBN_Right-RBN_Left)] ; next node
		or	ecx,ecx			; is next node valid?
		jnz	RBTreeSrcFnc2		; next node is valid

; ------------- Error, node not found

RBTreeSrcFnc6:	xor	ebx,ebx			; EBX <- 0, node not found
		stc				; flag - node not found

; ------------- Pop registers

RBTreeSrcFnc8:	pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;  Search nearest higher node in red-black tree with callback compare function
; -----------------------------------------------------------------------------
; INPUT:	EAX = user data to find (or node with data)
;		EDX = pointer to root (RBROOT)
;		ESI = callback compare function
;			INPUT:	EAX = user data to find (or node with data)
;				EBX = node to test
;			OUTPUT:	ZY = equal, CY = EAX.Data < EBX.Data
;				(as CMP EAX.Data,EBX.Data)
; OUTPUT:	CY = node not found (EBX = NULL)
;		EBX = pointer to found nearest higher or equal node (NULL=none)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeSrcHigh:	push	ecx			; push ECX
		push	edi			; push EDI

; ------------- Get first node

		xor	edi,edi			; EDI <- 0, no nearest node
		mov	ecx,[edx+RBR_Node]	; get first node
		jecxz	RBTreeSrcHigh6		; there is no node in the tree

; ------------- Next node is valid

RBTreeSrcHigh2:	mov	ebx,ecx			; EBX <- node is valid

; ------------- Compare data

		xor	ecx,ecx			; ECX <- 0
		call	esi			; test data
		je	RBTreeSrcHigh8		; node find OK
		ja	RBTreeSrcHigh4		; data is above node
		mov	edi,ebx			; EDI <- save higher node

; ------------- Get next node

RBTreeSrcHigh4:	seta	cl			; CL <- 1 (right), 0 (left)
		mov	ecx,[ebx+RBN_Left+ecx*(RBN_Right-RBN_Left)] ; next node
		or	ecx,ecx			; is next node valid?
		jnz	RBTreeSrcHigh2		; next node is valid

; ------------- Equal node not found

RBTreeSrcHigh6:	mov	ebx,edi			; EBX <- nearest node
		cmp	ebx,byte 1		; set error flag CY if NULL

; ------------- Pop registers

RBTreeSrcHigh8:	pop	edi			; pop EDI
		pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;  Search nearest lower node in red-black tree with callback compare function
; -----------------------------------------------------------------------------
; INPUT:	EAX = user data to find (or node with data)
;		EDX = pointer to root (RBROOT)
;		ESI = callback compare function
;			INPUT:	EAX = user data to find (or node with data)
;				EBX = node to test
;			OUTPUT:	ZY = equal, CY = EAX.Data < EBX.Data
;				(as CMP EAX.Data,EBX.Data)
; OUTPUT:	CY = node not found (EBX = NULL)
;		EBX = pointer to found nearest lower or equal node (NULL=none)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeSrcLow:	push	ecx			; push ECX
		push	edi			; push EDI

; ------------- Get first node

		xor	edi,edi			; EDI <- 0, no nearest node
		mov	ecx,[edx+RBR_Node]	; get first node
		jecxz	RBTreeSrcLow6		; there is no node in the tree

; ------------- Next node is valid

RBTreeSrcLow2:	mov	ebx,ecx			; EBX <- node is valid

; ------------- Compare data

		xor	ecx,ecx			; ECX <- 0
		call	esi			; test data
		je	RBTreeSrcLow8		; node find OK
		jb	RBTreeSrcLow4		; data is below node
		mov	edi,ebx			; EDI <- save lower node

; ------------- Get next node

RBTreeSrcLow4:	seta	cl			; CL <- 1 (right), 0 (left)
		mov	ecx,[ebx+RBN_Left+ecx*(RBN_Right-RBN_Left)] ; next node
		or	ecx,ecx			; is next node valid?
		jnz	RBTreeSrcLow2		; next node is valid

; ------------- Equal node not found

RBTreeSrcLow6:	mov	ebx,edi			; EBX <- nearest node
		cmp	ebx,byte 1		; set error flag CY if NULL

; ------------- Pop registers

RBTreeSrcLow8:	pop	edi			; pop EDI
		pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;                    Rotate red-black balanced tree left
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to current node (RBNODE)
;		EDX = pointer to root (RBROOT)
; NOTES:	Right node must be valid.
; -----------------------------------------------------------------------------
;                  ri-le   ri-ri             left   ri-le
;                      \   /                    \   /
;               left   right                     node   ri-ri
;                  \   /           --->             \   /
;             ...   node                      ...   right
;               \   /                           \   /
;               parent                          parent
; -----------------------------------------------------------------------------
; Local variables:
%define		RBRi	EAX			; right node
%define		RBNo	EBX			; current node
%define		RBRL	ECX			; right-left node (hardcoded)
%define		RBRLL	CL			; right-left node LOW (temp.)
%define		RBRo	EDX			; root
%define		RBPa	ESI			; parent

; ------------- Push registers

RBTreeLeft:	push	RBRi			; push RBRi
		push	RBRL			; push RBRL
		push	RBPa			; push RBPa

; ------------- Get other nodes

		mov	RBRi,[RBNo+RBN_Right]	; get right node
		mov	RBRL,[RBRi+RBN_Left]	; get right-left node
		mov	RBPa,[RBNo+RBN_Parent]	; get parent

; ------------- Link right-left node as new right node of current node

		mov	[RBNo+RBN_Right],RBRL	; set as new right node
		jecxz	RBTreeLeft2		; no right-left node
		mov	[RBRL+RBN_Parent],RBNo	; current node is its parent

; ------------- Link current node as new left node of right node

RBTreeLeft2:	mov	[RBRi+RBN_Left],RBNo	; node is left for right one
		mov	[RBNo+RBN_Parent],RBRi	; new parent for current node
		
; ------------- Link right node to root

		mov	[RBRi+RBN_Parent],RBPa	; new parent for right node
		or	RBPa,RBPa		; is parent a root?
		jnz	RBTreeLeft4		; parent is not a root
		mov	[RBRo+RBR_Node],RBRi	; link right node to root
		jmp	short RBTreeLeft8

; ------------- Link right node to valid parent

RBTreeLeft4:    xor	RBRL,RBRL		; RBRL <- 0
		cmp	RBNo,[RBPa+RBN_Right]	; was it right or left node?
		sete	RBRLL			; RBRLL <- 1 (right), 0 (left)
		mov	[RBPa+RBN_Left+RBRL*(RBN_Right-RBN_Left)],RBRi

; ------------- Pop registers

RBTreeLeft8:	pop	RBPa			; pop RBPa
		pop	RBRL			; pop RBRL
		pop	RBRi			; pop RBRi
		ret

%undef		RBRi				; right node
%undef		RBNo				; current node
%undef		RBRL				; right-left node (hardcoded)
%undef		RBRLL				; right-left node LOW (temp.)
%undef		RBRo				; root
%undef		RBPa				; parent

; -----------------------------------------------------------------------------
;                    Rotate red-black balanced tree right
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to current node (RBNODE)
;		EDX = pointer to root (RBROOT)
; NOTES:	Left node must be valid.
; -----------------------------------------------------------------------------
;           le-le   le-ri                        le-ri   right
;               \   /                                \   /
;               left   right                  le-le   node
;                  \   /           --->           \   /
;             ...   node                    ...   left
;               \   /                         \   /
;               parent                        parent
; -----------------------------------------------------------------------------
; Local variables:
%define		RBLe	EAX			; left node
%define		RBNo	EBX			; current node
%define		RBLR	ECX			; left-right node (hardcoded)
%define		RBLRL	CL			; left-right node LOW (temp.)
%define		RBRo	EDX			; root
%define		RBPa	ESI			; parent

; ------------- Push registers

RBTreeRight:	push	RBLe			; push RBLe
		push	RBLR			; push RBLR
		push	RBPa			; push RBPa

; ------------- Get other nodes

		mov	RBLe,[RBNo+RBN_Left]	; get left node
		mov	RBLR,[RBLe+RBN_Right]	; get left-right node
		mov	RBPa,[RBNo+RBN_Parent]	; get parent

; ------------- Link left-right node as new left node of current node

		mov	[RBNo+RBN_Left],RBLR	; set as new left node
		jecxz	RBTreeRight2		; no left-right node
		mov	[RBLR+RBN_Parent],RBNo	; current node is its parent

; ------------- Link current node as new right node of left node

RBTreeRight2:	mov	[RBLe+RBN_Right],RBNo	; node is right for left one
		mov	[RBNo+RBN_Parent],RBLe	; new parent for current node
		
; ------------- Link left node to root

		mov	[RBLe+RBN_Parent],RBPa	; new parent for left node
		or	RBPa,RBPa		; is parent a root?
		jnz	RBTreeRight4		; parent is not a root
		mov	[RBRo+RBR_Node],RBLe	; link left node to root
		jmp	short RBTreeRight8

; ------------- Link left node to valid parent

RBTreeRight4:	xor	RBLR,RBLR		; RBLR <- 0
		cmp	RBNo,[RBPa+RBN_Right]	; was it right or left node?
		sete	RBLRL			; RBRLL <- 1 (right), 0 (left)
		mov	[RBPa+RBN_Left+RBLR*(RBN_Right-RBN_Left)],RBLe

; ------------- Pop registers

RBTreeRight8:	pop	RBPa			; pop RBPa
		pop	RBLR			; pop RBLR
		pop	RBLe			; pop RBLe
		ret

%undef		RBLe				; right node
%undef		RBNo				; current node
%undef		RBLR				; right-left node (hardcoded)
%undef		RBLRL				; right-left node LOW (temp.)
%undef		RBRo				; root
%undef		RBPa				; parent

; -----------------------------------------------------------------------------
;                   Replace node of red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to new node (RBN)
;		EBX = pointer to old node (RBN)
;		EDX = pointer to root (RBR)
; -----------------------------------------------------------------------------
; Local variables:
%define		RBNew	EAX			; new node
%define		RBOld	EBX			; old node
%define		RBTm	ECX			; temporary (hardcoded)
%define		RBTmL	CL			; temporary LOW
%define		RBRo	EDX			; root

; ------------- Push registers

RBTreeReplace:	push	RBTm			; push RBTm

; ------------- Relink entries in the list

		mov	RBTm,[RBOld+LIST_Prev]	; RBTm <- previous entry
		call	ListDelEBX		; delete entry from the list
		push	ebx			; push EBX
		mov	ebx,RBTm		; EBX <- previous entry
		call	ListAfter		; link entry after previous one
		pop	ebx			; pop EBX

; ------------- Copy color

		mov	RBTmL,[RBOld+RB_Color]	; get color from old node
		mov	[RBNew+RB_Color],RBTmL	; set color to new node

; ------------- Check if parent is ROOT

		mov	RBTm,[RBOld+RBN_Parent]	; get parent of old node
		jecxz	RBTreeReplace3		; parent is root

; ------------- Link to parent

		cmp	RBOld,[RBTm+RBN_Left]	; is it left node?
		jne	RBTreeReplace2		; it is not left node
		mov	[RBTm+RBN_Left],RBNew	; link as left node
		jmp	short RBTreeReplace4
RBTreeReplace2:	mov	[RBTm+RBN_Right],RBNew	; link as right node
		jmp	short RBTreeReplace4

; ------------- Link to parent in root

RBTreeReplace3:	mov	[RBRo+RBR_Node],RBNew	; link from root
RBTreeReplace4:	mov	[RBNew+RBN_Parent],RBTm	; link to parent from new node

; ------------- Link to left child

		mov	RBTm,[RBOld+RBN_Left]	; get left child
		jecxz	RBTreeReplace6		; left child is not valid
		mov	[RBTm+RBN_Parent],RBNew	; link from left child
RBTreeReplace6:	mov	[RBNew+RBN_Left],RBTm	; link to left child

; ------------- Link to right child

		mov	RBTm,[RBOld+RBN_Right]	; get right child
		jecxz	RBTreeReplace8		; right child is not valid
		mov	[RBTm+RBN_Parent],RBNew	; link from right child
RBTreeReplace8:	mov	[RBNew+RBN_Right],RBTm	; link to right child

; ------------- Pop registers

		pop	RBTm			; pop RBTm
		ret

%undef		RBNew				; new node
%undef		RBOld				; old node
%undef		RBTm				; temporary (hardcoded)
%undef		RBTmL				; temporary LOW
%undef		RBRo				; root

; -----------------------------------------------------------------------------
;                Insert red color into red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to current node (RBNODE)
;		EDX = pointer to root (RBROOT)
; NOTES:	Entry point is RBTreeInsCol.
; -----------------------------------------------------------------------------
; Local variables:
%define		RBGr	EAX			; grand parent
%define		RBNo	EBX			; current node
%define		RBUn	ECX			; uncle
%define		RBRo	EDX			; root
%define		RBPa	ESI			; parent

; ============= Macros

; ------------- Macro - insert color in one direction
; Parameters (direction word): %1 = Left (Right), %2 = Right (Left)

%macro		RBTreeInsC 2

; ------------- Get uncle as grand parent's right (left) node

		mov	RBUn,[RBGr+RBN_%2]	; get uncle
		or	RBUn,RBUn		; is uncle valid?
		jz	short %%L2		; uncle is invalid

; ------------- Check if uncle is red

		CMPRED	RBUn			; is uncle red?
		jne	short %%L2		; uncle is not red
		
; ------------- Uncle is red, set uncle and parent black, set grandpa red

		SETBLK	RBUn			; set uncle black
		SETBLK	RBPa			; set parent black
		SETRED	RBGr			; set grandpa red
		mov	RBNo,RBGr		; node <- grand parent
		jmp	short RBTreeInsCol2	; next node

; ------------- Uncle is black, check if node is right (left) node of parent 

%%L2:		cmp	RBNo,[RBPa+RBN_%2]	; is node right (left) node?
		jne	short %%L4		; node is not right (left) node

; ------------- Rotate left (right) to become node as new parent node

		push	RBNo			; push RBNo
		mov	RBNo,RBPa		; parent will be used
		call	RBTree%1		; rotate parent left (right)
		pop	RBPa			; parent <- node

; ------------- Set parent black, set grandpa red and rotate it right (left)

%%L4:		SETBLK	RBPa			; set parent black
		SETRED	RBGr			; set grandpa red
		push	RBNo			; push RBNo
		mov	RBNo,RBGr		; grandpa will be used
		call	RBTree%2		; rotate grandpa right (left)
		pop	RBNo			; pop RBNo
%endmacro

; ============= RBTreeInsCol function

; ------------- Push registers

RBTreeInsCol:	push	RBGr			; push RBGr
		push	RBNo			; push RBNo
		push	RBUn			; push RBUn
		push	RBPa			; push RBPa

; ------------- Get parent

RBTreeInsCol2:	mov	RBPa,[RBNo+RBN_Parent]	; get parent
		or	RBPa,RBPa		; is parent valid?
		jz	near RBTreeInsCol8	; no other parent

; ------------- Check if parent is red

		CMPRED	RBPa			; parent is red?
		jne	near RBTreeInsCol8	; parent is not red

; ------------- Get grand parent and check if parent is left of grand parent
; Parent is red and therefore grandpa is always valid (because root is black)

		mov	RBGr,[RBPa+RBN_Parent]	; get grand parent
		cmp	RBPa,[RBGr+RBN_Left]	; is parent left of grandpa?
		jne	short RBTreeInsCol4	; no, it is right of grandpa

; ------------- Parent is left of grand parent

		RBTreeInsC Left, Right		; insert color for left
RBTreeInsCol3:	jmp	short RBTreeInsCol2	; next node

; ------------- Parent is right of grand parent

RBTreeInsCol4:	RBTreeInsC Right, Left		; insert color for right
		jmp	short RBTreeInsCol3	; next node

; ------------- Set root node black

RBTreeInsCol8:	mov	RBNo,[RBRo+RBR_Node]	; get root node
		SETBLK	RBNo			; set root node black

; ------------- Pop registers

		pop	RBPa			; pop RBPa
		pop	RBUn			; pop RBUn
		pop	RBNo			; pop RBNo
		pop	RBGr			; pop RBGr
		ret

%undef		RBGr				; grand parent
%undef		RBNo				; current node
%undef		RBUn				; uncle
%undef		RBRo				; root
%undef		RBPa				; parent

; -----------------------------------------------------------------------------
;                 Insert new entry into red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to new entry (RBNODE with filled user data)
;		EDX = pointer to root (RBROOT)
;		ESI = callback compare function
;			INPUT:	EAX = pointer to new entry (with user data)
;				EBX = node to test
;			OUTPUT:	ZY = equal, CY = EAX.Data < EBX.Data
;				(as CMP EAX.Data,EBX.Data)
; OUTPUT:	CY = entry already exists (EBX = pointer to existing node)
;		EBX = pointer to existing entry (if CY) or new entry (=EAX)
; -----------------------------------------------------------------------------

; ------------- Push registers

RBTreeInsert:	push	ecx			; push ECX

; ------------- Initialize new node

		xor	ecx,ecx			; ECX <- 0
		mov	[eax+RB_ColorFlags],cx	; set color to red, clear flags
		mov	[eax+RBN_Left],ecx	; no left node
		mov	[eax+RBN_Right],ecx	; no right node

; ------------- Get first node

		mov	ecx,[edx+RBR_Node]	; ECX <- get first node
		or	ecx,ecx			; is any node in the tree?
		jnz	RBTreeInsert2		; tree is not empty

; ------------- Store node into root

		mov	ebx,edx			; EBX <- root
		call	ListAdd			; add entry into list
		mov	[edx+RBR_Node],eax	; link root to this node
		mov	[eax+RBN_Parent],ecx	; set parent to NULL
		inc	byte [eax+RB_Color]	; set color to black for root
		mov	ebx,eax			; EBX <- new node
		jmp	short RBTreeInsert8

; ------------- Next node is valid

RBTreeInsert2:	mov	ebx,ecx			; EBX <- node is valid

; ------------- Compare data

		call	esi			; test data
		jb	RBTreeInsert3		; data is lower
		stc				; set error flag
		je	RBTreeInsert9		; node already exists

; ------------- Higher data, use right branch

		mov	ecx,[ebx+RBN_Right]	; ECX <- right node
		or	ecx,ecx			; is right node valid?
		jnz	RBTreeInsert2		; right node is valid

; ------------- Insert new node to the right

		mov	[ebx+RBN_Right],eax	; insert node to the right
		call	ListAfter		; add entry into list
		jmp	short RBTreeInsert4

; ------------- Lower data, use left branch

RBTreeInsert3:	mov	ecx,[ebx+RBN_Left]	; ECX <- left node
		or	ecx,ecx			; is left node valid?
		jnz	RBTreeInsert2		; left node is valid

; ------------- Insert new node to the left

		mov	[ebx+RBN_Left],eax	; insert node to the left
		call	ListBefore		; add entry into list
RBTreeInsert4:	mov	[eax+RBN_Parent],ebx	; set node as parent of new one

; ------------- Insert red color into tree

		mov	ebx,eax			; EBX <- new node
		call	RBTreeInsCol		; insert color

; ------------- Increate number of entries

RBTreeInsert8:	inc	dword [edx+RBR_Count]	; increase number of entries

; ------------- Pop registers

		clc				; clear error flag
RBTreeInsert9:	pop	ecx			; pop ECX
		ret

; -----------------------------------------------------------------------------
;         Insert new entry into red-black balanced tree with address
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to new entry (RBNODE)
;		EDX = pointer to root (RBROOT)
; OUTPUT:	CY = entry already exists (EBX = pointer to existing node)
;		EBX = pointer to existing entry (if CY) or new entry (=EAX)
; NOTES:	Entry point is RBTreeInsertW.
; -----------------------------------------------------------------------------

RBTreeInsAddr:	push	esi			; push ESI
		mov	esi,RBTreeInsAddr4	; ESI <- callback function
		call	RBTreeInsert		; insert new entry
		pop	esi			; pop ESI
		ret

; ------------- Callback compare function for address

RBTreeInsAddr4:	cmp	eax,ebx			; compare nodes
		ret

; -----------------------------------------------------------------------------
;         Insert new entry into red-black balanced tree with WORD data
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to new entry (RBNODE with filled WORD user data)
;		EDX = pointer to root (RBROOT)
; OUTPUT:	CY = entry already exists (EBX = pointer to existing node)
;		EBX = pointer to existing entry (if CY) or new entry (=EAX)
; NOTES:	Entry point is RBTreeInsertW.
; -----------------------------------------------------------------------------

RBTreeInsertW:	push	esi			; push ESI
		mov	esi,RBTreeInsertW4	; ESI <- callback function
		call	RBTreeInsert		; insert new entry
		pop	esi			; pop ESI
		ret

; ------------- Callback compare function for WORD data

RBTreeInsertW4:	push	eax			; push EAX
		mov	ax,[eax+RB_DataW]	; AX <- user data
		cmp	ax,[ebx+RB_DataW]	; test data
		pop	eax			; pop EAX
		ret

; -----------------------------------------------------------------------------
;         Insert new entry into red-black balanced tree with DWORD data
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to new entry (RBNODE with filled DWORD user data)
;		EDX = pointer to root (RBROOT)
; OUTPUT:	CY = entry already exists (EBX = pointer to existing node)
;		EBX = pointer to existing entry (if CY) or new entry (=EAX)
; NOTES:	Entry point is RBTreeInsertDW.
; -----------------------------------------------------------------------------

RBTreeInsertDW:	push	esi			; push ESI
		mov	esi,RBTreeInsertDW4	; ESI <- callback function
		call	RBTreeInsert		; insert new entry
		pop	esi			; pop ESI
		ret

; ------------- Callback compare function for DWORD data

RBTreeInsertDW4:push	eax			; push EAX
		mov	eax,[eax+RBN_Data]	; EAX <- user data
		cmp	eax,[ebx+RBN_Data]	; test data
		pop	eax			; pop EAX
		ret

; -----------------------------------------------------------------------------
;              Delete color of node from red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to parent of node (RBNODE, NULL=root)
;		EBX = pointer to deleted node (RBNODE, node must be unlinked)
;		EDX = pointer to root (RBROOT)
; NOTES:	Entry point is RBTreeDelCol.
; -----------------------------------------------------------------------------
; Local variables:
%define		RBPa	EAX			; parent
%define		RBNo	EBX			; deleted node
%define		RBNe	ECX			; nephew (hardcoded)
%define		RBNeL	CL			; nephew LOW (temporary reg.)
%define		RBRo	EDX			; root
%define		RBBr	ESI			; brother

; ============= Macros

; ------------- Macro - check if left (right) nephew is black
; Parameters: %1 = Left (Right), %2 = jump label if nephew is not black

%macro		TESTNE	2

		mov	RBNe,[RBBr+RBN_%1]	; get nephew
		jecxz	%%black			; nephew is not valid
		CMPBLK	RBNe			; is nephew black?
		jne	%2			; nephew is not black
%%black:

%endmacro

; ------------- Macro - delete color in one direction
; Parameters (direction word): %1 = Left (Right), %2 = Right (Left)

%macro		RBTreeDelC 2

; ------------- Get brother node from right (left) and check if it is red
; Node is black or invalid and therefore its brother is always valid

		mov	RBBr,[RBPa+RBN_%2]	; get brother node
		CMPRED	RBBr			; is brother node red?
		jne	short %%L2		; brother node is not red

; ------------- Set brother node black, set parent red a rotate it left (right)

		SETBLK	RBBr			; set brother node black
		SETRED	RBPa			; set parent node red
		push	RBNo			; push RBNo
		mov	RBNo,RBPa		; parent node will be used
		call	RBTree%1		; rotate parent left (right)
		pop	RBNo			; pop RBNo
		mov	RBBr,[RBPa+RBN_%2]	; get new brother node

; ------------- Check if left (right) nephew is black

%%L2:		TESTNE	%1, %%L4		; check left (right) nephew

; ------------- Check if right (left) nephew is black

		TESTNE	%2, %%L4		; check right (left) nephew

; ------------- Set brother to red

		SETRED	RBBr			; set brother to red
		mov	RBNo,RBPa		; node <- parent
		mov	RBPa,[RBNo+RBN_Parent]	; get new parent
		jmp	RBTreeDelCol2		; next node
		
; ------------- Check if right (left) nephew is black

%%L4:		TESTNE	%2, %%L6		; check right (left) nephew

; ------------- Set left (right) nephew to black

		mov	RBNe,[RBBr+RBN_%1]	; get left (right) nephew
		jecxz	%%L5			; nephew is not valid
		SETBLK	RBNe			; set nephew black

; ------------- Set brother red and rotate it right (left)

%%L5:		SETRED	RBBr			; set brother red
		push	RBNo			; push RBNo
		mov	RBNo,RBBr		; node <- brother
		call	RBTree%2		; rotate brother right (left)
		pop	RBNo			; pop RBNo
		mov	RBBr,[RBPa+RBN_%2]	; get new brother node

; ------------- Copy parent's color to brother

%%L6:		mov	RBNeL,[RBPa+RB_Color]	; get parent's color
		mov	[RBBr+RB_Color],RBNeL	; set brother's color
		SETBLK	RBPa			; set parent black

; ------------- Set right (left) nephew to black

		mov	RBNe,[RBBr+RBN_%2]	; get right (left) nephew
		jecxz	%%L8			; nephew is not valid
		SETBLK	RBNe			; set nephew black

; ------------- Rotate parent left (right)

%%L8:		mov	RBNo,RBPa		; parent will be used
		call	RBTree%1		; rotate parent left (right)
		mov	RBNo,[RBRo+RBR_Node]	; get root node
%endmacro

; ============= RBTreeDelCol function

; ------------- Push registers

RBTreeDelCol:	push	RBPa			; push RBPa
		push	RBNo			; push RBNo
		push	RBNe			; push RBNe
		push	RBBr			; push RBBr

; ------------- Node must be black or invalid

RBTreeDelCol2:	or	RBNo,RBNo		; is node valid?
		jz	short RBTreeDelCol3	; node is not valid
		CMPBLK	RBNo			; is node black?
		jne	near RBTreeDelCol4	; node is not black

; ------------- Node must not be a root node

RBTreeDelCol3:	cmp	RBNo,[RBRo+RBR_Node]	; is it root node?
		je	near RBTreeDelCol4	; it is root node

; ------------- Check if current node is left node of parent

		cmp	RBNo,[RBPa+RBN_Left]	; is current node left node?
		jne	near RBTreeDelCol5	; it is not left node

; ------------- Node is left node

		RBTreeDelC Left, Right		; delete color for left
RBTreeDelCol4:	jmp	RBTreeDelCol6		; quit

; ------------- Node is right node

RBTreeDelCol5:	RBTreeDelC Right, Left		; delete color for right

; ------------- Set node to black

RBTreeDelCol6:	or	RBNo,RBNo		; is node valid?
		jz	short RBTreeDelCol8	; node is invalid
		SETBLK	RBNo			; set node to black

; ------------- Pop registers

RBTreeDelCol8:	pop	RBBr			; pop RBBr
		pop	RBNe			; pop RBNe
		pop	RBNo			; pop RBNo
		pop	RBPa			; pop RBPa
		ret

%undef		RBPa				; parent
%undef		RBNo				; deleted node
%undef		RBNe				; nephew
%undef		RBNeL				; nephew LOW (temporary reg.)
%undef		RBRo				; root
%undef		RBBr				; brother

; -----------------------------------------------------------------------------
;                  Delete node from red-black balanced tree
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to deleted node (RBNODE)
;		EDX = pointer to root (RBROOT)
; NOTES:	RBNODE memory block is not destroyed.
; -----------------------------------------------------------------------------
; Local variables:
%define		RBPa	EAX			; parent
%define		RBPaL	AL			; parent LOW
%define		RBNo	EBX			; current node
%define		RBCo	ECX			; color
%define		RBCoL	CL			; color LOW
%define		RBRo	EDX			; root
%define		RBOl	ESI			; old node
%define		RBCh	EDI			; child

; ------------- Push registers

RBTreeDelete:	push	RBPa			; push RBPa
		push	RBNo			; push RBNo
		push	RBCo			; push RBCo
		push	RBOl			; push RBOl
		push	RBCh			; push RBCh

; ------------- Decrease number of entries

		dec	dword [RBRo+RBR_Count]	; decrease number of entries

; ------------- Detach entry from the list

		call	ListDelEBX		; delete node

; ------------- Get child node from right node if left node is not valid

		mov	RBCh,[RBNo+RBN_Right]	; RBCh <- get right node
		mov	RBOl,[RBNo+RBN_Left]	; RBOl <- get left node
		or	RBOl,RBOl		; ir left node valid?
		jz	RBTreeDelete6		; left node is not valid

; ------------- Get child node from left node if right node is not valid

		xchg	RBOl,RBCh		; child <- left, old <- right
		or	RBOl,RBOl		; is right node valid?
		jz	RBTreeDelete6		; right node is not valid

; ------------- Find leftmost node of right node

		mov	RBCh,RBOl		; child <- save right node
		mov	RBOl,RBNo		; old <- save current node
RBTreeDelete1:	mov	RBNo,RBCh		; node <- right/left
		mov	RBCh,[RBNo+RBN_Left]	; child <- get left node
		or	RBCh,RBCh		; is left node valid?
		jnz	RBTreeDelete1		; next left node

; ------------- Get right child, parent and color of the node

		mov	RBCh,[RBNo+RBN_Right]	; child <- get right node
		mov	RBPa,[RBNo+RBN_Parent]	; parent <- get parent
		mov	RBCoL,[RBNo+RB_Color]	; color <- get color

; ------------- Link parent to right child

		or	RBCh,RBCh		; is child valid?	
		jz	RBTreeDelete2		; child is not valid
		mov	[RBCh+RBN_Parent],RBPa	; child <- set new parent

; ------------- If parent is old (deleted) node link it as its right node

RBTreeDelete2:	cmp	RBOl,RBPa		; is parent equal to old node?
		jne	RBTreeDelete3		; parent is not old node
		mov	[RBPa+RBN_Right],RBCh	; set child as right of parent
		mov	RBPa,RBNo		; parent <- node
		jmp	short RBTreeDelete4
RBTreeDelete3:	mov	[RBPa+RBN_Left],RBCh	; set child as left of parent

; ------------- Copy color, right and left node from old node to current one

RBTreeDelete4:	push	RBPa			; push RBPa (old parent)
		mov	RBPaL,[RBOl+RB_Color]	; color
		mov	[RBNo+RB_Color],RBPaL
		mov	RBPa,[RBOl+RBN_Left]	; left node
		mov	[RBNo+RBN_Left],RBPa
		mov	RBPa,[RBOl+RBN_Right]	; right node
		mov	[RBNo+RBN_Right],RBPa
		mov	RBPa,[RBOl+RBN_Parent]	; parent
		mov	[RBNo+RBN_Parent],RBPa

; ------------- Link current node to parent

		or	RBPa,RBPa		; is parent valid?
		jz	RBTreeDelete56		; parent is not valid
		cmp	[RBPa+RBN_Left],RBOl	; old node=left node of parent?
		jne	RBTreeDelete52		; no
		mov	[RBPa+RBN_Left],RBNo	; node -> left node of parent
		jmp	short RBTreeDelete58
RBTreeDelete52:	mov	[RBPa+RBN_Right],RBNo	; node -> right node of parent
		jmp	short RBTreeDelete58
RBTreeDelete56:	mov	[RBRo+RBR_Node],RBNo	; node -> root node

; ------------- Link current node as parent of old left node

RBTreeDelete58:	mov	RBPa,[RBOl+RBN_Left]	; RBPa <- get old left node
		mov	[RBPa+RBN_Parent],RBNo	; node -> parent of left node

; ------------- Link current node as parent of old right node

		mov	RBPa,[RBOl+RBN_Right]	; RBPa <- get old right node
		or	RBPa,RBPa		; is old right node valid?
		jz	RBTreeDelete59		; old right node is not valid
		mov	[RBPa+RBN_Parent],RBNo	; node -> parent of right node
RBTreeDelete59:	pop	RBPa			; pop RBPa (old parent)
		jmp	short RBTreeDelete7	; delete color

; ------------- Get parent and color of current node

RBTreeDelete6:	mov	RBPa,[RBNo+RBN_Parent]	; RBPa <- get current parent
		mov	RBCoL,[RBNo+RB_Color]	; RBCoL <- get current color

; ------------- Link parent as new parent of the child

		or	RBCh,RBCh		; is child valid?
		jz	RBTreeDelete62		; child is not valid
		mov	[RBCh+RBN_Parent],RBPa	; parent -> parent of the child

; ------------- Link child to the parent

RBTreeDelete62:	or	RBPa,RBPa		; is parent valid?
		jz	RBTreeDelete66		; parent is not valid
		cmp	RBNo,[RBPa+RBN_Left]	; is current node left child?
		jne	RBTreeDelete64		; is it not left child
		mov	[RBPa+RBN_Left],RBCh	; link child as left child
		jmp	short RBTreeDelete7
RBTreeDelete64:	mov	[RBPa+RBN_Right],RBCh	; link child as right child
		jmp	short RBTreeDelete7
RBTreeDelete66:	mov	[RBRo+RBR_Node],RBCh	; child -> root node

; ------------- Delete color

RBTreeDelete7:	cmp	RBCoL,RB_BLACK		; is it black color?
		jne	RBTreeDelete8		; it is not black color
		mov	ebx,RBCh		; EBX <- child node
		call	RBTreeDelCol		; delete color

; ------------- Pop registers

RBTreeDelete8:	pop	RBCh			; pop RBCh
		pop	RBOl			; pop RBOl
		pop	RBCo			; pop RBCo
		pop	RBNo			; pop RBNo
		pop	RBPa			; pop RBPa
		ret

; -----------------------------------------------------------------------------
;                          Debug test red-black tree
; -----------------------------------------------------------------------------

%ifdef DEBUG_RBTREE

TestRBTree:	call	DebOutClear
		mov	esi,TestTreeText1
		call	DebOutText

; ------------- Create random nodes

		mov	ecx,1000
		mov	edx,TestTree
TestRBTree1:	call	RandByte
		test	al,7
		jnz	TestRBTree2

; ------------- Delete one random node

		mov	eax,[TestTree+RBR_Count]
		dec	eax
		call	RandMaxDWord
		call	RBTreeIndex
		jc	TestRBTree1
		call	RBTreeDelete
		xchg	eax,ebx
		call	SysMemFree
		jmp	short TestRBTree1

; ------------- Create one random node

TestRBTree2:	mov	eax,RBNODE_size+4
		call	SysMemAlloc
		push	eax
		call	RandDWord
		xchg	eax,esi
		pop	eax
		mov	[eax+RBN_Data],esi
		call	RBTreeInsertDW
		loop	TestRBTree1

; ------------- Limit number of nodes

TestRBTree3:	mov	eax,[TestTree+RBR_Count]
		cmp	eax,byte 100
		jbe	TestRBTree4
		dec	eax
		call	RandMaxDWord
		call	RBTreeIndex
		call	RBTreeDelete
		xchg	eax,ebx
		call	SysMemFree
		jmp	short TestRBTree3

; ------------- Display nodes

TestRBTree4:	call	RBTreeFirst
		jc	TestRBTree7
TestRBTree5:	mov	eax,[ebx+RBN_Data]
		call	DebOutNum
		add	byte [VideoPos],15
		and	byte [VideoPos],~0fh
		cmp	byte [VideoPos],70
		jb	TestRBTree6
		call	DebNewLine
TestRBTree6:   	call	RBTreeNext
		jnc	TestRBTree5

TestRBTree7:	jmp	$

; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

TestTree:	RBTREE			; test tree

TestTreeText1:	db	'Test Red-Black Tree...',10,0

%endif ; DEBUG_RBTREE

Back to source browser