Exemple #1
0
        public static void SetCapacity(UnsafeList *list, int capacity)
        {
            Assert.Check(list != null);

            if (list->_items.Dynamic == false)
            {
                throw new InvalidOperationException(LIST_FIXED_CANT_CHANGE_CAPACITY);
            }

            // no change in capacity
            if (capacity == list->_items.Length)
            {
                return;
            }

            // tried to set to zero or negative, so free items
            if (capacity <= 0)
            {
                // have to make sure to set count to 0
                list->_count = 0;

                // and clear memory for items
                if (list->_items.Ptr != null)
                {
                    UnsafeBuffer.Free(&list->_items);
                }

                return;
            }

            // allocate new items
            UnsafeBuffer newItems = default;

            UnsafeBuffer.InitDynamic(&newItems, capacity, list->_items.Stride);

            // if have anything in list, copy it
            if (list->_count > 0)
            {
                // also make sure that count is
                // not larger than the new capacity
                if (list->_count > capacity)
                {
                    list->_count = capacity;
                }

                // copy over elements
                UnsafeBuffer.Copy(list->_items, 0, newItems, 0, list->_count);
            }

            // if an existing buffer was here, free it
            if (list->_items.Ptr != null)
            {
                UnsafeBuffer.Free(&list->_items);
            }

            // assign new buffer
            list->_items = newItems;
        }
        public static UnsafeHashSet *Allocate(int capacity, int valStride, bool fixedSize = false)
        {
            var entryStride = sizeof(UnsafeHashCollection.Entry);

            // round capacity up to next prime
            capacity = UnsafeHashCollection.GetNextPrime(capacity);

            // this has to be true
            Assert.Check(entryStride == 16);

            var valAlignment = Native.GetAlignment(valStride);

            // the alignment for entry/key/val, we can't have less than ENTRY_ALIGNMENT
            // bytes alignment because entries are 16 bytes with 1 x pointer + 2 x 4 byte integers
            var alignment = Math.Max(UnsafeHashCollection.Entry.ALIGNMENT, valAlignment);

            // calculate strides for all elements
            valStride   = Native.RoundToAlignment(valStride, alignment);
            entryStride = Native.RoundToAlignment(sizeof(UnsafeHashCollection.Entry), alignment);

            // dictionary ptr
            UnsafeHashSet *set;

            if (fixedSize)
            {
                var sizeOfHeader        = Native.RoundToAlignment(sizeof(UnsafeHashSet), alignment);
                var sizeOfBucketsBuffer = Native.RoundToAlignment(sizeof(UnsafeHashCollection.Entry * *) * capacity, alignment);
                var sizeofEntriesBuffer = (entryStride + valStride) * capacity;

                // allocate memory
                var ptr = Native.MallocAndClear(sizeOfHeader + sizeOfBucketsBuffer + sizeofEntriesBuffer, alignment);

                // start of memory is the dict itself
                set = (UnsafeHashSet *)ptr;

                // buckets are offset by header size
                set->_collection.Buckets = (UnsafeHashCollection.Entry * *)((byte *)ptr + sizeOfHeader);

                // initialize fixed buffer
                UnsafeBuffer.InitFixed(&set->_collection.Entries, (byte *)ptr + (sizeOfHeader + sizeOfBucketsBuffer), capacity, entryStride + valStride);
            }
            else
            {
                // allocate dict, buckets and entries buffer separately
                set = Native.MallocAndClear <UnsafeHashSet>();
                set->_collection.Buckets = (UnsafeHashCollection.Entry * *)Native.MallocAndClear(sizeof(UnsafeHashCollection.Entry * *) * capacity, sizeof(UnsafeHashCollection.Entry * *));

                // init dynamic buffer
                UnsafeBuffer.InitDynamic(&set->_collection.Entries, capacity, entryStride + valStride);
            }

            set->_collection.FreeCount = 0;
            set->_collection.UsedCount = 0;
            set->_collection.KeyOffset = entryStride;

            return(set);
        }
        static void Expand(UnsafeHashCollection *collection)
        {
            Assert.Check(collection->Entries.Dynamic == 1);

            var capacity = GetNextPrime(collection->Entries.Length);

            Assert.Check(capacity >= collection->Entries.Length);

            var newBuckets = (Entry **)Native.MallocAndClear(capacity * sizeof(Entry * *), sizeof(Entry * *));
            var newEntries = default(UnsafeBuffer);

            UnsafeBuffer.InitDynamic(&newEntries, capacity, collection->Entries.Stride);
            UnsafeBuffer.Copy(collection->Entries, 0, newEntries, 0, collection->Entries.Length);

            collection->FreeHead  = null;
            collection->FreeCount = 0;

            for (int i = collection->Entries.Length - 1; i >= 0; --i)
            {
                var entry = (Entry *)((byte *)newEntries.Ptr + (i * newEntries.Stride));
                if (entry->State == EntryState.Used)
                {
                    var bucketHash = entry->Hash % capacity;

                    // assign current entry in buckets as next
                    entry->Next = newBuckets[bucketHash];

                    // assign entry as new bucket head
                    newBuckets[bucketHash] = entry;
                }

                // entry is in free list
                else if (entry->State == EntryState.Free)
                {
                    // assign free list as next
                    entry->Next = collection->FreeHead;

                    // re-assign free list to entry
                    collection->FreeHead  = entry;
                    collection->FreeCount = collection->FreeCount + 1;
                }
            }

            // free old memory
            Native.Free(collection->Buckets);
            UnsafeBuffer.Free(&collection->Entries);

            // new storage
            collection->Buckets = newBuckets;
            collection->Entries = newEntries;
        }
        static void Expand(UnsafeStack *stack)
        {
            // new buffer for elements
            UnsafeBuffer newItems = default;

            // initialize to double size of existing one
            UnsafeBuffer.InitDynamic(&newItems, stack->_items.Length * 2, stack->_items.Stride);

            // copy memory over from previous items
            UnsafeBuffer.Copy(stack->_items, 0, newItems, 0, stack->_items.Length);

            // free old buffer
            UnsafeBuffer.Free(&stack->_items);

            // replace buffer with new
            stack->_items = newItems;
        }
