public static unsafe DynamicBuffer <T> GetBufferRO <T>(this EntityManager manager, Entity entity)
            where T : struct, IBufferElementData
        {
            var typeIndex = TypeManager.GetTypeIndex <T>();

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            manager.EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);
            if (!TypeManager.IsBuffer(typeIndex))
            {
                throw new ArgumentException(
                          $"GetBuffer<{typeof(T)}> may not be IComponentData or ISharedComponentData; currently {TypeManager.GetTypeInfo<T>().Category}");
            }
#endif

            manager.ComponentJobSafetyManager->CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header           = (BufferHeader *)manager.EntityComponentStore->GetComponentDataWithTypeRO(entity, typeIndex);
            int           internalCapacity = TypeManager.GetTypeInfo(typeIndex).BufferCapacity;

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            var isReadOnly = false; // @TODO FIXME! we need DynamicBuffer<T>.GetUnsafeReadOnlyPtr();
            return(new DynamicBuffer <T>(header, manager.ComponentJobSafetyManager->GetSafetyHandle(typeIndex, isReadOnly), manager.ComponentJobSafetyManager->GetBufferSafetyHandle(typeIndex), isReadOnly, internalCapacity));
#else
            return(new DynamicBuffer <T>(header, internalCapacity));
#endif
        }
Example #2
0
        //cm
        internal void AddBufferRaw(Entity entity, int componentTypeIndex, BufferHeader *tempBuffer)
        {
            EntityComponentStore->AssertEntityHasComponent(entity, componentTypeIndex);

            ComponentJobSafetyManager->CompleteReadAndWriteDependency(componentTypeIndex);

            var bufferHeader = (BufferHeader *)EntityComponentStore->GetComponentDataWithTypeRW(entity, componentTypeIndex,
                                                                                                EntityComponentStore->GlobalSystemVersion);

            var typeInfo    = TypeManager.GetTypeInfo(componentTypeIndex);
            var elementSize = typeInfo.ElementSize;
            var alignment   = typeInfo.AlignmentInBytes;

            var total = bufferHeader->Length + tempBuffer->Length;

            if (total > bufferHeader->Capacity)
            {
                BufferHeader.EnsureCapacity(bufferHeader, total, elementSize, alignment, BufferHeader.TrashMode.RetainOldData);
            }

            UnsafeUtility.MemCpy(
                BufferHeader.GetElementPointer(bufferHeader) + bufferHeader->Length * elementSize,
                BufferHeader.GetElementPointer(tempBuffer),
                tempBuffer->Length * elementSize);

            bufferHeader->Length = total;
        }
Example #3
0
        public DynamicBuffer <T> GetBuffer <T>(Entity entity) where T : struct, IBufferElementData
        {
            CheckAccess();

            var typeIndex = TypeManager.GetTypeIndex <T>();

            m_EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (!TypeManager.IsBuffer(typeIndex))
            {
                throw new ArgumentException(
                          $"GetBuffer<{typeof(T)}> may not be IComponentData or ISharedComponentData; currently {TypeManager.GetTypeInfo<T>().Category}");
            }
#endif

            BufferHeader *header = (BufferHeader *)m_EntityComponentStore->GetComponentDataWithTypeRW(entity, typeIndex, m_EntityComponentStore->GlobalSystemVersion);

            int internalCapacity = TypeManager.GetTypeInfo(typeIndex).BufferCapacity;

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            return(new DynamicBuffer <T>(header, m_Safety, m_Safety, false, internalCapacity));
#else
            return(new DynamicBuffer <T>(header, internalCapacity));
#endif
        }
