예제 #1
0
        public static UnsafeHashSet *Allocate <T>(int capacity, bool fixedSize = false)
            where T : unmanaged, IEquatable <T>
        {
            var valStride   = sizeof(T);
            var entryStride = sizeof(UnsafeHashCollection.Entry);

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

            var valAlignment = Memory.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   = Memory.RoundToAlignment(valStride, alignment);
            entryStride = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry), alignment);

            // dictionary ptr
            UnsafeHashSet *set;

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

                // allocate memory
                var ptr = Memory.MallocAndZero(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 = Memory.MallocAndZero <UnsafeHashSet>();
                set->_collection.Buckets = (UnsafeHashCollection.Entry * *)Memory.MallocAndZero(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;
            set->_typeHandle           = typeof(T).TypeHandle.Value;

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

            // We need to grab the pext prime, so at least current length + 1
            var capacity = GetNextPrime(collection->Entries.Length + 1);

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

            var newBuckets = (Entry **)Memory.MallocAndZero(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
            Memory.Free(collection->Buckets);
            UnsafeBuffer.Free(&collection->Entries);

            // new storage
            collection->Buckets = newBuckets;
            collection->Entries = newEntries;
        }
        int                     _valueOffset;     // Readonly

        public static UnsafeSortedDictionary *Allocate <K, V>(int capacity, bool fixedSize = false)
            where K : unmanaged, IComparable <K>
            where V : unmanaged
        {
            var keyStride   = sizeof(K);
            var valStride   = sizeof(V);
            var entryStride = sizeof(UnsafeHashCollection.Entry);

            var keyAlignment = Memory.GetAlignment(keyStride);
            var valAlignment = Memory.GetAlignment(valStride);

            var alignment = Math.Max(UnsafeHashCollection.Entry.ALIGNMENT, Math.Max(keyAlignment, valAlignment));

            keyStride   = Memory.RoundToAlignment(keyStride, alignment);
            valStride   = Memory.RoundToAlignment(valStride, alignment);
            entryStride = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry), alignment);

            var totalStride = keyStride + valStride + entryStride;

            UnsafeSortedDictionary *map;

            if (fixedSize)
            {
                var sizeOfHeader        = Memory.RoundToAlignment(sizeof(UnsafeDictionary), alignment);
                var sizeOfBucketsBuffer = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry * *) * capacity, alignment);
                var sizeofEntriesBuffer = totalStride * capacity;

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

                map = (UnsafeSortedDictionary *)ptr;
                UnsafeBuffer.InitFixed(&map->_collection.Entries, (byte *)ptr + (sizeOfHeader + sizeOfBucketsBuffer), capacity, totalStride);
            }
            else
            {
                map = Memory.MallocAndZero <UnsafeSortedDictionary>();
                UnsafeBuffer.InitDynamic(&map->_collection.Entries, capacity, totalStride);
            }

            // header init
            map->_collection.FreeCount = 0;
            map->_collection.UsedCount = 0;
            map->_collection.KeyOffset = entryStride;
            map->_typeHandleKey        = typeof(K).TypeHandle.Value;
            map->_typeHandleValue      = typeof(V).TypeHandle.Value;

            map->_valueOffset = entryStride + keyStride;

            return(map);
        }