Exemple #5
0
        public static UnsafeOrderedSet *Allocate(int capacity, int valStride, bool fixedSize = false)
        {
            var entryStride  = sizeof(UnsafeOrderedCollection.Entry);
            var valAlignment = Native.GetAlignment(valStride);

            // the alignment for entry/key/val, we can't have less than ENTRY_ALIGNMENT
            // bytes alignment because entries are 12 bytes with 3 x 32 bit integers
            var alignment = Math.Max(UnsafeOrderedCollection.Entry.ALIGNMENT, valAlignment);

            // calculate strides for all elements
            valStride   = Native.RoundToAlignment(valStride, alignment);
            entryStride = Native.RoundToAlignment(entryStride, alignment);

            // dictionary ptr
            UnsafeOrderedSet *set;

            if (fixedSize)
            {
                var sizeOfHeader        = Native.RoundToAlignment(sizeof(UnsafeOrderedSet), alignment);
                var sizeofEntriesBuffer = (entryStride + valStride) * capacity;

                // allocate memory
                var ptr = Native.MallocAndClear(sizeOfHeader + sizeofEntriesBuffer, alignment);

                // start of memory is the set itself
                set = (UnsafeOrderedSet *)ptr;

                // initialize fixed buffer
                UnsafeBuffer.InitFixed(&set->_collection.Entries, (byte *)ptr + sizeOfHeader, capacity, entryStride + valStride);
            }
            else
            {
                // allocate set separately
                set = Native.MallocAndClear <UnsafeOrderedSet>();

                // init dynamic buffer
                UnsafeBuffer.InitDynamic(&set->_collection.Entries, capacity, entryStride + valStride);
            }

            set->_collection.FreeCount = 0;
            set->_collection.UsedCount = 0;
            set->_collection.KeyOffset = entryStride;

            return(set);
        }
        static void Expand(UnsafeOrderedCollection *collection)
        {
            Assert.Check(collection->Entries.Dynamic == 1);
            Assert.Check(collection->FreeCount == 0);
            Assert.Check(collection->FreeHead == 0);

            var capacity   = collection->Entries.Length * 2;
            var newEntries = default(UnsafeBuffer);

            UnsafeBuffer.InitDynamic(&newEntries, capacity, collection->Entries.Stride);
            UnsafeBuffer.Copy(collection->Entries, 0, newEntries, 0, collection->Entries.Length);

            // free old memory
            UnsafeBuffer.Free(&collection->Entries);

            // new storage
            collection->Entries = newEntries;
        }
        static void ExpandHeap(UnsafeHeapMin *heap)
        {
            Assert.Check(heap->_items.Dynamic == 1);

            // new buffer for elements
            UnsafeBuffer newItems = default;

            // initialize to double size of existing one
            UnsafeBuffer.InitDynamic(&newItems, heap->_items.Length * 2, heap->_items.Stride);

            // copy memory over from previous items
            UnsafeBuffer.Copy(heap->_items, 0, newItems, 0, heap->_items.Length);

            // free old buffer
            UnsafeBuffer.Free(&heap->_items);

            // replace buffer with new
            heap->_items = newItems;
        }
        public static UnsafeStack *Allocate(int capacity, int stride, bool fixedSize = false)
        {
            Assert.Check(capacity > 0);
            Assert.Check(stride > 0);

            UnsafeStack *stack;

            // fixedSize stack means we are allocating the memory
            // for the stack header and the items in it as one block
            if (fixedSize)
            {
                var alignment = AllocHelper.GetAlignmentForArrayElement(stride);

                // align stack header size to the elements alignment
                var sizeOfStack = AllocHelper.RoundUpToAlignment(sizeof(UnsafeStack), alignment);
                var sizeOfArray = stride * capacity;

                // allocate memory for stack and array with the correct alignment
                var ptr = AllocHelper.MallocAndClear(sizeOfStack + sizeOfArray, alignment);

                // grab stack ptr
                stack = (UnsafeStack *)ptr;

                // initialize fixed buffer from same block of memory as the stack
                UnsafeBuffer.InitFixed(&stack->_items, (byte *)ptr + sizeOfStack, capacity, stride);
            }

            // dynamic sized stack means we're allocating the stack header
            // and its memory separately
            else
            {
                // allocate stack separately
                stack = AllocHelper.MallocAndClear <UnsafeStack>();

                // initialize dynamic buffer with separate memory
                UnsafeBuffer.InitDynamic(&stack->_items, capacity, stride);
            }

            // just safety, make sure count is 0
            stack->_count = 0;

            return(stack);
        }
        public static UnsafeHeapMax *Allocate(int capacity, int keyStride, int valStride, bool fixedSize = false)
        {
            capacity += 1;

            // get alignment for key/val
            var keyAlignment = Native.GetAlignment(keyStride);
            var valAlignment = Native.GetAlignment(valStride);

            // pick the max one as our alignment
            var alignment = Math.Max(keyAlignment, valAlignment);

            // align sizes to their respective alignments
            keyStride = Native.RoundToAlignment(keyStride, alignment);
            valStride = Native.RoundToAlignment(valStride, alignment);

            UnsafeHeapMax *heap;

            if (fixedSize)
            {
                var sizeOfHeader = Native.RoundToAlignment(sizeof(UnsafeHeapMax), alignment);
                var sizeOfBuffer = (keyStride + valStride) * capacity;

                var ptr = Native.MallocAndClear(sizeOfHeader + sizeOfBuffer, alignment);

                // heap pointer
                heap = (UnsafeHeapMax *)ptr;

                // initialize our fixed buffer
                UnsafeBuffer.InitFixed(&heap->_items, (byte *)ptr + sizeOfHeader, capacity, keyStride + valStride);
            }
            else
            {
                heap = Native.MallocAndClear <UnsafeHeapMax>();

                // dynamic buffer (separate memory)
                UnsafeBuffer.InitDynamic(&heap->_items, capacity, keyStride + valStride);
            }

            heap->_count     = 1;
            heap->_keyStride = keyStride;
            return(heap);
        }
        public static UnsafeQueue *Allocate(int capacity, int stride, bool fixedSize = false)
        {
            Assert.Check(capacity > 0);
            Assert.Check(stride > 0);

            UnsafeQueue *queue;

            // fixedSize queue means we are allocating the memory for the header and the items in it as one block
            if (fixedSize)
            {
                var alignment   = Native.GetAlignment(stride);
                var sizeOfQueue = Native.RoundToAlignment(sizeof(UnsafeQueue), alignment);
                var sizeOfArray = stride * capacity;

                var ptr = Native.MallocAndClear(sizeOfQueue + sizeOfArray, alignment);

                // cast ptr to queue
                queue = (UnsafeQueue *)ptr;

                // initialize fixed buffer from same block of memory as the stack
                UnsafeBuffer.InitFixed(&queue->_items, (byte *)ptr + sizeOfQueue, capacity, stride);
            }

            // dynamic sized queue means we're allocating the stack header and its memory separately
            else
            {
                // allocate memory for queue
                queue = Native.MallocAndClear <UnsafeQueue>();

                // initialize dynamic buffer with separate memory
                UnsafeBuffer.InitDynamic(&queue->_items, capacity, stride);
            }

            queue->_head  = 0;
            queue->_tail  = 0;
            queue->_count = 0;

            return(queue);
        }
        // expand algorithm from first answer here: https://codereview.stackexchange.com/questions/129819/queue-resizing-array-implementation
        static void Expand(UnsafeQueue *queue, int capacity)
        {
            Assert.Check(capacity > 0);

            // queue has to be dynamic and capacity we're going to have to be larger
            Assert.Check(queue->_items.Dynamic == 1);
            Assert.Check(queue->_items.Length < capacity);

            // new buffer for elements
            UnsafeBuffer newItems = default;

            // initialize to double size of existing one
            UnsafeBuffer.InitDynamic(&newItems, capacity, queue->_items.Stride);

            if (queue->_count > 0)
            {
                // when head is 'ahead' or at tail it means that we're wrapping around
                if (queue->_head >= queue->_tail)
                {
                    // so we need to copy head first, from (head, length-head) into (0, length-head)
                    UnsafeBuffer.Copy(queue->_items, queue->_head, newItems, 0, queue->_items.Length - queue->_head);

                    // and then copy tail, from (0, tail) into (length-head, tail)
                    UnsafeBuffer.Copy(queue->_items, 0, newItems, queue->_items.Length - queue->_head, queue->_tail);
                }
                else
                {
                    // if not, we can just copy from (tail, count) into (0, count)
                    UnsafeBuffer.Copy(queue->_items, queue->_head, newItems, 0, queue->_count);
                }
            }

            // free existing buffer
            UnsafeBuffer.Free(&queue->_items);

            queue->_items = newItems;
            queue->_head  = 0;
            queue->_tail  = queue->_count % queue->_items.Length;
        }
