Пример #1
0
 public static void Remove(PtrLst *self, void *ptr)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
     int oldCount = self->count;
                 #endif
     void **arr = self->arr;
     int    i = 0, len = self->count;
     while (i < len && arr[i] != ptr)
     {
         i += 1;
     }
     if (i < len)                // arr[i] == p
     // for (len = self->count -= 1; i < len; i += 1) arr[i] = arr[i + 1];
     {
         byte *src   = (byte *)(arr + i);
         int   size  = self->size;
         int   count = self->count -= 1;
         Mem.Memmove(src, src + size, (count - i) * size);
     }
                 #if FDB
     else
     {
         Fdb.Error("{0:X} does not exist in PtrLst {1:X}", (ulong)ptr, (ulong)self);
     }
     Should.Equal("self->count", self->count, oldCount - 1);
                 #endif
 }
Пример #2
0
 public static void Init(PtrIntDict *self)
 {
                 #if FDB
     Should.NotNull("self", self);
     self->type = Type;
                 #endif
     self->tag = Tag.PtrIntDict;
     int level = self->level = 0;
     int len   = self->len = Const.Lens[level];
     self->count = 0;
     self->free  = 0;
     // | (Entry)entries... | (int)arr... |
     // used entry: next: next entry in the bucket
     // free entry: next: next free entry
     int    EntrySize = Const.EntrySize;
     var    entries   = self->entries = (Entry *)Mem.Malloc(len * (EntrySize + IntSize));
     Entry *entry     = null;
     for (int i = 0; i < len; i += 1)
     {
         entry       = entries + i;
         entry->val  = null;
         entry->next = i + 1;
     }
     entry->next = -1;              // the last free entry
     int *arr = self->arr = (int *)((byte *)entries + len * EntrySize);
     for (int i = 0; i < len; i += 1)
     {
         arr[i] = -1;
     }
 }
Пример #3
0
        public static void Init(Pool *self, int len)
        {
                        #if FDB
            Should.NotNull("self", self);
            Should.GreaterThanZero("len", len);
            self->type = Type;
                        #endif
            self->len = len;
            byte *arr = self->arr = (byte *)Mem.Malloc(len);
            self->shift = 0;

            // sentinel
            int *head = (int *)arr;
            head[0] = -1;                  // sentinelHead.prev = -1;
            head[1] = HeadSize + TailSize; // sentinelhead.next = HeadSize + TailSize;
            head[2] = 0;                   // sentinelHead.size = 0;
            head[3] = -1;                  // sentinelTail.size = -1;  // to prevent merging
//			Fdb.Dump(arr, len);
            //               sentinel              firstFree             sentinel
            int size = len - HeadSize - TailSize - HeadSize - TailSize - HeadSize;
            SetFreeMeta((int *)(arr + HeadSize + TailSize), 0, -1, size);

            // sentinel
            head    = (int *)(arr + len - HeadSize);
            head[0] = -1;              // prev = -1 will prevent merging
            head[1] = -1;
            head[2] = 0;

            PtrLst.Init(&self->dependentLst);
                        #if FDB
            Verify(self);
                        #endif
        }
Пример #4
0
 public static void FillUvs(TpSpriteMeta *self, float *uvs)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.NotNull("uvs", uvs);
     Should.TypeEqual("self", self->type, Type);
     Should.NotNull("self->atlas", self->atlas);
     Should.TypeEqual("self->atlas->type", self->atlas->type, TpAtlasMeta.Type);
                 #endif
     float *size = self->atlas->size;
     float  invSizeX = 1 / size[0], invSizeY = 1 / size[1];
     float *uv = self->uv;
     float  uvX = uv[0], uvY = uv[1], uvW = uv[2], uvH = uv[3];
     if (self->rotated)
     {
         Vec2.Set(uvs, (uvX + uvW) * invSizeX, -uvY * invSizeY);
         Vec2.Set(uvs + 2, (uvX + uvW) * invSizeX, (-uvY - uvH) * invSizeY);
         Vec2.Set(uvs + 4, uvX * invSizeX, (-uvY - uvH) * invSizeY);
         Vec2.Set(uvs + 6, uvX * invSizeX, -uvY * invSizeY);
     }
     else
     {
         Vec2.Set(uvs, uvX * invSizeX, -uvY * invSizeY);
         Vec2.Set(uvs + 2, (uvX + uvW) * invSizeX, -uvY * invSizeY);
         Vec2.Set(uvs + 4, (uvX + uvW) * invSizeX, (-uvY - uvH) * invSizeY);
         Vec2.Set(uvs + 6, uvX * invSizeX, (-uvY - uvH) * invSizeY);
     }
 }
