Buchempfehlung
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Umfassend, aber leicht verständlich führt dieses Buch in die Programmierung von ATMEL AVR Mikrocontrollern ein. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

fb:porticula NoPaste

Info
Info / Hilfe
Liste
Übersicht / Liste
Neu
Datei hochladen
Suche
Quellcode suchen
Download
Dateidownload

Dictionary nach .NET-Vorbild.

Uploader:MitgliedStringEpsilon
Datum/Zeit:02.01.2015 20:45:44

' Dictionary.bas,  written by StringEpsilon.
' Heavily influenced by the implementation of the Dictionary-class in .NET / Mono.
' The array of primes is taken from the mono source code.
' The function StringHash()) is a direct reimplementation of the GetHashCode-Method of the string class (.NET)
'
' Do what the fuck you want (WTFPL).

namespace fbDictionary

dim shared PRIMES(0 to ...) as integer = { 11,19,37,73,109,163,251,367,557,823,1237,1861,2777,4177_
,6247,9371,14057,21089,31627,47431,71143,106721,160073, _
240101,360163,540217,810343,1215497,1823231,2734867, _
4102283,6153409,9230113,13845163 }

function StringHash(value as string) as integer
    dim as integer hash
    if (value = "" ) then return 0

    for i as integer = 0 to len(value)
        hash = 31 * hash + value[i]
    next
    return hash
end function

end namespace

#MACRO DeclareDictionary(datatype )

type ##datatype##Bucket
    key as string
    value as datatype ptr
    nextBucket as ##datatype##Bucket ptr

    declare constructor()
    declare constructor(key as string, value as datatype)
    declare destructor()
end type

constructor ##datatype##Bucket
    this.value = callocate(sizeof(datatype))
end constructor

constructor ##datatype##Bucket(key as string, value as datatype)
    this.value = callocate(sizeof(datatype))
    this.key = key
    *this.value = value
end constructor


destructor ##datatype##Bucket()
    deallocate(this.value)
    deallocate this.nextBucket
end destructor


Type ##datatype##Dictionary
    declare constructor ()
    declare destructor()

    declare operator [](key as string) as datatype ptr
    declare property Size() as uinteger
    declare property Count() as uinteger
    declare sub Remove(key as string)
    declare sub Insert(key as string, value as datatype)

    private:
        _table as ##datatype##Bucket ptr ptr
        _size as uinteger
        _inUse as uinteger

        declare sub Rehash(newsize as uinteger)
end type

operator ##datatype##Dictionary.[](key as string) as datatype ptr
    dim as integer index = fbDictionary.StringHash(key) MOD this._size
    dim as ##datatype##Bucket ptr bucket = this._table[index]
    if bucket = 0 then
        return 0
    end if

    if (bucket->key = key) then
        return bucket->value
    else
        bucket = bucket->nextBucket

        while ( bucket <> 0 ANDALSO bucket->key <> key)

            bucket = bucket->nextBucket
        wend
        if (bucket <> 0) then
            return bucket->value
        end if
    end if
    return 0
end operator

constructor ##datatype##Dictionary()
    this._size = fbDictionary.PRIMES(0)
    this._table = callocate( this._size, sizeof(##datatype##Bucket) )
end constructor

sub ##datatype##Dictionary.Insert(key as string, value as datatype)
    if key = "" then exit sub
    dim as integer index = fbDictionary.StringHash(key) MOD this._size

    if (this._table[index] = 0) then
        this._table[index] = new ##datatype##Bucket(key, value)
        this._inUse += 1
    else

        if (this._table[index]->key = key ) then exit sub
        if (this._inUse >= this._size) then

            ' Resize / Rehash the table if it's full with the next best prime number
            dim as integer newPrime
            for i as integer = 0 to ubound(fbDictionary.PRIMES)
                if ( this._size*2 < fbDictionary.PRIMES(i)) then
                    newPrime = fbDictionary.PRIMES(i)
                    exit for
                end if
            next

            this.rehash( newPrime )
            this.Insert(key, value)
        else
            ? "Chained: "& this._table[index]->key & " -> " & key
            this._table[index]->nextBucket = new ##datatype##Bucket(key, value)
            this._inUse += 1
        end if
    end if
end sub


sub ##datatype##Dictionary.Rehash(newsize as uinteger)
    dim as ##datatype##Bucket ptr ptr oldTable = this._table
    dim as integer oldSize = this._size
    this._inUse = 0
    this._size = newSize
    this._table = callocate(newsize, sizeof(##datatype##Bucket))

    for i as uinteger = 0 to oldSize
        if ( oldTable[i]->key <> "" ) then
            dim as ##datatype##Bucket ptr item = oldTable[i]
            do while ( item <> 0 )
                this.Insert(item->key, *item->value)
                item = item->nextBucket
            loop
        end if
    next
    deallocate oldTable
    this._size = newSize
end sub

destructor ##datatype##Dictionary()
    deallocate this._table
end destructor

property ##datatype##Dictionary.Size() as uinteger
    return this._size
end property

property ##datatype##Dictionary.Count() as uinteger
    return this._inUse
end property

sub ##datatype##Dictionary.Remove(key as string)
    dim as integer index = fbDictionary.StringHash(key) MOD this._size
    dim as ##datatype##Bucket ptr bucket = this._table[index]

    if bucket = 0 then
        exit sub
    end if

    if (bucket->key = key) then
        if ( bucket->nextBucket = 0 ) then
            delete bucket
        else
            this._table[index] = bucket->nextBucket
            bucket->nextBucket = 0
            delete bucket
        end if
        this._inUse -= 1
    else
        dim as ##datatype##Bucket ptr oldBucket = bucket
        while ( bucket <> 0 ANDALSO bucket->key <> key)
            oldBucket = bucket
            bucket = bucket->nextBucket
        wend
        if (bucket->key = key) then
            oldBucket->nextBucket = bucket->nextBucket
            bucket->nextBucket = 0
            delete bucket
            this._inUse -= 1
        end if
    end if

end sub

#endMacro