flat assembler
Message board for the users of flat assembler.
Index
> Tutorials and Examples > rather simple example of red-black trees |
Author |
|
typedef 07 Feb 2014, 18:29
So you want to also provide a 32-bit version?
|
|||
07 Feb 2014, 18:29 |
|
tthsqe 07 Feb 2014, 19:10
32 bit version
Code: format PE GUI 4.0 entry Start include 'win32axp.inc' TT_MAX_ENTRIES fix 1024 IDI_MAIN = 17 ID_DLGMAIN = 37 ID_EXPRESSION = 39 ID_RESULT = 200 struct NODE ; 32 bytes in size LEFT dd ? ; left child RIGHT dd ? ; right child UP dd ? ; parent COL db ? ; 0 for black, 1 for red \ db ?,?,? ; unused NUM dd ? ; number dd ?,?,? ends LG_NODE_SIZE fix 5 ; log2(sizeof.NODE) section '.text' code readable executable Start: invoke InitCommonControls invoke GetModuleHandle,NULL invoke DialogBoxParam,eax,ID_DLGMAIN,NULL,DlgProc,NULL invoke ExitProcess,0 proc DlgProc,.hDlg,.uMsg,.wParam,.lParam mov eax,dword[.uMsg] cmp eax,WM_COMMAND je .wmcommand cmp eax,WM_CLOSE je .wmclose cmp eax,WM_INITDIALOG je .wminitdialog .default: xor eax, eax ret .wmcommand: movzx edx,word[.wParam+2] movzx eax,word[.wParam] cmp eax,ID_EXPRESSION jne .default cmp edx, EN_CHANGE jne .default .edit_changed: invoke SendDlgItemMessage,[.hDlg],ID_EXPRESSION,WM_GETTEXT,1023,InputString push esi edi call TT_Clear lea esi,[InputString] .read_next: call SkipSpaces cmp byte[esi],0 je .read_done call ParseInteger mov ecx,eax call TT_FindNode jmp .read_next .read_done: lea edi,[ResultString] call TT_InOrderTraverse xor eax,eax stosb pop edi esi invoke SetDlgItemText,[.hDlg],ID_RESULT,ResultString jmp .default .wmclose: invoke EndDialog,[.hDlg],0 jmp .default .wminitdialog: invoke SendDlgItemMessage,[.hDlg],ID_EXPRESSION,EM_LIMITTEXT,1022,0 .processed: mov eax,1 .return: ret endp ; return in eax address of node that corresponds to number in ecx ; if ecx is not in table, then a new node is made ; if table is full, then TTNull is returned ; NOTE: insertion code is stolen from wikipedia align 16 TT_FindNode: mov edx,dword[TTEntries] test edx,edx jnz .OldTree .NewTree: lea eax,[TT] add edx,1 mov dword[TTEntries],edx mov dword[eax+NODE.UP],TTHead mov dword[eax+NODE.LEFT],TTNull mov dword[eax+NODE.RIGHT],TTNull mov dword[eax+NODE.COL],0 mov dword[eax+NODE.NUM],ecx mov dword[TTHead+NODE.LEFT],eax ret align 16 .TreeFull: lea eax,[TTNull] .Ret: pop ebx esi edi ebp ret ; this can be called to skip the previous branch if it is known that the tree is not empty align 16 .OldTree: push ebp edi esi ebx mov ebx,dword[TTHead+NODE.LEFT] mov edx,dword[TTEntries] lea ebp,[edx+1] shl edx,LG_NODE_SIZE lea edx,[edx+TT] .Compare: mov esi,dword[ebx+NODE.LEFT] mov edi,dword[ebx+NODE.RIGHT] mov eax,dword[ebx+NODE.NUM] cmp eax,ecx jg .GoLeft jl .GoRight .Found: mov eax,ebx jmp .Ret .GoLeft: cmp esi,TTNull je .MakeNewLeft mov ebx,esi jmp .Compare .GoRight: cmp edi,TTNull je .MakeNewRight mov ebx,edi jmp .Compare .MakeNewLeft: cmp ebp,TT_MAX_ENTRIES ja .TreeFull mov dword[ebx+NODE.LEFT],edx jmp .FixTree .MakeNewRight: cmp ebp,TT_MAX_ENTRIES ja .TreeFull mov dword[ebx+NODE.RIGHT],edx .FixTree: mov dword[TTEntries],ebp mov dword[edx+NODE.UP],ebx mov dword[edx+NODE.LEFT],TTNull mov dword[edx+NODE.RIGHT],TTNull mov dword[edx+NODE.COL],1 ; set color to red mov dword[edx+NODE.NUM],ecx mov eax,edx ; this is the node to return .FixNode: ; node is in rdx ; Case 1: The current node N is at the root of the tree. In this case, it is repainted black to satisfy property 2 (the root is black). Since this adds one black node to every path at once, property 5 (all paths from any given node to its leaf nodes contain the same number of black nodes) is not violated. .Case1: mov esi,dword[edx+NODE.UP] cmp esi,TTHead jne .Case2 mov byte[edx+NODE.COL],0 ; set as black jmp .Ret ; Case 2: The current node's parent P is black, so property 4 (both children of every red node are black) is not invalidated. In this case, the tree is still valid. Property 5 (all paths from any given node to its leaf nodes contain the same number of black nodes) is not threatened, because the current node N has two black leaf children, but because N is red, the paths through each of its children have the same number of black nodes as the path through the leaf it replaced, which was black, and so this property remains satisfied. .Case2: cmp byte[esi+NODE.COL],0 je .Ret ; Case 3: If both the parent P and the uncle U are red, then both of them can be repainted black and the grandparent G becomes red (to maintain property 5 (all paths from any given node to its leaf nodes contain the same number of black nodes)). Now, the current red node N has a black parent. Since any path through the parent or uncle must pass through the grandparent, the number of black nodes on these paths has not changed. However, the grandparent G may now violate properties 2 (The root is black) or 4 (Both children of every red node are black) (property 4 possibly being violated since G may have a red parent). To fix this, the entire procedure is recursively performed on G from case 1 .Case3: mov edi,dword[esi+NODE.UP] ; rsi must have a parent mov ebx,dword[edi+NODE.LEFT] mov ebp,dword[edi+NODE.RIGHT] cmp esi,ebx cmove ebx,ebp cmp ebx,TTNull je .Case4 cmp byte[ebx+NODE.COL],0 je .Case4 mov edx,edi mov byte[esi+NODE.COL],0 mov byte[edi+NODE.COL],1 mov byte[ebx+NODE.COL],0 jmp .FixNode ; Case 4: The parent P is red but the uncle U is black; also, the current node N is the right child of P, and P in turn is the left child of its parent G. In this case, a left rotation on P that switches the roles of the current node N and .Case4: mov ebx,dword[edi+NODE.UP] ; rbx = great grandparent of rdx .Case4A: cmp edx,dword[esi+NODE.RIGHT] jne .Case4B cmp esi,dword[edi+NODE.LEFT] jne .Case4B mov ebp,dword[edx+NODE.LEFT] mov dword[edi+NODE.LEFT],edx mov dword[edx+NODE.LEFT],esi mov dword[esi+NODE.RIGHT],ebp mov dword[esi+NODE.UP],edx mov dword[edx+NODE.UP],edi mov dword[ebp+NODE.UP],esi jmp .Case4Done .Case4B: cmp edx,dword[esi+NODE.LEFT] jne .Case5 cmp esi,dword[edi+NODE.RIGHT] jne .Case5 mov ebp,dword[edx+NODE.RIGHT] mov dword[edi+NODE.RIGHT],edx mov dword[edx+NODE.RIGHT],esi mov dword[esi+NODE.LEFT],ebp mov dword[esi+NODE.UP],edx mov dword[edx+NODE.UP],edi mov dword[ebp+NODE.UP],esi .Case4Done: xchg edx,esi ; Case 5: The parent P is red but the uncle U is black, the current node N is the left child of P, and P is the left child of its parent G. In this case, a right rotation on G is performed; the result is a tree where the former parent P is now the parent of both the current node N and the former grandparent G. .Case5: mov ebp,dword[ebx+NODE.RIGHT] cmp ebp,edi cmove ebp,esi mov dword[ebx+NODE.RIGHT],ebp mov ebp,dword[ebx+NODE.LEFT] cmp ebp,edi cmove ebp,esi mov dword[ebx+NODE.LEFT],ebp mov dword[esi+NODE.UP],ebx mov byte[esi+NODE.COL],0 mov dword[edi+NODE.UP],esi mov byte[edi+NODE.COL],1 mov ebp,dword[esi+NODE.RIGHT] mov ebx,dword[esi+NODE.LEFT] cmp edx,ebx jne .Case5Left .Case5Right: mov dword[esi+NODE.RIGHT],edi mov dword[edi+NODE.LEFT],ebp mov dword[ebp+NODE.UP],edi jmp .Ret .Case5Left: mov dword[esi+NODE.LEFT],edi mov dword[edi+NODE.RIGHT],ebx mov dword[ebx+NODE.UP],edi jmp .Ret ; Clears the transposition table align 16 TT_Clear: mov dword[TTHead+NODE.LEFT],TTNull mov dword[TTEntries],0 ret ; Prints the table to rdi align 16 TT_InOrderTraverse: mov ecx,dword[TTHead+NODE.LEFT] .entry: cmp ecx,TTNull je .ret push ecx mov ecx,dword[ecx+NODE.LEFT] call .entry mov ecx,[esp] call TT_PrintNode pop ecx mov ecx,dword[ecx+NODE.RIGHT] call .entry .ret: ret ; Prints node at rcx align 16 TT_PrintNode: mov eax,dword[ecx+NODE.NUM] call PrintInteger mov eax,' ' stosb ret PrintInteger: ; rax: number push ebp push edx mov ebp,esp test eax,eax jns .l1 mov byte[edi],'-' add edi,1 neg eax .l1: xor edx,edx div [OutputBase] push edx test eax,eax jnz .l1 .l2: pop eax add al,'0' stosb cmp esp,ebp jb .l2 pop edx pop ebp ret ParseInteger: ; string at rsi, integer to rax xor ecx,ecx xor eax,eax xor edx,edx cmp byte[esi],'-' je .neg cmp byte[esi],'+' je .pos jmp .next .neg: not edx .pos: add esi,1 .next: mov cl,byte[esi] test cl,cl jz .done sub cl,'0' js .done cmp cl,9 ja .done add esi,1 imul eax,[OutputBase] add eax,ecx jmp .next .done: xor eax,edx sub eax,edx ret SkipSpaces: ; rsi string ; skip over anything that is not a digit or NULL sub esi,1 @@: add esi,1 cmp byte[esi],0 je .done cmp byte[esi],'0' jb @b cmp byte[esi],'9' ja @b .done: ret section '.data' data readable writeable align 4 OutputBase dd 10 align 4 TTEntries dd ? InputString rb 1024 ResultString rb 1024 align 64 TTHead NODE TTNull NODE TT rb sizeof.NODE*TT_MAX_ENTRIES section '.idata' import data readable writeable library kernel32,'KERNEL32.DLL',\ user32,'USER32.DLL',\ gdi32,'GDI32.DLL',\ comctl32,'COMCTL32.DLL' include 'api/kernel32.inc' include 'api/user32.inc' include 'api/gdi32.inc' import comctl32,\ InitCommonControls,'InitCommonControls' section '.rsrc' resource data readable directory RT_DIALOG,dialogs resource dialogs,\ ID_DLGMAIN,LANG_ENGLISH+SUBLANG_DEFAULT,calculator dialog calculator,'red-black sorter',10,10,384,60,DS_CENTER+DS_MODALFRAME+WS_SYSMENU+WS_MINIMIZEBOX,0,0;ID_MENUMAIN dialogitem 'STATIC','enter number to sort separated by spaces',-1, 2,02,380,8, WS_VISIBLE+SS_LEFT+WS_GROUP dialogitem 'EDIT','',ID_EXPRESSION, 2,14,380,12,WS_VISIBLE+WS_TABSTOP+WS_BORDER+ES_AUTOHSCROLL dialogitem 'EDIT','',ID_RESULT, 2,30,380,12,WS_VISIBLE+WS_BORDER+WS_TABSTOP+ES_READONLY+ES_AUTOHSCROLL enddialog |
|||
07 Feb 2014, 19:10 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.