Пример #5
0
 public static void Clear(PtrLst *self)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
                 #endif
     self->count = 0;
 }
Пример #6
0
 public static void SetTint(TpSprite *self, float r, float g, float b)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
                 #endif
     Vec3.Set(self->color, r, g, b);
 }
Пример #7
0
 public static void SetAlpha(TpSprite *self, float a)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
                 #endif
     self->color[3] = a;
 }
Пример #8
0
 public static void QuickSort(void **arr, int len, Cmp cmp)
 {
                 #if FDB
     Should.NotNull("arr", arr);
     Should.GreaterThanZero("len", len);
     Should.NotNull("cmp", cmp);
                 #endif
     QuickSort(arr, 0, len - 1, cmp);
 }
Пример #9
0
 public static void SetRotation(TpSprite *self, float rotation)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
                 #endif
     self->rot = rotation;
     self->isTransformDirty = true;
 }
Пример #10
0
 public static void SetScale(TpSprite *self, float x, float y)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
                 #endif
     Vec2.Set(self->scl, x, y);
     self->isTransformDirty = true;
 }
Пример #11
0
 public static void SetPosition(TpSprite *self, float x, float y, float z)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
                 #endif
     Vec3.Set(self->pos, x, y, z);
     self->isTransformDirty = true;
 }
Пример #12
0
 public static int BinarySearch(void **arr, int len, void *val, Cmp cmp)
 {
                 #if FDB
     Should.NotNull("arr", arr);
     Should.GreaterThanZero("len", len);
     Should.NotNull("cmp", cmp);
                 #endif
     return(BinarySearch(arr, 0, len - 1, val, cmp));
 }
Пример #13
0
 /**
  * | -1 | -1 | size | data... | -1 |
  *                  | size    |
  */
 static void SetUsedMeta(int *head, int size)
 {
                 #if FDB
     Should.NotNull("head", head);
     Should.GreaterThanZero("size", size);
                 #endif
     head[0] = -1; head[1] = -1; head[2] = size;
     int *tail = (int *)((byte *)(head + 3) + size);
     tail[0] = -1;
 }
Пример #14
0
        public static void Verify(PtrLst *self)
        {
            Should.NotNull("self", self);
            Should.TypeEqual("self", self->type, Type);
            int len = Mem.Verify(self->arr) / sizeof(void *);

            Should.Equal("self->len", self->len, len);
            Should.InRange("self->count", self->count, 0, self->len);
            Should.Equal("self->size", self->size, sizeof(void *));
        }
Пример #15
0
 public static void MergeSort(void **arr, int len, Cmp cmp)
 {
                 #if FDB
     Should.NotNull("arr", arr);
     Should.GreaterThanZero("len", len);
     Should.NotNull("cmp", cmp);
                 #endif
     void **temp = stackalloc void *[len];
     MergeSort(arr, temp, 0, len - 1, cmp);
 }
Пример #16
0
        public static void Draw(void *node, float *parentMat, bool isParentTransformDirty)
        {
                        #if FDB
            Should.NotNull("node", node);
                        #endif
            switch (*(int *)node)
            {
            case Tag.TpSprite: TpSprite.Draw((TpSprite *)node, parentMat, isParentTransformDirty); return;

            case Tag.Group: Group.Draw((Group *)node, parentMat, isParentTransformDirty); return;
            }
        }
Пример #17
0
 /**
  * | prev | next | size | data... | size |
  *                      | size    |
  */
 static void SetFreeMeta(int *head, int prev, int next, int size)
 {
                 #if FDB
     Should.NotNull("head", head);
     Should.GreaterThanOrEqualTo("prev", prev, -1);
     Should.GreaterThanOrEqualTo("next", next, -1);
     Should.GreaterThanZero("size", size);
                 #endif
     head[0] = prev; head[1] = next; head[2] = size;
     int *tail = (int *)((byte *)(head + 3) + size);
     tail[0] = size;
 }