예제 #4
0
        public static UnsafeSortedSet *Allocate <T>(int capacity, bool fixedSize = false)
            where T : unmanaged, IComparable <T>
        {
            var valStride    = sizeof(T);
            var entryStride  = sizeof(UnsafeOrderedCollection.Entry);
            var valAlignment = Memory.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   = Memory.RoundToAlignment(valStride, alignment);
            entryStride = Memory.RoundToAlignment(entryStride, alignment);

            // dictionary ptr
            UnsafeSortedSet *set;

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

                // allocate memory
                var ptr = Memory.MallocAndZero(sizeOfHeader + sizeofEntriesBuffer, alignment);

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

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

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

            set->_collection.FreeCount = 0;
            set->_collection.UsedCount = 0;
            set->_collection.KeyOffset = entryStride;
            set->_typeHandle           = typeof(T).TypeHandle.Value;

            return(set);
        }
        public static UnsafeStack *Allocate <T>(int capacity, bool fixedSize = false) where T : unmanaged
        {
            if (capacity < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), string.Format(ThrowHelper.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
            }

            var          stride = sizeof(T);
            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 = Memory.GetAlignment(stride);

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

                // allocate memory for stack and array with the correct alignment
                var ptr = Memory.MallocAndZero(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 = Memory.MallocAndZero <UnsafeStack>();

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

            // just safety, make sure count is 0
            stack->_count      = 0;
            stack->_typeHandle = typeof(T).TypeHandle.Value;

            return(stack);
        }
예제 #6
0
        public static void SetCapacity(UnsafeList *list, int capacity)
        {
            UDebug.Assert(list != null);
            UDebug.Assert(list->_items.Ptr != null);
            UDebug.Assert(capacity > 0);

            if (list->_items.Dynamic == 0)
            {
                throw new InvalidOperationException(ThrowHelper.InvalidOperation_CollectionFull);
            }

            // no change in capacity
            if (capacity == list->_items.Length)
            {
                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;
        }
        static void Expand(UnsafeOrderedCollection *collection)
        {
            UDebug.Assert(collection->Entries.Dynamic == 1);
            UDebug.Assert(collection->FreeCount == 0);
            UDebug.Assert(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;
        }
예제 #8
0
        public static UnsafeQueue *Allocate <T>(int capacity, bool fixedSize = false) where T : unmanaged
        {
            if (capacity < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), string.Format(ThrowHelper.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
            }

            int stride = sizeof(T);

            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   = Memory.GetAlignment(stride);
                var sizeOfQueue = Memory.RoundToAlignment(sizeof(UnsafeQueue), alignment);
                var sizeOfArray = stride * capacity;

                var ptr = Memory.MallocAndZero(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 = Memory.MallocAndZero <UnsafeQueue>();

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

            queue->_head       = 0;
            queue->_tail       = 0;
            queue->_count      = 0;
            queue->_typeHandle = typeof(T).TypeHandle.Value;

            return(queue);
        }
        private static void Expand(UnsafeStack *stack)
        {
            // new buffer for elements
            UnsafeBuffer newItems = default;

            // initialize to double size of existing one
            int newSize = stack->_items.Length == 0 ? DEFAULT_CAPACITY : stack->_items.Length * 2;

            UnsafeBuffer.InitDynamic(&newItems, newSize, 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;
        }
예제 #10
0
        public static UnsafeList *Allocate <T>(int capacity, bool fixedSize = false) where T : unmanaged
        {
            if (capacity < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), string.Format(ThrowHelper.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
            }

            int stride = sizeof(T);

            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 = Memory.GetAlignment(stride);

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

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

                // 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 = Memory.MallocAndZero <UnsafeList>();

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

            list->_count      = 0;
            list->_typeHandle = typeof(T).TypeHandle.Value;
            return(list);
        }
예제 #11
0
        static void Expand(UnsafeQueue *queue, int capacity)
        {
            UDebug.Assert(capacity > 0);

            // queue has to be dynamic and capacity we're going to have to be larger
            UDebug.Assert(queue->_items.Dynamic == 1);
            UDebug.Assert(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;
        }
예제 #12
0
        int                  _valueOffset;     // Readonly

        public static UnsafeDictionary *Allocate <K, V>(int capacity, bool fixedSize = false)
            where K : unmanaged, IEquatable <K>
            where V : unmanaged
        {
            var keyStride   = sizeof(K);
            var valStride   = sizeof(V);
            var entryStride = sizeof(UnsafeHashCollection.Entry);

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

            var keyAlignment = Memory.GetAlignment(keyStride);
            var valAlignment = Memory.GetAlignment(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   = Memory.RoundToAlignment(keyStride, alignment);
            valStride   = Memory.RoundToAlignment(valStride, alignment);
            entryStride = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry), alignment);

            // map ptr
            UnsafeDictionary *map;

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

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

                // start of memory is the dict itself
                map = (UnsafeDictionary *)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 = Memory.MallocAndZero <UnsafeDictionary>();
                map->_collection.Buckets = (UnsafeHashCollection.Entry * *)Memory.MallocAndZero(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->_typeHandleKey        = typeof(K).TypeHandle.Value;
            map->_typeHandleValue      = typeof(V).TypeHandle.Value;

            map->_valueOffset = entryStride + keyStride;

            return(map);
        }