Exemple #12
0
        public static UnsafeList *Allocate(int capacity, int stride, bool fixedSize = false)
        {
            Assert.Check(capacity > 0);
            Assert.Check(stride > 0);

            UnsafeList *list;

            // fixedSize means we are allocating the memory for the collection header and the items in it as one block
            if (fixedSize)
            {
                var alignment = AllocHelper.GetAlignmentForArrayElement(stride);

                // align header size to the elements alignment
                var sizeOfHeader = AllocHelper.RoundUpToAlignment(sizeof(UnsafeList), alignment);
                var sizeOfBuffer = stride * capacity;

                // allocate memory for list and array with the correct alignment
                var ptr = AllocHelper.MallocAndClear(sizeOfHeader + sizeOfBuffer, alignment);

                // grab header ptr
                list = (UnsafeList *)ptr;

                // initialize fixed buffer from same block of memory as the collection, offset by sizeOfHeader
                UnsafeBuffer.InitFixed(&list->_items, (byte *)ptr + sizeOfHeader, capacity, stride);
            }
            else
            {
                // allocate collection separately
                list = AllocHelper.MallocAndClear <UnsafeList>();

                // initialize dynamic buffer with separate memory
                UnsafeBuffer.InitDynamic(&list->_items, capacity, stride);
            }

            list->_count = 0;
            return(list);
        }
