• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[vJASS] Group<T>

GroupT


A Generic Group library that allows dynamic generation of structs that serve as containers for any kind of data.

Code

Documentation

Version History

Features to be added (by request)

Features to be added (planned)


JASS:
library GenericGroup requires /*

    */ Table,             /*
    *
    */ AllocationAndLinks /*
    *
    */
  
    public struct HASH extends array
        static constant hashtable HASH = InitHashtable()
  
        method destroy takes nothing returns nothing
            if LoadInteger(HASH, 0, this) != 0 then
                return
            endif
          
            call SaveInteger(HASH, 0, this, LoadInteger(HASH, 0, 0))
            call SaveInteger(HASH, 0, 0, this)
        endmethod
      
        static method new takes nothing returns integer
            local integer this = LoadInteger(HASH, 0, 0)
          
            if LoadInteger(HASH, 0, this) == 0 then
                set this = this + 1
                call SaveInteger(HASH, 0, 0, this)
            else
                call SaveInteger(HASH, 0, 0, LoadInteger(HASH, 0, this))
                call RemoveSavedInteger(HASH, 0, this)
            endif
            return this
        endmethod
    endstruct
  
    //! runtextmacro DLinkedListT("list", "")
  
//! textmacro GroupT takes T, K, I, T1, T2, T3, NaN, NaNT2
    module $T$GroupM
        private static method onInit takes nothing returns nothing
            set Value = GenericGroup_HASH.new()
            set Count = GenericGroup_HASH.new()
            set TriggerStorage = GenericGroup_HASH.new()
            set ConditionStorage = GenericGroup_HASH.new()
            set IsBeingRemoved = GenericGroup_HASH.new()
            debug set AllowDebug = GenericGroup_HASH.new()
        endmethod
    endmodule
  
    $K$ struct $T$Group extends array
        implement AllocH
        implement DoubleLink_list
      
        private static thistype array current
      
        private static constant integer SPACE = $I$
      
        private static integer Value = 0
        private static integer Count = 0
        private static integer TriggerStorage = 0
        private static integer ConditionStorage = 0
        private static integer IsBeingRemoved = 0
        debug private static integer AllowDebug = 0
      
        private integer Storage
      
        /*  ==================  //
        *   Variable operators  //
        *   ==================  // */
      
        private method setCount takes integer newValue returns nothing
            call SaveInteger(GenericGroup_HASH.GenericGroup_HASH, Count, this, newValue)
        endmethod
      
        method getCount takes nothing returns integer
            return LoadInteger(GenericGroup_HASH.GenericGroup_HASH, Count, this)
        endmethod
      
        method operator $T1$= takes $T3$ newR returns nothing
            if not (newR != $NaN$) then
                call RemoveSaved$NaNT2$(GenericGroup_HASH.GenericGroup_HASH, Value, this)
            else
                call Save$T2$(GenericGroup_HASH.GenericGroup_HASH, Value, this, newR)
            endif
        endmethod
      
        method operator $T1$ takes nothing returns $T3$
            return Load$T2$(GenericGroup_HASH.GenericGroup_HASH, Value, this)
        endmethod
      
        /*  ==================  //
        *   Safety checker      //
        *   ==================  // */
      
        private method isHead takes nothing returns boolean
            return this.list_head != 0
        endmethod
      
        /*  =================   //
        *   Instance getter     //
        *   =================   // */
      
        private method updatePositions takes integer instruction, integer value returns nothing
            local integer updateCount = this.getCount()/thistype.SPACE
            local thistype that = 0
          
            if instruction == 1 then
                //  Insertion call from add().
                set that = value
                if ModuloInteger(this.getCount(), thistype.SPACE) == 0 then
                    call SaveInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount, that)
                endif
            elseif instruction == 2 then
                //  Insertion call from add_pos().
                //  Start-off index.
                set value = value/thistype.SPACE
                if LoadInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount) == 0 then
                    call SaveInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount, this.list_prev)
                    set updateCount = updateCount - 1
                endif
                loop
                    exitwhen updateCount <= value
                    call SaveInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount, thistype(LoadInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount) ).list_prev)
                  
                    set updateCount = updateCount - 1
                endloop
            elseif instruction == 3 then
                //  Delete call from node_pop()
                //  Start-off index.
                set value = value/thistype.SPACE
              
                if updateCount < (this.getCount() + 1)/thistype.SPACE then
                    call RemoveSavedInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount + 1)
                endif
                loop
                    exitwhen updateCount <= value
                    call SaveInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount, thistype(LoadInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, updateCount) ).list_next)
                  
                    set updateCount = updateCount - 1
                endloop
            endif
        endmethod
      
        static if DEBUG_MODE then
            method operator debug_mode takes nothing returns boolean
                if isHead() then
                    return LoadBoolean(GenericGroup_HASH.GenericGroup_HASH, AllowDebug, this)
                endif
                return false
            endmethod
      
            method operator debug_mode= takes boolean b returns nothing
                if isHead() then
                    if b then
                        call SaveBoolean(GenericGroup_HASH.GenericGroup_HASH, AllowDebug, this, b)
                    else
                        call RemoveSavedBoolean(GenericGroup_HASH.GenericGroup_HASH, AllowDebug, this)
                    endif
                endif
            endmethod
        endif
      
        method operator [] takes integer pos returns thistype
            local integer mod_pos = 0
            local integer temp_pos = 0
            local thistype that = 0
          
            if not isHead() or pos > this.getCount() or pos < 0 then
                debug if not isHead() then
                    debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: op_getindex[] ] [Instance " + I2S(this) + "] Invalid pointer exception!")
                debug elseif pos > this.getCount() then
                    debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: op_getindex[] ] [Instance " + I2S(this) + "] Out of bounds exception! (Positive)")
                debug elseif pos < 0 then
                    debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: op_getindex[] ] [Instance " + I2S(this) + "] Out of bounds exception! (Negative)")
                debug endif
                return 0
            endif

            set mod_pos = ModuloInteger(pos, thistype.SPACE)
      
            set temp_pos = this.getCount()/thistype.SPACE*thistype.SPACE
            if pos > temp_pos then
                if mod_pos > thistype.SPACE/2 then
                    set that = this.list_prev
                    loop
                        exitwhen pos >= this.getCount()
                      
                        set that = that.list_prev
                        set pos = pos + 1
                    endloop
                else
                    set that = LoadInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, temp_pos/thistype.SPACE)
                    loop
                        exitwhen ModuloInteger(pos, thistype.SPACE) <= 0
                      
                        set that = that.list_next
                        set pos = pos - 1
                    endloop
                endif
            else
                if mod_pos > thistype.SPACE/2 then
                    set that = LoadInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, (pos/thistype.SPACE) + 1)
                    loop
                        exitwhen ModuloInteger(pos, thistype.SPACE) <= 0

                        set that = that.list_prev
                        set pos = pos + 1
                    endloop
                else
                    set that = LoadInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, pos/thistype.SPACE)
                    loop
                        exitwhen ModuloInteger(pos, thistype.SPACE) <= 0

                        set that = that.list_next
                        set pos = pos - 1
                    endloop
                endif
            endif          
            return that
        endmethod
      
        method add takes $T3$ val returns nothing
            local thistype that = 0
          
            if isHead() then
                set that = allocate()
              
                set that.$T1$ = val
                call that.list_insert(this)
              
                call this.setCount(this.getCount() + 1)
                call updatePositions(1, that)
            debug else
                debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: add] [Instance " + I2S(this) + "] Invalid pointer exception!")
            endif
        endmethod
      
        method add_pos takes $T3$ val, integer pos returns nothing
            local thistype that = 0
          
            if isHead() then
                if pos > this.getCount() then
                    call add(val)
                    return
                elseif pos < 0 then
                    return
                endif
              
                set pos = IMaxBJ(1, pos)
                set that = allocate()
              
                set that.$T1$ = val
                call that.list_insert(this[pos])
              
                call this.setCount(this.getCount() + 1)
                call updatePositions(2, pos)
            debug else
                debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: add_pos] [Instance " + I2S(this) + "] Invalid pointer exception!")
            endif
        endmethod
      
        method preset takes integer amount returns nothing
            loop
                exitwhen amount <= 0 or not isHead()
                call add($NaN$)
              
                set amount = amount - 1
            endloop
          
            debug if not isHead() then
                debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: preset] [Instance " + I2S(this) + "] Invalid pointer exception!")
            debug endif
        endmethod
      
        method clearData takes nothing returns nothing
            local thistype last = this.list_prev
          
            if isHead() then
                loop
                    exitwhen last == this
                    set last.$T1$ = $NaN$
                  
                    set last = last.list_prev
                endloop
                set this.$T1$ = $NaN$
            debug else
                debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: clearData] [Instance " + I2S(this) + "] Invalid pointer exception!")
            endif
        endmethod
      
        method node_pop takes integer pos returns nothing
            local thistype that = 0
            local thistype array callbackList
            local boolean b = LoadBoolean(GenericGroup_HASH.GenericGroup_HASH, IsBeingRemoved, this)
          
            if isHead() and not b then
                if pos <= 0 or pos > this.getCount() then
                    return
                endif
              
                set that = this[pos]

                set callbackList[1] = current[1]
                set callbackList[2] = current[2]
              
                set current[1] = that
                set current[2] = this
              
                debug if this.debug_mode then
                    debug call BJDebugMsg("$T$Group [" + I2S(this) + "]: Position of node: " + I2S(pos))
                debug endif
              
                call SaveBoolean(GenericGroup_HASH.GenericGroup_HASH, IsBeingRemoved, this, true)
                call TriggerEvaluate(LoadTriggerHandle(GenericGroup_HASH.GenericGroup_HASH, TriggerStorage, this))
                call RemoveSavedBoolean(GenericGroup_HASH.GenericGroup_HASH, IsBeingRemoved, this)
              
                set current[2] = callbackList[2]
                set current[1] = callbackList[1]

                set that.$T1$ = $NaN$
              
                call that.list_pop()
                call that.deallocate()
              
                call this.setCount(this.getCount() - 1)
                call this.updatePositions(3, pos - 1)
            endif
        endmethod
      
        static method getRemovedNode takes nothing returns thistype
            return current[1]
        endmethod
      
        static method getOnRemoveHeadNode takes nothing returns thistype
            return current[2]
        endmethod
      
        private static method exec_clear takes nothing returns nothing
            local thistype this = current[0]
            local integer i = 1
          
            loop
                exitwhen i > 60 or this.getCount() <= 0
              
                call this.node_pop(this.getCount())
                set i = i + 1
            endloop
          
            if this.getCount() > 0 then
                call ForForce(bj_FORCE_PLAYER[0], function thistype.exec_clear)
            endif
        endmethod
      
        method setOnDestroy takes code destfunc returns nothing
            local trigger t = null
            if isHead() then
                set t = LoadTriggerHandle(GenericGroup_HASH.GenericGroup_HASH, TriggerStorage, this)
                if t == null then
                    set t = CreateTrigger()
                    call SaveTriggerHandle(GenericGroup_HASH.GenericGroup_HASH, TriggerStorage, this, t)
                endif
              
                if LoadTriggerConditionHandle(GenericGroup_HASH.GenericGroup_HASH, ConditionStorage, this) != null then
                    call TriggerRemoveCondition(t, LoadTriggerConditionHandle(GenericGroup_HASH.GenericGroup_HASH, ConditionStorage, this))
                endif
              
                call SaveTriggerConditionHandle(GenericGroup_HASH.GenericGroup_HASH, ConditionStorage, this, TriggerAddCondition(t, Condition(destfunc)))
                set t = null
            endif
        endmethod
      
        method clear takes nothing returns boolean
            if isHead() and this.getCount() > 0 then
                set current[0] = this
              
                call ForForce(bj_FORCE_PLAYER[0], function thistype.exec_clear)
            endif
            return isHead()
        endmethod
      
        method destroy takes nothing returns nothing
            if not clear() then
                debug call BJDebugMsg("|cffffcc00$T$Group|r: [Method: destroy] [Instance: " + I2S(this) + "] invalid object exception!")
                return
            endif
          
            call list_pop()
            set list_head = 0
          
            call RemoveSavedInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, 0)
          
            call GenericGroup_HASH(Storage).destroy()
            set Storage = 0
          
            call DestroyTrigger(LoadTriggerHandle(GenericGroup_HASH.GenericGroup_HASH, TriggerStorage, this))
            call RemoveSavedHandle(GenericGroup_HASH.GenericGroup_HASH, TriggerStorage, this)
            call RemoveSavedHandle(GenericGroup_HASH.GenericGroup_HASH, ConditionStorage, this)
          
            set $T1$ = $NaN$
          
            call deallocate()
        endmethod
      
        static method create takes nothing returns thistype
            local thistype this = allocate()
          
            set Storage = GenericGroup_HASH.new()
          
            call this.list_insert(this)
            set this.list_head = 1
          
            call SaveInteger(GenericGroup_HASH.GenericGroup_HASH, this.Storage, 0, this)
            return this
        endmethod
      
        implement $T$GroupM
    endstruct  
