; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Sorted counter array.
;
;  Target OS: Any
;
;  Dependencies: FreshLib
;
;  Notes:
;_________________________________________________________________________________________

module "Value counter array library"


struct TCounter
  .value dd ?
  .count dd ?
ends


; returns:
;  edx - the new pointer to the array.
;  eax - pointer to the element incremented.

proc IncCount, .pArray, .value
begin
        mov     edx, [.pArray]
        stdcall __SearchCountArray, edx, [.value]
        jc      .add_new

        lea     eax, [edx+TArray.array+sizeof.TCounter*eax]
        inc     [eax+TCounter.count]
        js      .error
        return

.add_new:
        stdcall InsertArrayItems, edx, eax, 1
        push    [.value]
        pop     [eax+TCounter.value]
        mov     [eax+TCounter.count], 1
        return

.error:
        int3
        return
endp



; returns:
;  edx - the new pointer to the array.
;  eax - pointer to the element incremented or NULL, if the element has been deleted from the array.

proc DecCount, .pArray, .value
begin
        push    ecx

        mov     edx, [.pArray]
        stdcall __SearchCountArray, edx, [.value]
        jc      .error                  ; can't decrement not existing element!

        lea     ecx, [edx+TArray.array+sizeof.TCounter*eax]
        dec     [ecx+TCounter.count]
        js      .error
        jnz     .finish

        stdcall DeleteArrayItems, edx, eax, 1
        xor     ecx, ecx

.finish:
        mov     eax, ecx
        pop     ecx
        return

.error:
        int3
        jmp     .finish
endp


; binary search [.value] in the array.
; returns:
;   eax, the index where the element has been found or the index where the element has to be inserted, if not found
;   CF = 0 - element has been found.
;   CF = 1 - element not found.

proc __SearchCountArray, .pArray, .value
begin
        pushad

        mov     esi, [.pArray]

        xor     eax, eax
        xor     ecx, ecx                ; left
        mov     edx, [esi+TArray.count] ; right

        dec     edx
        js      .not_found

        mov     ebx, [.value]

.loop:
        cmp     edx, ecx
        jl      .not_found

        lea     eax, [ecx+edx]
        sar     eax, 1

        cmp     ebx, [esi+TArray.array+ sizeof.TCounter*eax+TCounter.value]
        je      .found

        ja      .goto_right

; goto left
        lea     edx, [eax-1]
        jmp     .loop


.goto_right:
        inc     eax
        mov     ecx, eax
        jmp     .loop

.found:
        clc

.finish:
        mov     [esp+4*regEAX], eax
        popad
        return

.not_found:
        stc
        jmp     .finish
endp






endmodule