Пример #18
0
 public static void Init(PtrLst *self, int len)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.GreaterThanZero("len", len);
     self->type = Type;
                 #endif
     self->tag   = Tag.PtrLst;
     self->len   = len;
     self->count = 0;
     int size = self->size = sizeof(void *);
     self->arr = (void **)Mem.Malloc(len * size);
 }
Пример #19
0
        public static void Verify(PtrIntDict *self)
        {
            Should.NotNull("self", self);
            Should.InRange("self->level", self->level, 0, Const.Lens.Length - 1);
            Should.Equal("self->len", self->len, Const.Lens[self->level]);
            Should.InRange("self->count", self->count, 0, self->len);
            Should.InRange("self->free", self->free, -1, self->len - 1);
            Mem.Verify(self->entries);
            Should.NotNull("self->arr", self->arr);

            int len   = self->len;
            int count = self->count;
            int j     = 0;

            for (int i = 0; i < len; i += 1)
            {
                var entry = self->entries + i;
                if (entry->val != null)                    // a real key
                {
                    j += 1;
                }
            }
            Should.Equal("j", j, count);

            int freeCount = len - count;
            int free      = self->free;

            while (free != -1)
            {
                freeCount -= 1;
                free       = self->entries[free].next;
            }
            Should.Zero("freeCount", freeCount);

            j = 0;
            for (int i = 0; i < len; i += 1)
            {
                int idx = self->arr[i];
                while (idx != -1)
                {
                    var entry = self->entries + idx;
                    Should.Equal("entry->hash % len", (uint)entry->hash % len, i);
                    j  += 1;
                    idx = entry->next;
                }
            }
//			Fdb.Dump(self->arr, self->len * IntSize);
//			Fdb.Dump(self->entries, self->len * EntrySize, EntrySize);
            Should.Equal("j", j, count);
        }
Пример #20
0
        public static void Draw(TpSprite *self, float *parentMat, bool isParentTransformDirty)
        {
                        #if FDB
            Should.NotNull("self", self);
            Should.TypeEqual("self", self->type, Type);
            Should.NotNull("self->spriteMeta", self->spriteMeta);
                        #endif
            var bat = DrawCtx.GetBatch(self->spriteMeta->atlas->name);
            int vertIdx = bat.vertCount, triIdx = bat.triCount;
            bat.RequestQuota(4, 6);

            float *verts = self->verts;
            float *uvs   = self->uvs;

            if (self->isTransformDirty)
            {
                float *mat = stackalloc float[6];
                Mat2D.FromScalingRotationTranslation(mat, self->pos, self->scl, self->rot);
                TpSpriteMeta.FillQuad(self->spriteMeta, mat, self->verts);
            }

            var   bVerts = bat.verts; var bUvs = bat.uvs;
            float z = self->pos[2];
            bVerts[vertIdx].Set(verts[0], verts[1], z);
            bVerts[vertIdx + 1].Set(verts[2], verts[3], z);
            bVerts[vertIdx + 2].Set(verts[4], verts[5], z);
            bVerts[vertIdx + 3].Set(verts[6], verts[7], z);

            bUvs[vertIdx].Set(uvs[0], uvs[1]);
            bUvs[vertIdx + 1].Set(uvs[2], uvs[3]);
            bUvs[vertIdx + 2].Set(uvs[4], uvs[5]);
            bUvs[vertIdx + 3].Set(uvs[6], uvs[7]);

            float *color   = self->color;
            var    bColor  = Vec4.Color(color, 0.5f);
            var    bColors = bat.colors;
            bColors[vertIdx]     = bColor;
            bColors[vertIdx + 1] = bColor;
            bColors[vertIdx + 2] = bColor;
            bColors[vertIdx + 3] = bColor;

            var bTris = bat.tris;
            bTris[triIdx]     = vertIdx;
            bTris[triIdx + 1] = vertIdx + 1;
            bTris[triIdx + 2] = vertIdx + 2;
            bTris[triIdx + 3] = vertIdx;
            bTris[triIdx + 4] = vertIdx + 2;
            bTris[triIdx + 5] = vertIdx + 3;
        }