//! endtextmacro

    //! runtextmacro GroupT("Real", "", "8", "real", "Real", "real", "0.", "Real")
  
endlibrary


JASS:
//! novjass
/**
*
*   --------------------------------
*       Generic Groups or GroupT
*   --------------------------------
*
*       Welcome to the documentation portion of the library aforementioned (above).
*       This will serve to fulfill the following objectives:
*           -   To inform the reader/s about the functionality of the library.
*           -   To inform the reader/s about the nature of the library.
*           -   To inform the reader/s about the purpose of the library.
*
*   For ease of reference, the Table of Contents is placed below with the appropriate line number
*
*    -------------------------------
*   |      Table of Contents        |
*    -------------------------------
*   |                               |
*   |   Functionalities: 29         |
*   |       Textmacros : 32         |
*   |       Methods    : 79         |
*   |   Nature         : 207        |
*   |   Purpose        : 221        |
*   |   Libraries used : 229        |
*   |   Anticipated Q  : 262        |
*    -------------------------------
*       
*   Functionalities:
*       -   This library provides the following functionalities:
*
*       -   Textmacros:
*           -   GroupT(T, K, I, T1, T2, T3, NaN, NaNT2)
*               -   This textmacro generates a struct which contains a certain type as declared in
*                   the following parameters:
*                       T - Refers to the prefix of the struct:
*                           - in this case, if T is Real, then the resulting struct is RealGroup
*
*                       K - Refers to the encapsulation of the struct:
*                           - if K is private, then the struct becomes private, only being
*                             accessible to the enclosing library or scope.
*
*                       I - Refers to the constant space between instances.
*                           - "I" takes an integer parameter. Aside from that, the constant serves
*                             to reduce the number of operations to O(I) and O(n/I) respectively.
*                             (This refers to a read operation (worst-case) and insertion and
*                              deletion (worst-case)).
*
*                       T1 - Refers to the operator of an individual instance.
*                           - For example, if T is Int, and T1 is real, we can simply write
*                             Int(2).real. However, this direct reference to instances is frowned
*                             upon.
*
*                       T2 - Refers to the equivalent native of the desired type.
*                           - From the previous example, say T2 is Boolean.
*                           - Thus, the following output would become something like this:
*                             set Int(2).real = false
*
*                       T3 - Refers to the type and return type of the instance.
*                           - This is the <T> part in Group<T>, which asserts strong type-safety.
*                           - This returns the appropriate data type from the request.
*                           - Now, if T = Real, T1 = real, T2 = Real, and T3 = real, the result
*                             would be:
*                                 Real(3).real = real r (sets the real member of instance 3 to
*                                                       (the appropriate literal r.)
*
*                       NaN - Refers to the actual null-type of the instance.
*                            - The null-type of the instance is equivalent to the null-value of the
*                              type of the instance.
*                            - For example, 0 is the usual null-type of integer (in JASS),
*                            - false is the null-type in boolean expressions (again in JASS).
*
*                       NaNT2 - Refers to the equivalent removal native of the desired type.
*                            - There are five natives specifically for removing the contents of a
*                              hashtable, namely RemoveSavedInteger, ..Real, ..Boolean, ..Handle,
*                              ..String.
*
*
*       -   Generic Methods:
*
*   -------------
*       NOTE:
*   -------------
*           *   Functions annotated with debug only exist in DEBUG_MODE.
*
    ------------------------------------------------------------------------------------------------
*           private method setCount(int newValue)
*               -   An internal method primarily used within head instances.
*               -   Giving this functionality to member instances would complicate things...
*                   operation-wise.
*
*           method getCount() returns int
*               -   Returns the number of instances in the list.
*               -   Will only work with head instances due to the nature of setCount.
*
*           method operator $T1$() returns $T3$
*               -   Explained in the Textmacro section (see $T1$ & $T3$).
*               -   The getter operator of the instance.
*
*           method operator $T1$= ($T3$ newValue)
*               -   Explained in the Textmacro section (see $T1$ & $T3$).
*               -   The setter operator of the instance.
*
*           private method isHead() returns boolean
*               -   A safety method that checks if the instance is a head instance.
*
*           private method updatePositions(int instruction, int value)
*               -   This handles the repositioning of instances upon insertion or deletion.
*               -   This only affects head nodes.
*
*               -   For each instruction {1, 2, 3}, there corresponds a task.
*                   - For instruction 1, it simply creates a new pointer to the last instance
*                     if the modulo of the number of instances and the amount of space is equal
*                     to 0.
*                       - That means if the amount of space is 8 ($I$ = 8), then a new pointer
*                         is created every 8 insertions.
*
*                   - For instruction 2, it adjusts the pointers such that the minimum amount
*                     of operations is achieved. This best averts the worst-case scenario, in
*                     a sense. It is called on insertion at a certain position.
*
*                   - For instruction 3, it adjusts the pointer such that the minimum amount
*                     of operations is achieved. It is called on deletion at a certain
*                     position.
*
*           debug method operator debug_mode= (boolean b)
*               -   In debug mode, this prints out the details on the processes involved.
*               -   This only happens if debug_mode is set to true (through the setter method)
*
*           debug method operator debug_mode() returns boolean
*               -   In debug_mode, this returns the flag for producing additional debug
*                   messages.
*               -   This is the getter method for the flag.
*
*           static method getRemovedNode() returns $T$Group
*               -   This returns the instance currently being removed.
*               -   Data persists only on notification of destruction.
*               -   Recursion-safe.
*
*           static method getOnRemoveHeadNode() returns $T$Group
*               -   This returns the head node of the instance currently being removed.
*               -   For example, let head = 1, and node = 2
*                   When 2 is removed, via node_pop(), getOnRemoveHeadNode will point to 1.
*               -   Data persists only on notification of destruction.
*               -   Recursion-safe.
*
*           private static method exec_clear()
*               -   This is the loop-method for the instance method clear().
*               -   This clears out the list of a head instance, by calling node_pop().
*               -   For best results, the last node is removed first to minimize operation count.
*               -   In another sense, this does the dirty work while clear sends out the
*                   instructions.
*               -   This clears out the pointer reference through updateInstructions through
*                   node_pop.
*
*           method clear() returns boolean
*               -   This internally calls exec_clear() without having to suffer an op-limit
*                   crash.
*               -   It checks if the instance is a head instance before calling exec_clear().
*                   -   The result of the condition is what is returned.
*               -   Thus, it is safe to use in scripting.
*
*           method setOnDestroy(code func)
*               -   This attaches a handler function to be run on the popping of a certain
*                   instance from a head instance.
*               -   This checks if the instance is a head instance before proceeding.
*
*           method destroy()
*               -   This destroys the head instance, and ignores member instances.
*               -   This internally calls clear() beforehand, and recycles the pointer list
*                   to be used later on.
*               -   In DEBUG_MODE, this prints an error message.
*           
*           static method create() returns $T$Group
*               -   This creates a head instance, which you can do a lot of things with.
*
*           method add($T3$ newValue)
*               -   This adds an entry with the requested value.
*               -   This internally calls updatePosition with the first instruction, and value equal
*                   to the allocated node instance (which holds said entry)
*               -   This checks if the requesting instance is a head instance and proceeds if so.
*               -   In DEBUG_MODE, this prints an error message.
*
*           method add_pos($T3$ newValue, integer pos)
*               -   This adds an entry at a desired index, pushing the instance found therein.
*               -   This internally calls updatePosition with the second instruction, and value
*                   equal to the index (pos).
*               -   If it exceeds the number of instances within the list, it calls add instead.
*               -   In DEBUG_MODE, this prints an error message.
*
*           method preset(integer amount)
*               -   This adds a certain number of fields equal to the requested amount.
*               -   This internally checks if the instance is a head instance and breaks immediately
*                   if so.
*               -   In DEBUG_MODE, this prints an error message.
*
*       -   Modules:
*           -   Module $T$GroupM
*               -   This is basically the initializer of the necessary variables.
*               -   This is best left untouched by the end-user.
*
*       Aside from those methods, the library also features a struct RealGroup, generated from
*   the GroupT textmacro.
*
*   ------------------------------------------------------------------------------------------------
*
*   Nature:
*       
*           The structs generated from the textmacro GroupT are, by nature, OOP-oriented.
*           The group structs, as they are to be called from this point, make it easier for one to
*       dynamically attach data at any amount. 
*           This can be very useful in attaching data to missiles such as the attributes of the
*       missile and the user-data fed to the missile, attaching data to units or timers, and even
*       just creating effect groups, destructable groups and item groups altogether, although
*       with the need for abstraction for the latter.
*           In short, this allows a lot of things that need to be clumped up into groups to be
*       done easier, and without too much of a hassle, and with needed type-checking.
*
*   ------------------------------------------------------------------------------------------------
*
*   Purpose:
*
*       This library aims to simplify a lot of things, as well as provide vJASS with de-facto
*       type safety in the matters of groups. This also acts as one crucial part in the making
*       of a standard vJASS library.
*
*   ------------------------------------------------------------------------------------------------
*
*   Libraries used:
*
*           This libraries uses the following libraries, with a succinct explanation as to why these
*       libraries are required.
*
*       */

    Library:
   
        Table   -   Bribe
       