Example #4
0
        public static void EnsureCapacity(BufferHeader *header, int count, int typeSize, int alignment, TrashMode trashMode)
        {
            if (header->Capacity >= count)
            {
                return;
            }

            int  newCapacity  = Math.Max(Math.Max(2 * header->Capacity, count), kMinimumCapacity);
            long newBlockSize = newCapacity * typeSize;

            byte *oldData = GetElementPointer(header);
            byte *newData = (byte *)UnsafeUtility.Malloc(newBlockSize, alignment, Allocator.Persistent);

            if (trashMode == TrashMode.RetainOldData)
            {
                long oldBlockSize = header->Capacity * typeSize;
                UnsafeUtility.MemCpy(newData, oldData, oldBlockSize);
            }

            // Note we're freeing the old buffer only if it was not using the internal capacity. Don't change this to 'oldData', because that would be a bug.
            if (header->Pointer != null)
            {
                UnsafeUtility.Free(header->Pointer, Allocator.Persistent);
            }

            header->Pointer  = newData;
            header->Capacity = newCapacity;
        }
        private IpcCircularBuffer(Section section, string sectionName, Semaphore readSemaphore, Semaphore writeSemaphore)
        {
            BufferHeader header;

            _section = section;

            _sectionView = section.MapView(Marshal.SizeOf(typeof(BufferHeader)));
            header       = _sectionView.ReadStruct <BufferHeader>();
            _sectionView.Dispose();

            if (readSemaphore == null || writeSemaphore == null)
            {
                _readSemaphore  = new Semaphore(sectionName + "_" + header.ReadSemaphoreId.ToString("x"));
                _writeSemaphore = new Semaphore(sectionName + "_" + header.WriteSemaphoreId.ToString("x"));
            }
            else
            {
                _readSemaphore  = readSemaphore;
                _writeSemaphore = writeSemaphore;
            }

            _sectionView = _section.MapView(header.BlockSize * header.NumberOfBlocks);
            _header      = (BufferHeader *)_sectionView.Memory;
            _data        = &_header->Data;
        }
Example #6
0
        public DynamicBuffer <T> this[int index]
        {
            get
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
                if (index < m_MinIndex || index > m_MaxIndex)
                {
                    FailOutOfRangeError(index);
                }
                var safety = m_Safety;
#endif

                if (index < m_Cache.CachedBeginIndex || index >= m_Cache.CachedEndIndex)
                {
                    m_Iterator.UpdateCache(index, out m_Cache, !m_IsReadOnly);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    if (m_Cache.CachedSizeOf < sizeof(BufferHeader))
                    {
                        throw new InvalidOperationException("size cache info is broken");
                    }
#endif
                }

                BufferHeader *header = (BufferHeader *)((byte *)m_Cache.CachedPtr + index * m_Cache.CachedSizeOf);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                return(new DynamicBuffer <T>(header, m_Safety));
#else
                return(new DynamicBuffer <T>(header));
#endif
            }
        }
Example #7
0
        /// <summary>
        /// Gets the dynamic buffer of an entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <typeparam name="T">The type of the buffer's elements.</typeparam>
        /// <returns>The DynamicBuffer object for accessing the buffer contents.</returns>
        /// <exception cref="ArgumentException">Thrown if T is an unsupported type.</exception>
        public DynamicBuffer <T> GetBuffer <T>(Entity entity) where T : struct, IBufferElementData
        {
            var typeIndex = TypeManager.GetTypeIndex <T>();

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);
            if (!TypeManager.IsBuffer(typeIndex))
            {
                throw new ArgumentException(
                          $"GetBuffer<{typeof(T)}> may not be IComponentData or ISharedComponentData; currently {TypeManager.GetTypeInfo<T>().Category}");
            }
#endif

            ComponentJobSafetyManager->CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header =
                (BufferHeader *)EntityComponentStore->GetComponentDataWithTypeRW(entity, typeIndex,
                                                                                 EntityComponentStore->GlobalSystemVersion);

            int internalCapacity = TypeManager.GetTypeInfo(typeIndex).BufferCapacity;

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            return(new DynamicBuffer <T>(header, ComponentJobSafetyManager->GetSafetyHandle(typeIndex, false),
                                         ComponentJobSafetyManager->GetBufferSafetyHandle(typeIndex), false, internalCapacity));
#else
            return(new DynamicBuffer <T>(header, internalCapacity));
#endif
        }
