GithubHelp home page GithubHelp logo

softstonedevelop / stackmemorycollections Goto Github PK

View Code? Open in Web Editor NEW
5.0 1.0 0.0 2.51 MB

Fast unsafe collections for memory reuse by stack type. Adding elements without overhead when increasing Capacity. Can also be used in as classic collection with resizing or on a custom memory allocator.

License: MIT License

C# 100.00%
collections memory-management stack analysis roslyn-analyzer roslyn-generator list queue unsafe-code netcore

stackmemorycollections's People

Contributors

softstonedevelop avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

stackmemorycollections's Issues

Add Stack Class/Struct Generator

By the presence of an attribute in a structure or class, generate an auxiliary class.

For Example:

    [GenerateStack]//generate stack class/struct
    public struct SimpleStruct
    {
        public SimpleStruct(
            int int32,
            long int64
            )
        {
            Int32 = int32;
            Int64 = int64;
        }

        public long Int64;
        public int Int32;
    }

Generated class:

public unsafe struct StackOfSimpleStruct : IDisposable, IEnumerable<SimpleStruct>
    {
        private readonly Struct.StackMemory* _stackMemoryS;
        private readonly Class.StackMemory? _stackMemoryC = null;
        private readonly void* _start;
        private int _version = 0;

        public StackOfSimpleStruct()
        {
            throw new ArgumentException("Default constructor not supported");
        }

        public StackOfSimpleStruct(
            nuint count,
            Struct.StackMemory* stackMemory
            )
        {
            if (stackMemory == null)
            {
                throw new ArgumentNullException(nameof(stackMemory));
            }

            _start = (*stackMemory).AllocateMemory(SimpleStructHelper.GetSize() * count);
            _stackMemoryS = stackMemory;
            Capacity = count;
        }

        public StackOfSimpleStruct(
            nuint count,
            Class.StackMemory stackMemory
            )
        {
            if (stackMemory == null)
            {
                throw new ArgumentNullException(nameof(stackMemory));
            }

            _start = stackMemory.AllocateMemory(SimpleStructHelper.GetSize() * count);
            _stackMemoryC = stackMemory;
            _stackMemoryS = null;
            Capacity = count;
        }

        public StackOfSimpleStruct(
            nuint count,
            void* memoryStart
            )
        {
            if (memoryStart == null)
            {
                throw new ArgumentNullException(nameof(memoryStart));
            }

            _start = memoryStart;
            _stackMemoryS = null;
            Capacity = count;
        }

        public nuint Capacity { get; private set; }

        public nuint Size { get; private set; } = 0;

        public bool IsEmpty => Size == 0;

        public void ReducingAvailableMemory(in nuint reducingCount)
        {
            if (reducingCount <= 0)
            {
                return;
            }

            if (Size < Capacity - reducingCount)
            {
                throw new Exception("Can't reduce available memory, it's already in use");
            }

            if(_stackMemoryS != null)
            {
                if (new IntPtr((*_stackMemoryS).Current) != new IntPtr((byte*)_start + (Capacity * SimpleStructHelper.GetSize())))
                {
                    throw new Exception("Failed to reduce available memory, stack moved further");
                }

                (*_stackMemoryS).FreeMemory(reducingCount * SimpleStructHelper.GetSize());
            }
            else if (_stackMemoryC != null)
            {
                if (new IntPtr(_stackMemoryC.Current) != new IntPtr((byte*)_start + (Capacity * SimpleStructHelper.GetSize())))
                {
                    throw new Exception("Failed to reduce available memory, stack moved further");
                }

                _stackMemoryC.FreeMemory(reducingCount * SimpleStructHelper.GetSize());
            }

            Capacity -= reducingCount;
        }

        public void ExpandAvailableMemory(in nuint expandBytes)
        {
            Capacity += expandBytes;
        }

        public void SetAvailableMemoryCurrentUsed()
        {
            ReducingAvailableMemory(Capacity - Size);
        }


        public void Push(in SimpleStruct item)
        {
            var tempSize = Size + 1;
            if (tempSize > Capacity)
            {
                throw new Exception("Not enough memory to allocate stack element");
            }

            SimpleStructHelper.CopyToPtr(in item, (byte*)_start + (Size * SimpleStructHelper.GetSize()));
            Size = tempSize;
            _version++;
        }

        public bool TryPush(in SimpleStruct item)
        {
            var tempSize = Size + 1;
            if (tempSize > Capacity)
            {
                return false;
            }

            SimpleStructHelper.CopyToPtr(in item, (byte*)_start + (Size * SimpleStructHelper.GetSize()));
            Size = tempSize;
            _version++;

            return true;
        }

        public void Pop()
        {
            if (Size <= 0)
            {
                throw new Exception("There are no elements on the stack");
            }

            Size--;
            _version++;
        }

        public void Clear()
        {
            if (Size != 0)
            {
                Size = 0;
                _version++;
            }
        }

        public SimpleStruct Front()
        {
            if (Size == 0)
            {
                throw new Exception("There are no elements on the stack");
            }

            SimpleStruct result = default;
            SimpleStructHelper.CopyToValue((byte*)_start + ((Size - 1) * SimpleStructHelper.GetSize()), ref result);
            return
                result;
        }

        public void* FrontPtr()
        {
            if (Size == 0)
            {
                throw new Exception("There are no elements on the stack");
            }

            return (byte*)_start + ((Size - 1) * SimpleStructHelper.GetSize());
        }

        public void Dispose()
        {
            if(_stackMemoryS != null)
            {
                (*_stackMemoryS).FreeMemory(Capacity * SimpleStructHelper.GetSize());
            }
            else if (_stackMemoryC != null)
            {
                _stackMemoryC.FreeMemory(Capacity * SimpleStructHelper.GetSize());
            }
        }

        #region IEnumerable<T>

        public IEnumerator<SimpleStruct> GetEnumerator()
        {
            return new Enumerator(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }

        public void CopyTo(Array array, int index)
        {
            throw new NotImplementedException();
        }

        public struct Enumerator : IEnumerator<SimpleStruct>, IEnumerator
        {
            private readonly StackOfSimpleStruct _stack;
            private SimpleStruct _current;
            private int _currentIndex;
            private int _version;

            internal Enumerator(StackOfSimpleStruct stack)
            {
                _stack = stack;
                _currentIndex = -1;
                _current = default;
                _version = _stack._version;
            }

            public SimpleStruct Current => _current;

            object IEnumerator.Current => Current;

            public void Dispose()
            {
                _currentIndex = -1;
            }

            public bool MoveNext()
            {
                if (_version != _stack._version)
                {
                    throw new InvalidOperationException("The stack was changed during the enumeration");
                }

                if (_stack.Size < 0)
                {
                    return false;
                }

                if (_currentIndex == -2)
                {
                    _currentIndex = (int)_stack.Size - 1;
                    SimpleStruct result = default;
                    SimpleStructHelper.CopyToValue((byte*)_stack._start + (_currentIndex * (int)SimpleStructHelper.GetSize()), ref result);
                    _current = result;
                    return true;
                }

                if (_currentIndex == -1)
                {
                    return false;
                }

                --_currentIndex;
                if (_currentIndex >= 0)
                {
                    SimpleStruct result = default;
                    SimpleStructHelper.CopyToValue((byte*)_stack._start + (_currentIndex * (int)SimpleStructHelper.GetSize()), ref result);
                    _current = result;
                    return true;
                }
                else
                {
                    _current = default;
                    return false;
                }
            }

            public void Reset()
            {
                _currentIndex = -2;
            }
        }

        #endregion

        public SimpleStruct this[nuint index]
        {
            get
            {
                if (Size <= 0 || Size <= index)
                {
                    throw new Exception("Element outside the stack");
                }
                SimpleStruct result = default;
                SimpleStructHelper.CopyToValue((byte*)_start + ((Size - 1 - index) * SimpleStructHelper.GetSize()), ref result);
                return
                    result;
            }
        }

        public void* GetByIndex(nuint index)
        {
            if (Size <= 0 || Size <= index)
            {
                throw new Exception("Element outside the stack");
            }
            
            return
                (byte*)_start + ((Size - 1 - index) * SimpleStructHelper.GetSize());
        }
    }

Add deep copy method generation

Now you can create a copy like this:

var tempWrap = new Benchmark.Struct.JobStructWrapper();
tempWrap.Fill(in item);
var copyItem = tempWrap.GetValue();

But this way is slow.

You need to generate something like the following:

public static JobStruct DeepCopy(in JobStruct item)
{
    var result = new JobStruct();
    result.Int32 = item.Int32;
    result.Int64 = item.Int64;
    result.JobStruct2.Int32 = item.Int32;
    result.JobStruct2.Int64 = item.Int64;

    return result;
}

Usage:

var copyItem  = JobStructHelper.DeepCopy(in item);

Add Helper Class Generator

By the presence of an attribute in a structure or class, generate an auxiliary class.

For Example:

    [GenerateHelper]//generate helper class
    public struct SimpleStruct
    {
        public SimpleStruct(
            int int32,
            long int64
            )
        {
            Int32 = int32;
            Int64 = int64;
        }

        public long Int64;
        public int Int32;
    }

Generated class:

using System;

namespace StackMemoryCollections
{
    public unsafe static class SimpleStructHelper
    {


        public static nuint GetSize()
        {
            return 12;
        }


        public static void* GetInt64Ptr(in void* ptr)
        {
            return (byte*)ptr + 0;
        }


        public static Int64 GetInt64Value(in void* ptr)
        {
            return *(Int64*)((byte*)ptr + 0);
        }


        public static void SetInt64Value(in void* ptr, in Int64 value)
        {
            *(Int64*)((byte*)ptr + 0) = value;
        }


        public static void SetInt64Value(in void* ptr, in SimpleStruct value)
        {
            *(Int64*)((byte*)ptr + 0) = value.Int64;
        }


        public static void* GetInt32Ptr(in void* ptr)
        {
            return (byte*)ptr + 8;
        }


        public static Int32 GetInt32Value(in void* ptr)
        {
            return *(Int32*)((byte*)ptr + 8);
        }


        public static void SetInt32Value(in void* ptr, in Int32 value)
        {
            *(Int32*)((byte*)ptr + 8) = value;
        }


        public static void SetInt32Value(in void* ptr, in SimpleStruct value)
        {
            *(Int32*)((byte*)ptr + 8) = value.Int32;
        }


        public static void CopyToPtr(in SimpleStruct value, in void* ptr)
        {


            SetInt64Value(in ptr, in value);

            SetInt32Value(in ptr, in value);


        }


        public static void CopyToValue(in void* ptr, ref SimpleStruct value)
        {


            value.Int64 = GetInt64Value(in ptr);

            value.Int32 = GetInt32Value(in ptr);

        }



    }
}

Add support for collections on pointers

Example:

unsafe
{
    using (var memory = new StackMemoryCollections.Struct.StackMemory(JobClassHelper.GetSize() * 15))
    {
        using var stack = new Benchmark.Struct.StackOfIntPtr((nuint)Size, &memory);
        for (int i = 0; i < Size; i++)
        {
            var item = new Struct.JobStructWrapper(&memory);
            stack.Push(new IntPtr(item.Ptr)); 
        }
    }
}

Add property/field ignore attribute

The generator does not support complex properties/fields like dictionaries or if your property has logic. In this case, you need to use a special attribute.

[GeneratorIgnore]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.