/**
*       -   Table is a library that has a lot of practical uses, aside from simplifying the life of
*           a coder in matters of hashtables. That being said, Table is not really required as a
*           whole in this library, but why it is required anyway is because of the next library
*           requirement.
*
*       URL:    https://www.hiveworkshop.com/threads/snippet-new-table.188084/
*       */

        AllocationAndLinks  -   MyPad

/**
*       -   AllocationAndLinks is just one part of 4 libraries, which are -> AllocT, LinkedListT
*           and AllocLink. As AllocationAndLinks requires AllocLink, so does AllocLink require
*           AllocT and LinkedListT, which optionally requires Table (the library above).
*           The hashtable allocation method could not be left ignored, thus leading to the 
*           requirement of the library above, which, for hashtable allocation, requires Table.
*
*       URL:    https://www.hiveworkshop.com/threads/allocation-and-links.293621/#post-3159130
*
*   ------------------------------------------------------------------------------------------------
*
*   Anticipated Questions:
*
*   ----------------------
*
*       Why have another hashtable HASH if you could just use Table instances?
*           -   I preferred to be on the safe side of things, so I had to use another hashtable
*               so that I don't end up using too many Table instances.
*
*       Why is the HASH struct public? Does it mean we can use it?
*           -   For the intents and purposes of the coder, the HASH is better treated as a
*               private struct in terms of usage, but that doesn't mean it isn't public.
*               The HASH struct is public because of the following reason, the ability for
*               generated struct groups to access the HASH struct, which would be rendered
*               impossible to access from the outside if the HASH struct is private.
*
**/
//! endnovjass

  • v.1.0 - Release!

  • None.

  • Search method.
 
A group for each type would be useful but this seems a bit over-complicated. What benefit does this library provide over List<T> or any other generic container?

The code can also be hard to read at times especially with your usage of hashtables (for example GenericGroup_HASH.GenericGroup_HASH). There is also no example code showing how to use the system and you are mixing camelCase with underscores.

In your documentation you state that you are using a dedicated hashtable over something like Table because you don't want too many Table instances. This doesn't make any sense because you can only have 255 hashtables whereas you can have thousands of Table instances. A hashtable may be more convenient if you need the 2D storage space so it's fine to use a dedicated one for some systems.

The idea is useful but I don't understand the benefit of this over the other containers like List<T>.
 
Last edited:
There's only one benefit I know of for this system. It allows O(c) access regarding any element, where c is a constant size. Removal of an instance at the worst case scenario is O(n/c), when updating the median buckets.

Having a dedicated hashtable for this is just a pre-emptive for allaying my own restrictions on Table instances.

Overall, this is something I made before checking out List<T>.
 
Top