Example #8
0
        public static void PatchEntitiesForPrefab(EntityPatchInfo *scalarPatches, int scalarPatchCount, BufferEntityPatchInfo *bufferPatches, int bufferPatchCount, byte *data, int indexInChunk, int entityCount, SparseEntityRemapInfo *remapping, int remappingCount)
        {
            // Patch scalars (single components) with entity references.
            for (int p = 0; p < scalarPatchCount; p++)
            {
                byte *entityData = data + scalarPatches[p].Offset;
                for (int e = 0; e != entityCount; e++)
                {
                    Entity *entity = (Entity *)(entityData + scalarPatches[p].Stride * (e + indexInChunk));
                    *       entity = RemapEntityForPrefab(remapping + e * remappingCount, remappingCount, *entity);
                }
            }

            // Patch buffers that contain entity references
            for (int p = 0; p < bufferPatchCount; ++p)
            {
                byte *bufferData = data + bufferPatches[p].BufferOffset;

                for (int e = 0; e != entityCount; e++)
                {
                    BufferHeader *header = (BufferHeader *)(bufferData + bufferPatches[p].BufferStride * (e + indexInChunk));

                    byte *elemsBase = BufferHeader.GetElementPointer(header) + bufferPatches[p].ElementOffset;
                    int   elemCount = header->Length;

                    for (int k = 0; k != elemCount; ++k)
                    {
                        Entity *entityPtr = (Entity *)elemsBase;
                        *       entityPtr = RemapEntityForPrefab(remapping + e * remappingCount, remappingCount, *entityPtr);
                        elemsBase += bufferPatches[p].ElementStride;
                    }
                }
            }
        }
        public DynamicBuffer <T> this[int index]
        {
            get
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                if (m_IsReadOnly)
                {
                    AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
                }
                else
                {
                    AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
                }

                if (index < 0 || index >= Length)
                {
                    throw new InvalidOperationException($"index {index} out of range in LowLevelBufferAccessor of length {Length}");
                }
#endif
                BufferHeader *hdr = (BufferHeader *)(m_BasePointer + index * m_Stride);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                return(new DynamicBuffer <T>(hdr, m_Safety, m_ArrayInvalidationSafety));
#else
                return(new DynamicBuffer <T>(hdr));
#endif
            }
        }
Example #10
0
 public static unsafe void Destroy(BufferHeader *header)
 {
     if (header.Pointer != null)
     {
         UnsafeUtility.Free((void *)header.Pointer, Allocator.Persistent);
     }
     Initialize(header, 0);
 }