Пример #21
0
        public static TpAtlasMeta *Init(TpAtlasMeta *self, string str)
        {
                        #if FDB
            Should.NotNull("self", self);
            Should.NotNullOrEmpty("str", str);
            self->type = Type;
                        #endif
            string[] segs = str.Split(',');
            int *    nums = stackalloc int[segs.Length];
            for (int j = 0, end = segs.Length; j < end; j += 1)
            {
                nums[j] = int.Parse(segs[j]);
            }

            int i = 0;
            self->name        = nums[i++];
            self->size[0]     = nums[i++];
            self->size[1]     = nums[i++];
            self->spriteCount = nums[i++];
            self->sprites     = (TpSpriteMeta *)Mem.Malloc(self->spriteCount * sizeof(TpSpriteMeta));
            for (int j = 0, end = self->spriteCount; j < end; j += 1)
            {
                var sprite = self->sprites + j;
                                #if FDB
                sprite->type = TpSpriteMeta.Type;
                                #endif
                sprite->atlas     = self;
                sprite->name      = nums[i++];
                sprite->rotated   = nums[i++] != 0;
                sprite->size[0]   = nums[i++];
                sprite->size[1]   = nums[i++];
                sprite->pivot[0]  = nums[i++];
                sprite->pivot[1]  = nums[i++];
                sprite->quad[0]   = nums[i++];
                sprite->quad[1]   = nums[i++];
                sprite->quad[2]   = nums[i++];
                sprite->quad[3]   = nums[i++];
                sprite->uv[0]     = nums[i++];
                sprite->uv[1]     = nums[i++];
                sprite->uv[2]     = nums[i++];
                sprite->uv[3]     = nums[i++];
                sprite->border[0] = nums[i++];
                sprite->border[1] = nums[i++];
                sprite->border[2] = nums[i++];
                sprite->border[3] = nums[i++];
            }

            return(self);
        }
Пример #22
0
 /**
  * | head    | data... | tail | rightHead | data...   | rightTail |
  *           | size    |                  | rightSize |
  * | newHead | data...                                | tail      |
  *           | newSize                                |
  * assume head is free and linked
  */
 static void MergeRight(byte *arr, int *head)
 {
                 #if FDB
     Should.NotNull("arr", arr);
     Should.NotNull("head", head);
                 #endif
     int  size      = head[2];
     int *rightHead = (int *)((byte *)head + HeadSize + size + TailSize);
     if (rightHead[0] == -1)
     {
         return;                                  // since only the left most sentinel has head.prev = -1, we can check this to see if the node is used
     }
     RemoveFromFreeList(arr, rightHead);
     SetFreeMeta(head, size + TailSize + HeadSize + rightHead[2]);              // do not need to insert since head is already in free list
 }
Пример #23
0
 static void RemoveFromFreeList(byte *arr, int *head)
 {
                 #if FDB
     Should.NotNull("arr", arr);
     Should.NotNull("head", head);
                 #endif
     int prev = head[0], next = head[1];
     if (prev != -1)
     {
         ((int *)(arr + prev))[1] = next;
     }
     if (next != -1)
     {
         ((int *)(arr + next))[0] = prev;
     }
 }
Пример #24
0
 public static void Decon(TpAtlasMeta *self)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.TypeEqual("self", self->type, Type);
     Should.NotNull("self->sprites", self->sprites);
     self->type = Fdb.NullType;
     for (int j = 0, end = self->spriteCount; j < end; j += 1)
     {
         var sprite = self->sprites + j;
         Should.TypeEqual("sprite->type", sprite->type, TpSpriteMeta.Type);
         sprite->type = Fdb.NullType;
     }
                 #endif
     self->name = -1;
     Mem.Free(self->sprites); self->sprites = null;
 }
Пример #25
0
        /**
         * | leftHead | data...  | leftTail | head | data... | tail    |
         *            | leftSize |                 | size    |
         * | newHead  | data...                              | newTail |
         *            | newSize                              |
         * assume the head is free and linked
         */
        static int *MergeLeft(byte *arr, int *head)
        {
                        #if FDB
            Should.NotNull("arr", arr);
            Should.NotNull("head", head);
                        #endif
            int *leftTail = head - 1;
            int  leftSize = *leftTail;
            if (leftSize == -1)
            {
                return(head);
            }

            RemoveFromFreeList(arr, head);
            int *leftHead = (int *)((byte *)leftTail - leftSize - HeadSize);
            SetFreeMeta(leftHead, leftSize + TailSize + HeadSize + head[2]);
            return(leftHead);
        }