Exemple #13
0
        internal static UnsafeOrderedCollection *Allocate(int capacity, int valStride)
        {
            var entryStride  = sizeof(Entry);
            var valAlignment = Native.GetAlignment(valStride);

            // alignment we need is max of the two alignments
            var alignment = Math.Max(Entry.ALIGNMENT, valAlignment);

            // calculate strides for all elements
            valStride   = Native.RoundToAlignment(valStride, alignment);
            entryStride = Native.RoundToAlignment(entryStride, alignment);

            // allocate dict, buckets and entries buffer separately
            var collection = Native.MallocAndClear <UnsafeOrderedCollection>();

            // init dynamic buffer
            UnsafeBuffer.InitDynamic(&collection->Entries, capacity, entryStride + valStride);

            collection->FreeCount = 0;
            collection->UsedCount = 0;
            collection->KeyOffset = entryStride;

            return(collection);
        }
Exemple #14
0
        public static UnsafeHashMap *Allocate(int capacity, int keyStride, int valStride, bool fixedSize = false)
        {
            var entryStride = sizeof(UnsafeHashCollection.Entry);

            // round capacity up to next prime
            capacity = UnsafeHashCollection.GetNextPrime(capacity);

            // this has to be true
            Assert.Check(entryStride == 16);

            var keyAlignment = AllocHelper.GetAlignmentForArrayElement(keyStride);
            var valAlignment = AllocHelper.GetAlignmentForArrayElement(valStride);

            // the alignment for entry/key/val, we can't have less than ENTRY_ALIGNMENT
            // bytes alignment because entries are 8 bytes with 2 x 32 bit integers
            var alignment = Math.Max(UnsafeHashCollection.Entry.ALIGNMENT, Math.Max(keyAlignment, valAlignment));

            // calculate strides for all elements
            keyStride   = AllocHelper.RoundUpToAlignment(keyStride, alignment);
            valStride   = AllocHelper.RoundUpToAlignment(valStride, alignment);
            entryStride = AllocHelper.RoundUpToAlignment(sizeof(UnsafeHashCollection.Entry), alignment);

            // map ptr
            UnsafeHashMap *map;

            if (fixedSize)
            {
                var sizeOfHeader        = AllocHelper.RoundUpToAlignment(sizeof(UnsafeHashMap), alignment);
                var sizeOfBucketsBuffer = AllocHelper.RoundUpToAlignment(sizeof(UnsafeHashCollection.Entry * *) * capacity, alignment);
                var sizeofEntriesBuffer = (entryStride + keyStride + valStride) * capacity;

                // allocate memory
                var ptr = AllocHelper.MallocAndClear(sizeOfHeader + sizeOfBucketsBuffer + sizeofEntriesBuffer, alignment);

                // start of memory is the dict itself
                map = (UnsafeHashMap *)ptr;

                // buckets are offset by header size
                map->_collection.Buckets = (UnsafeHashCollection.Entry * *)((byte *)ptr + sizeOfHeader);

                // initialize fixed buffer
                UnsafeBuffer.InitFixed(&map->_collection.Entries, (byte *)ptr + (sizeOfHeader + sizeOfBucketsBuffer), capacity, entryStride + keyStride + valStride);
            }
            else
            {
                // allocate dict, buckets and entries buffer separately
                map = AllocHelper.MallocAndClear <UnsafeHashMap>();
                map->_collection.Buckets = (UnsafeHashCollection.Entry * *)AllocHelper.MallocAndClear(sizeof(UnsafeHashCollection.Entry * *) * capacity, sizeof(UnsafeHashCollection.Entry * *));

                // init dynamic buffer
                UnsafeBuffer.InitDynamic(&map->_collection.Entries, capacity, entryStride + keyStride + valStride);
            }

            // header init
            map->_collection.FreeCount = 0;
            map->_collection.UsedCount = 0;
            map->_collection.KeyOffset = entryStride;

            map->_valueOffset = entryStride + keyStride;

            return(map);
        }