Example #11
0
        public static void ReplicateComponents(Chunk *srcChunk, int srcIndex, Chunk *dstChunk, int dstBaseIndex, int count)
        {
            var srcArchetype        = srcChunk->Archetype;
            var srcBuffer           = srcChunk->Buffer;
            var dstBuffer           = dstChunk->Buffer;
            var dstArchetype        = dstChunk->Archetype;
            var srcOffsets          = srcArchetype->Offsets;
            var srcSizeOfs          = srcArchetype->SizeOfs;
            var srcBufferCapacities = srcArchetype->BufferCapacities;
            var srcTypesCount       = srcArchetype->TypesCount;
            var srcTypes            = srcArchetype->Types;
            var dstTypes            = dstArchetype->Types;
            var dstOffsets          = dstArchetype->Offsets;
            var dstTypeIndex        = 1;

            // type[0] is always Entity, and will be patched up later, so just skip
            for (var srcTypeIndex = 1; srcTypeIndex != srcTypesCount; srcTypeIndex++)
            {
                var srcType = srcTypes[srcTypeIndex];
                var dstType = dstTypes[dstTypeIndex];

                // Type does not exist in destination. Skip it.
                if (srcType.TypeIndex != dstType.TypeIndex)
                {
                    continue;
                }

                var srcOffset = srcOffsets[srcTypeIndex];
                var srcSizeOf = srcSizeOfs[srcTypeIndex];

                var dstOffset = dstOffsets[dstTypeIndex];

                var src = srcBuffer + (srcOffset + srcSizeOf * srcIndex);
                var dst = dstBuffer + (dstOffset + srcSizeOf * dstBaseIndex);

                if (!srcType.IsBuffer)
                {
                    UnsafeUtility.MemCpyReplicate(dst, src, srcSizeOf, count);
                }
                else
                {
                    var srcBufferCapacity = srcBufferCapacities[srcTypeIndex];
                    var alignment         = 8; // TODO: Need a way to compute proper alignment for arbitrary non-generic types in TypeManager
                    var elementSize       = TypeManager.GetTypeInfo(srcType.TypeIndex).ElementSize;
                    for (int i = 0; i < count; ++i)
                    {
                        BufferHeader *srcHdr = (BufferHeader *)src;
                        BufferHeader *dstHdr = (BufferHeader *)dst;
                        BufferHeader.Initialize(dstHdr, srcBufferCapacity);
                        BufferHeader.Assign(dstHdr, BufferHeader.GetElementPointer(srcHdr), srcHdr->Length, elementSize, alignment);

                        dst += srcSizeOf;
                    }
                }

                dstTypeIndex++;
            }
        }
        public static unsafe void PatchEntities(EntityPatchInfo *scalarPatches, int scalarPatchCount, BufferEntityPatchInfo *bufferPatches, int bufferPatchCount, byte *data, int count, ref NativeArray <EntityRemapInfo> remapping)
        {
            int index = 0;

            while (true)
            {
                if (index >= scalarPatchCount)
                {
                    int num3 = 0;
                    while (num3 < bufferPatchCount)
                    {
                        byte *numPtr2 = data + bufferPatches[num3].BufferOffset;
                        int   num4    = 0;
                        while (true)
                        {
                            if (num4 == count)
                            {
                                num3++;
                                break;
                            }
                            BufferHeader *header  = (BufferHeader *)numPtr2;
                            byte *        numPtr3 = BufferHeader.GetElementPointer(header) + bufferPatches[num3].ElementOffset;
                            int           length  = header->Length;
                            int           num6    = 0;
                            while (true)
                            {
                                if (num6 == length)
                                {
                                    numPtr2 += bufferPatches[num3].BufferStride;
                                    num4++;
                                    break;
                                }
                                Entity *entityPtr2 = (Entity *)numPtr3;
                                entityPtr2[0] = RemapEntity(ref remapping, entityPtr2[0]);
                                numPtr3      += bufferPatches[num3].ElementStride;
                                num6++;
                            }
                        }
                    }
                    return;
                }
                byte *numPtr = data + scalarPatches[index].Offset;
                int   num2   = 0;
                while (true)
                {
                    if (num2 == count)
                    {
                        index++;
                        break;
                    }
                    Entity *entityPtr = (Entity *)numPtr;
                    entityPtr[0] = RemapEntity(ref remapping, entityPtr[0]);
                    numPtr      += scalarPatches[index].Stride;
                    num2++;
                }
            }
        }
        public static void Destroy(BufferHeader *header)
        {
            if (header->Pointer != null)
            {
                Memory.Unmanaged.Free(header->Pointer, Allocator.Persistent);
            }

            Initialize(header, 0);
        }
Example #14
0
    public void SetBufferRaw(Entity entity, int componentTypeIndex, BufferHeader *tempBuffer, int sizeInChunk)
    {
        if (m_IsMainThread)
        {
            DependencyManager->CompleteReadAndWriteDependency(componentTypeIndex);
        }

        EntityComponentStore->SetBufferRawWithValidation(entity, componentTypeIndex, tempBuffer, sizeInChunk);
    }
Example #15
0
        public static byte *GetElementPointer(BufferHeader *header)
        {
            if (header->Pointer != null)
            {
                return(header->Pointer);
            }

            return((byte *)(header + 1));
        }