Пример #26
0
 // v0 - v1
 // |  \ |
 // v3 - v2
 public static void FillQuad(TpSpriteMeta *self, float *mat, float *verts)
 {
                 #if FDB
     Should.NotNull("self", self);
     Should.NotNull("verts", verts);
     Should.NotNull("mat", mat);
     Should.TypeEqual("self", self->type, Type);
     Should.NotNull("self->atlas", self->atlas);
     Should.TypeEqual("self->atlas->type", self->atlas->type, TpAtlasMeta.Type);
                 #endif
     float *pivot = self->pivot;
     float  pivotX = pivot[0], pivotY = pivot[1];
     float *quad = self->quad;
     float  quadX = quad[0], quadY = quad[1], quadW = quad[2], quadH = quad[3];
     Vec2.TransformMat2D(verts, mat, -pivotX + quadX, pivotY - quadY);
     Vec2.TransformMat2D(verts + 2, mat, -pivotX + quadX + quadW, pivotY - quadY);
     Vec2.TransformMat2D(verts + 4, mat, -pivotX + quadX + quadW, pivotY - quadY - quadH);
     Vec2.TransformMat2D(verts + 6, mat, -pivotX + quadX, pivotY - quadY - quadH);
 }
Пример #27
0
        public static void Init(TpSprite *self, TpSpriteMeta *spriteMeta)
        {
                        #if FDB
            Should.NotNull("self", self);
            Should.NotNull("spriteMeta", spriteMeta);
            self->type = Type;
                        #endif
            self->tag = Tag.TpSprite;

            Vec3.Zero(self->pos);
            Vec2.One(self->scl);
            self->rot = 0;
            self->isTransformDirty = true;              // delay regen verts to first Draw

            Vec4.Set(self->color, 1, 1, 1, 0);
            TpSpriteMeta.FillUvs(spriteMeta, self->uvs);

            self->spriteMeta = spriteMeta;
        }
Пример #28
0
        /**
         * | 0 | firstFreeHead.next | size | data... | size |
         *                                 | size    |
         */
        static void SetFreeMetaAndInsert(byte *arr, int *head, int size)
        {
                        #if FDB
            Should.NotNull("arr", arr);
            Should.NotNull("head", head);
            Should.GreaterThanZero("size", size);
                        #endif
            int *firstFreeHead = (int *)arr;
            int  firstFreeHeadNext;
            head[0] = 0; firstFreeHeadNext = head[1] = firstFreeHead[1]; head[2] = size;

            int pos = (int)((byte *)head - arr);
            if (firstFreeHeadNext != -1)
            {
                *(int *)(arr + firstFreeHeadNext) = pos; // firstFreeHead.next.prev = head
            }
            firstFreeHead[1] = pos;                      // firstFreeHead.next = head
            int *tail = (int *)((byte *)(head + 3) + size);
            tail[0] = size;
        }
