• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Set (theory)

Status
Not open for further replies.
Level 13
Joined
Nov 7, 2014
Messages
571
JASS:
library Set

//! novjass

General notes:
    This is an attempt to implement a struct for working with sets.

References:
    sets: https://en.wikipedia.org/wiki/Set_theory
    union: https://en.wikipedia.org/wiki/Union_(set_theory)
    intersection: https://en.wikipedia.org/wiki/Intersection_(set_theory)
    difference: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
    symmetric difference: https://en.wikipedia.org/wiki/Symmetric_difference

API:

// for brevity when `a` is mentioned it is the same as the Set represented by the `this` argument of the methods


// creates an empty set
static method create takes nothing returns thistype

// destroys the set
static method destroy takes nothing returns nothing


// the number of elements in the set
readonly integer size

// returns the i'th element of `a`, i must be in the range: 1 <= i <= `a`.size
method operator[] takes integer i returns integer


// adds the element `e` to the set `a`, returns `a`
method add takes integer e returns thistype

// removes the element `e` from the set `a`, returns `a`
method remove takes integer e returns thistype

// returns true if the element `e` is in the set `a`
method has takes integer e returns boolean


// returns true if `b` has all the elements of `a` or more, i.e `a` is a subset of (<=, less than or equal to, le) `b`
method le takes Set b returns boolean

// returns true if `b` has all the elements of `a` and more, i.e `a` is a strict subset of (<, less than, lt) `b`
method lt takes Set b returns boolean


// returns the union of `a` and `b`, i.e the set that contains the elements that are either in `a`, `b` or both
method union takes Set b returns Set

// returns the intersection of `a` and `b`, i.e the set that contains the elements that are both in `a` and in `b`
method intersection takes Set b returns Set

// returns the set difference of `a` and `b`, i.e the set that contains the elements that are in `a` and not in `b`
method diff takes Set b returns Set

// returns the symmetric difference of `a` and `b`, i.e the set that contains the elements that are in `a` or `b` but not both
method sym_diff takes Set b returns Set


// returns a string representation of the set
method to_string takes nothing returns string

//! endnovjass


globals
    private hashtable ht = InitHashtable()
endglobals

struct Set
    readonly integer size = 0

    //
    // the default create method is sufficient
    //

    method destroy takes nothing returns nothing
        call FlushChildHashtable(ht, 3 * this)
        call FlushChildHashtable(ht, 3 * this + 1)
        call FlushChildHashtable(ht, 3 * this + 2)
        call this.deallocate()
    endmethod


static if DEBUG_MODE then
    private static method panic takes string s returns nothing
        call BJDebugMsg("|cffFF0000" + "thistype" + " error: " + s + "|r")
        if 1 / 0 == 1 then // we report the error and stop the script from running any further
        endif
    endmethod
endif

    method operator[] takes integer i returns integer
        debug if not (1 <= i and i <= this.size) then
        debug    call panic("attempt to access the " + I2S(i) + "th element of Set(" + I2S(this) + ") but size is " + I2S(this.size))
        debug endif
        return LoadInteger(ht, 3 * this + 1, i)
    endmethod


    method add takes integer e returns thistype
        local integer elems = 3 * this

        if HaveSavedInteger(ht, elems, e) then
            return this
        endif

        call SaveInteger(ht, elems, e, 1)
        set this.size = this.size + 1
        call SaveInteger(ht, 3 * this + 1, this.size, e)
        call SaveInteger(ht, 3 * this + 2, e, this.size)

        return this
    endmethod

    method remove takes integer e returns thistype
        local integer elems
        local integer list
        local integer pos
        local integer e_pos
        local integer last_e

        set elems = 3 * this
        if not HaveSavedInteger(ht, elems, e) then
            return this
        endif

        call RemoveSavedInteger(ht, elems, e)

        set list = 3 * this + 1
        set pos = 3 * this + 2
        set e_pos = LoadInteger(ht, pos, e)
        set last_e = LoadInteger(ht, list, this.size)

        call SaveInteger(ht, list, e_pos, last_e)
        call SaveInteger(ht, pos, last_e, e_pos)

        call RemoveSavedInteger(ht, pos, e)
        call RemoveSavedInteger(ht, list, this.size)

        set this.size = this.size - 1

        return this
    endmethod

    method has takes integer e returns boolean
        return HaveSavedInteger(ht, 3 * this, e)
    endmethod


    method le takes thistype b returns boolean
        local thistype a = this
        local integer a_list = 3 * a + 1
        local integer count = a.size
        local integer i

        set i = 1
        loop
            exitwhen i > count
            if not b.has(LoadInteger(ht, a_list, i)) then
                return false
            endif
            set i = i + 1
        endloop

        return true
    endmethod

    method lt takes thistype b returns boolean
        return b.size > this.size and this.le(b)
    endmethod


    method union takes thistype b returns thistype
        local thistype a = this
        local thistype result = allocate()
        local integer list
        local integer count
        local integer i

        set list = 3 * a + 1
        set count = a.size
        set i = 1
        loop
            exitwhen i > count
            call result.add(LoadInteger(ht, list, i))
            set i = i + 1
        endloop

        set list = 3 * b + 1
        set count = b.size
        set i = 1
        loop
            exitwhen i > count
            call result.add(LoadInteger(ht, list, i))
            set i = i + 1
        endloop

        return result
    endmethod

    method intersection takes thistype b returns thistype
        local thistype a = this
        local thistype result = allocate()
        local integer list
        local integer count
        local integer i
        local integer e

        set list = 3 * a + 1
        set count = a.size
        set i = 1
        loop
            exitwhen i > count
            set e = LoadInteger(ht, list, i)
            if b.has(e) then
                call result.add(e)
            endif
            set i = i + 1
        endloop

        set list = 3 * b + 1
        set count = b.size
        set i = 1
        loop
            exitwhen i > count
            set e = LoadInteger(ht, list, i)
            if a.has(e) then
                call result.add(e)
            endif
            set i = i + 1
        endloop

        return result
    endmethod

    method diff takes thistype b returns thistype
        local thistype a = this
        local thistype result = allocate()
        local integer list
        local integer count
        local integer i
        local integer e

        set list = 3 * a + 1
        set count = this.size
        set i = 1
        loop
            exitwhen i > count
            set e = LoadInteger(ht, list, i)
            if not b.has(e) then
                call result.add(e)
            endif
            set i = i + 1
        endloop

        return result
    endmethod

    method sym_diff takes thistype b returns thistype
        local thistype a = this
        local thistype result = allocate()
        local integer list
        local integer count
        local integer i
        local integer e

        set list = 3 * a + 1
        set count = a.size
        set i = 1
        loop
            exitwhen i > count
            set e = LoadInteger(ht, list, i)
            if not b.has(e) then
                call result.add(e)
            endif
            set i = i + 1
        endloop

        set list = 3 * b + 1
        set count = b.size
        set i = 1
        loop
            exitwhen i > count
            set e = LoadInteger(ht, list, i)
            if not a.has(e) then
                call result.add(e)
            endif
            set i = i + 1
        endloop

        return result
    endmethod


    method to_string takes nothing returns string
        local string s
        local integer count = this.size
        local integer i

        if count <= 0 then
            return "{}"
        endif

        set s = "{ " + I2S(this[1])

        set i = 2
        loop
            exitwhen i > count
            set s = s + ", " + I2S(this[i])
            set i = i + 1
        endloop

        set s = s + " }"

        return s
    endmethod

endstruct

endlibrary
 

Attachments

  • set-demo.w3x
    54.3 KB · Views: 47
Status
Not open for further replies.
Top