Example #16
0
 internal DynamicBuffer(BufferHeader *header, AtomicSafetyHandle safety, AtomicSafetyHandle arrayInvalidationSafety, bool isReadOnly)
 {
     m_Buffer               = header;
     m_Safety0              = safety;
     m_Safety1              = arrayInvalidationSafety;
     m_SafetyReadOnlyCount  = isReadOnly ? 2 : 0;
     m_SafetyReadWriteCount = isReadOnly ? 0 : 2;
     m_IsReadOnly           = isReadOnly;
 }
Example #17
0
        internal unsafe void SetBufferRaw(Entity entity, int componentTypeIndex, BufferHeader *tempBuffer, int sizeInChunk)
        {
            this.Entities.AssertEntityHasComponent(entity, componentTypeIndex);
            this.ComponentJobSafetyManager.CompleteReadAndWriteDependency(componentTypeIndex);
            byte *numPtr = ref this.Entities.GetComponentDataWithTypeRW(entity, componentTypeIndex, this.Entities.GlobalSystemVersion);

            BufferHeader.Destroy((BufferHeader *)numPtr);
            UnsafeUtility.MemCpy((void *)numPtr, (void *)tempBuffer, (long)sizeInChunk);
        }
Example #18
0
        public static void EnsureCapacity(BufferHeader *header, int count, int typeSize, int alignment, TrashMode trashMode, bool useMemoryInitPattern, byte memoryInitPattern)
        {
            if (count <= header->Capacity)
            {
                return;
            }
            var adjustedCount = Math.Max(kMinimumCapacity, Math.Max(2 * header->Capacity, count)); // stop pathological performance of ++Capacity allocating every time, tiny Capacities

            SetCapacity(header, adjustedCount, typeSize, alignment, trashMode, useMemoryInitPattern, memoryInitPattern, 0);
        }
        public static void Burst_Unity__Entities__EntityDataAccess_SetBufferRaw(IntPtr p)
        {
            var           v0       = default(Entity);
            var           v1       = default(int);
            BufferHeader *v2       = (BufferHeader *)((byte *)p + 2048);
            var           v3       = default(int);
            var           instance = (EntityDataAccess *)p;

            instance->SetBufferRaw(v0, v1, v2, v3);
        }
Example #20
0
        internal void *GetBufferRawRW(Entity entity, int typeIndex)
        {
            Entities->AssertEntityHasComponent(entity, typeIndex);

            ComponentJobSafetyManager.CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header = (BufferHeader *)Entities->GetComponentDataWithTypeRW(entity, typeIndex, Entities->GlobalSystemVersion);

            return(BufferHeader.GetElementPointer(header));
        }
Example #21
0
        internal int GetBufferLength(Entity entity, int typeIndex)
        {
            Entities->AssertEntityHasComponent(entity, typeIndex);

            ComponentJobSafetyManager.CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header = (BufferHeader *)Entities->GetComponentDataWithTypeRW(entity, typeIndex, Entities->GlobalSystemVersion);

            return(header->Length);
        }
Example #22
0
        internal int GetBufferLength(Entity entity, int typeIndex)
        {
            EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);

            ComponentJobSafetyManager->CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header = (BufferHeader *)EntityComponentStore->GetComponentDataWithTypeRO(entity, typeIndex);

            return(header->Length);
        }
Example #23
0
        internal void *GetBufferRawRO(Entity entity, int typeIndex)
        {
            EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);

            ComponentJobSafetyManager->CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header = (BufferHeader *)EntityComponentStore->GetComponentDataWithTypeRO(entity, typeIndex);

            return(BufferHeader.GetElementPointer(header));
        }