Пример #29
0
        public static void Verify(Pool *self)
        {
            Should.NotNull("self", self);
            Should.TypeEqual("self", self->type, Type);

            Should.GreaterThanZero("self->len", self->len);
            Should.Equal("self->HeadSize", HeadSize, 3 * sizeof(int));
            Should.Equal("self->TailSize", TailSize, sizeof(int));

            int len = Mem.Verify(self->arr);

            Should.Equal("self->len", self->len, len);

//			Fdb.Dump(self->arr, len);

            byte *arr = self->arr;
            int * head;

            head = (int *)(arr + self->len - HeadSize);
            Should.Equal("endHead->prev", head[0], -1);             // head.prev = -1
            Should.Equal("endHead->next", head[1], -1);             // head.next = -1
            Should.Equal("endHead->size", head[2], 0);              // head.size = 0

            head = (int *)arr;
            Should.Equal("firstHead->prev", head[0], -1);             // head.prev = -1
            Should.Equal("firstHead->size", head[2], 0);              // head.size = 0
            Should.Equal("firstTail->size", head[3], -1);             // tail.size = -1

            int curFree = head[1], lastFree = 0;
            var dict = new System.Collections.Generic.Dictionary <int, int>();

            while (curFree != -1)
            {
                head = (int *)(arr + curFree);
                Should.Equal("head" + curFree + "->prev", head[0], lastFree);
                Should.Equal("tail->size", *(int *)((byte *)head + HeadSize + head[2]), head[2]);
                dict.Add(curFree, head[2]);
                lastFree = curFree;
                curFree  = head[1];
            }

            head = (int *)(arr + HeadSize + TailSize);
            int *end = (int *)(arr + self->len);

            while (head < end)
            {
                int  pos = (int)((byte *)head - self->arr);
                int  prev = head[0], next = head[1], size = head[2];
                int *tail = (int *)((byte *)head + HeadSize + size);

                if (tail < end)
                {
                    int tailVal = tail[0];
                    if (tailVal == -1)                        // in use
                    {
                        Should.False("dict.ContainsKey(pos)", dict.ContainsKey(pos));
                        Should.Equal("prev", prev, -1);
                        Should.Equal("next", next, -1);
                        Should.GreaterThanZero("size", size);
                    }
                    else                          // free
                    {
                        Should.True("dict.ContainsKey(pos)" + pos, dict.ContainsKey(pos));
                        Should.GreaterThanOrEqualTo("prev", prev, 0);
                        Should.GreaterThanOrEqualTo("next", next, -1);
                        Should.Equal("size", size, dict[pos]);
                        dict.Remove(pos);
                    }
                }
                else                      // head is end sentinel, no tail
                {
                    Should.Equal("head", head, (int *)(arr + len - HeadSize));
                    Should.Equal("endHead->prev", head[0], -1);                     // head.prev = -1
                    Should.Equal("endHead->next", head[1], -1);                     // head.next = -1
                    Should.Equal("endHead->size", head[2], 0);                      // head.size = 0
                }

                head = (int *)((byte *)head + HeadSize + size + TailSize);
            }
            Should.Zero("dict.Count", dict.Count);
        }
Пример #30
0
        public static void Set(PtrIntDict *self, int hash, void *val)
        {
                        #if FDB
            Verify(self);
            Should.NotNull("val", val);
                        #endif
            int *  arr = self->arr;
            long   mod = (uint)hash % self->len;
            int    idx = arr[mod], cur = idx;
            var    entries = self->entries;
            Entry *entry   = null;
            while (cur != -1)
            {
                entry = entries + cur;
                if (entry->hash == hash)                    // found the key
                {
                    entry->val = val;
                                        #if FDB
                    Verify(self);
                                        #endif
                    return;
                }
                cur = entry->next;
            }

            // find a free entry
            int free = self->free;
            if (free == -1)                // expand
            {
                int level  = self->level += 1;
                int oldLen = self->len;
                int len    = self->len = Const.Lens[level];

                // rehash
                int EntrySize = Const.EntrySize;
                entries = self->entries = (Entry *)Mem.Realloc(entries, len * (EntrySize + IntSize));
                arr     = self->arr = (int *)((byte *)entries + len * EntrySize);
                for (int i = 0; i < len; i += 1)
                {
                    arr[i] = -1;                                               // clear the buckets
                }
                for (int i = 0; i < oldLen; i += 1)
                {
                    entries[i].next = -1;                              // clear old links
                }
                for (int i = 0; i < oldLen; i += 1)                    // insert all old entries
                {
                    entry       = entries + i;
                    mod         = (uint)entry->hash % len;
                    entry->next = arr[mod];
                    arr[mod]    = i;
                }

                // link all new entries
                self->free = oldLen + 1;                  // point to new allocated entries
                for (int i = oldLen + 1; i < len; i += 1)
                {
                    entry       = entries + i;
                    entry->val  = null;
                    entry->next = i + 1;
                }
                entry->next = -1;                  // the last free entry

                entry = entries + oldLen;
                idx   = arr[mod = (uint)hash % len];                // different idx after expand
                free  = oldLen;
            }
            else
            {
                entry      = entries + free;
                self->free = entry->next;
            }

            entry->hash = hash;
            entry->next = idx;
            entry->val  = val;
            arr[mod]    = free;

            self->count += 1;
                        #if FDB
            Verify(self);
                        #endif
        }