Example #24
0
        public static void Assign(BufferHeader *header, byte *source, int count, int typeSize, int alignment)
        {
            EnsureCapacity(header, count, typeSize, alignment, TrashMode.TrashOldData);

            // Select between internal capacity buffer and heap buffer.
            byte *elementPtr = GetElementPointer(header);

            UnsafeUtility.MemCpy(elementPtr, source, typeSize * count);

            header->Length = count;
        }
        public DynamicBuffer <T> CreateBufferCommand <T>(ECBCommand commandType, EntityCommandBufferChain *chain, Entity e) where T : struct, IBufferElementData
        {
            BufferHeader *header = AddEntityBufferCommand <T>(chain, commandType, e);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            var safety = m_BufferSafety;
            AtomicSafetyHandle.UseSecondaryVersion(ref safety);
            return(new DynamicBuffer <T>(header, safety));
#else
            return(new DynamicBuffer <T>(header));
#endif
        }
 internal DynamicBuffer(BufferHeader *header, AtomicSafetyHandle safety, AtomicSafetyHandle arrayInvalidationSafety, bool isReadOnly, bool useMemoryInitPattern, byte memoryInitPattern, int internalCapacity)
 {
     m_Buffer               = header;
     m_Safety0              = safety;
     m_Safety1              = arrayInvalidationSafety;
     m_SafetyReadOnlyCount  = isReadOnly ? 2 : 0;
     m_SafetyReadWriteCount = isReadOnly ? 0 : 2;
     m_IsReadOnly           = isReadOnly;
     m_InternalCapacity     = internalCapacity;
     m_useMemoryInitPattern = useMemoryInitPattern;
     m_memoryInitPattern    = memoryInitPattern;
 }
Example #27
0
        internal void SetBufferRaw(Entity entity, int componentTypeIndex, BufferHeader *tempBuffer, int sizeInChunk)
        {
            Entities->AssertEntityHasComponent(entity, componentTypeIndex);

            ComponentJobSafetyManager.CompleteReadAndWriteDependency(componentTypeIndex);

            var ptr = Entities->GetComponentDataWithTypeRW(entity, componentTypeIndex, Entities->GlobalSystemVersion);

            BufferHeader.Destroy((BufferHeader *)ptr);

            UnsafeUtility.MemCpy(ptr, tempBuffer, sizeInChunk);
        }
        internal void *GetBufferRawRW(Entity entity, int typeIndex)
        {
            var access = GetCheckedEntityDataAccess();
            var ecs    = access->EntityComponentStore;

            ecs->AssertEntityHasComponent(entity, typeIndex);

            access->DependencyManager->CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header = (BufferHeader *)ecs->GetComponentDataWithTypeRW(entity, typeIndex, ecs->GlobalSystemVersion);

            return(BufferHeader.GetElementPointer(header));
        }
        internal int GetBufferLength(Entity entity, int typeIndex)
        {
            var access = GetCheckedEntityDataAccess();
            var ecs    = access->EntityComponentStore;

            ecs->AssertEntityHasComponent(entity, typeIndex);

            access->DependencyManager->CompleteReadAndWriteDependency(typeIndex);

            BufferHeader *header = (BufferHeader *)ecs->GetComponentDataWithTypeRO(entity, typeIndex);

            return(header->Length);
        }
Example #30
0
            public BufferHeader *Alloc(int size)
            {
                if (size == _pageSize)
                {
                    return(Alloc());
                }

                BufferHeader *header = (BufferHeader *)Marshal.AllocHGlobal(size + BufferHeader.BufferHeaderSize);

                (*header).Next = null;
                (*header).Size = size;
                (*header).Used = 0;
                return(header);
            }
Example #31
0
        protected override void Dispose(bool disposing)
        {
            var pool = Interlocked.Exchange(ref _pool, null);
            var head = _first;
            _first = null;
            _current = null;

            if (head != null && pool != null)
                pool.Dealloc(head);

            base.Dispose(disposing);
        }
Example #32
0
        int EnsureCapacity()
        {
            var pool = _pool ?? (_pool = ThreadBufferPool.Pool);

            if (_current == null)
            {
                var buffer = pool.Alloc();
                _current = _first = buffer;
                return (*_current).Size;
            }

            var current = (*_current);
            if (current.Used == current.Size)
            {
                var buffer = pool.Alloc();
                (*_current).Next = buffer;
                _current = buffer;
                return (*buffer).Size;
            }

            return current.Size - current.Used;
        }