/// <summary>
 /// Resize the <see cref="ArraySegmentPool{T}"/> and update the instance reference.
 /// </summary>
 /// <param name="pool"></param>
 /// <returns>New pool</returns>
 private _pool GetNewPool(_pool pool)
 {
     lock (_poolLock)
     {
         if (_isAutoResize == false)
         {
             throw new OverflowException("ArraySegmentPool size out of max capacity");
         }
         //check if other thread already create new resized pool.
         if (pool != _currentPool)
         {
             return(_currentPool);
         }
         //check limits.
         if (pool.ArrayLayout.Length == _maxCapacity)
         {
             throw new OverflowException("ArraySegmentPool size out of max capacity");
         }
         //create new resized pool and refresh current ref.
         int newLayoutLength = pool.ArrayLayout.Length * 2L < _maxCapacity ? pool.ArrayLayout.Length * 2 : _maxCapacity;
         int newLength       = _maxArraySegmentLength * newLayoutLength;
         _currentPool = new _pool()
         {
             ArrayLayout = new int[newLayoutLength], Array = new T[newLength]
         };
         //return new pool.
         return(_currentPool);
     }
 }
 /// <summary>
 /// Sets the capacity of <see cref="ArraySegmentPool{T}"/> to the size of the used <see cref="ArraySegment{T}"/>. This method can be used to minimize a pool's memory overhead once it is known that no new <see cref = "ArraySegment{T}" /> will be added to the <see cref= "ArraySegmentPool{T}"/>.
 /// </summary>
 public void TrimExcess()
 {
     lock (_poolLock)
     {
         if (_isAutoResize == false)
         {
             throw new AccessViolationException("Can't trim while auto resize false");
         }
         int count             = _currentPool.Count;
         int new_layout_length = count > 1 ? count : 1;
         int new_length        = new_layout_length * _maxArraySegmentLength;
         _currentPool = new _pool()
         {
             ArrayLayout = new int[new_layout_length], Array = new T[new_length]
         };
     }
 }
        /// <summary>
        /// (!) Dangerous. Gets an <see cref="ArraySegment{T}"/> of the custom length. <see cref="ArraySegment{T}"/> must be returned via <see cref="Return"/> on the same <see cref="ArraySegmentPool{T}"/> instance to avoid memory leaks.
        /// </summary>
        /// <param name="length">Lenght of the rented <see cref="ArraySegment{T}"/>. Lenght must be equal or smaller than <see cref="defaultLength"/></param>
        /// <returns><see cref="ArraySegment{T}"/></returns>
        public ArraySegment <T> DangerousRent(int length)
        {
            if (length <1 | length> _maxArraySegmentLength)
            {
                throw new ArgumentOutOfRangeException("Length must be greater than one and smaller than default length");
            }
            _pool pool = _currentPool;

            //Get new resized pool if free segment not finded.
            if (pool.Count >= pool.ArrayLayout.Length)
            {
                pool = GetNewPool(pool);
            }
            //Try find free segment and ocupy.
            int position    = pool.LastRentedSegment + 1;
            int searchCount = 0;

            do
            {
                if (position > pool.ArrayLayout.GetUpperBound(0))
                {
                    position = 0;
                }
                if (System.Threading.Interlocked.CompareExchange(ref pool.ArrayLayout[position], 1, 0) == 0)
                {
                    System.Threading.Interlocked.Increment(ref pool.Count);
                    pool.LastRentedSegment = position;
                    return(new ArraySegment <T>(pool.Array, position * _maxArraySegmentLength, length));
                }
#if UT
                System.Threading.Interlocked.Increment(ref _failsCount);
#endif
                position    += 1;
                searchCount += 1;
                //That check prevent state, where thread will loop forever.
                if (searchCount == pool.ArrayLayout.Length)
                {
                    pool        = GetNewPool(pool);
                    position    = 0;
                    searchCount = 0;
                }
            }while (true);
        }
        /// <summary>
        /// Returns to the <see cref="ArraySegmentPool{T}"/> an <see cref="ArraySegment{T}"/> that was previously obtained via <see cref="DangerousRent"/> on the same <see cref="ArraySegmentPool{T}"/> instance.
        /// </summary>
        /// <param name="ArraySegment"></param>
        public void Return(ref ArraySegment <T> ArraySegment)
        {
            if (ArraySegment.Count == 0)
            {
                throw new ArgumentException("Do not Slice rented ArraySegment to zero, since the pool will not be able to free memory");
            }
            _pool pool = _currentPool;

            if (ArraySegment.Array == pool.Array)
            {
                //return segment.
                int position = ArraySegment.Offset / _maxArraySegmentLength;
                if (System.Threading.Interlocked.Exchange(ref pool.ArrayLayout[position], 0) == 0)
                {
                    throw new Exception("ArraySegment was returned already");
                }
                System.Threading.Interlocked.Decrement(ref pool.Count);
            }
            ArraySegment = ArraySegment <T> .Empty;
        }
 private ArraySegmentPool(int maxArraySegmentLength, int initialCapacity, int maxCapacity, bool autoResize)
 {
     if (maxArraySegmentLength < 1 | initialCapacity < 1 | maxCapacity < 1)
     {
         throw new ArgumentOutOfRangeException("Arguments must be greater than 1");
     }
     if (initialCapacity > maxCapacity)
     {
         throw new ArgumentOutOfRangeException("InitialCapacity > MaxCapacity");
     }
     if ((long)maxArraySegmentLength * maxCapacity > int.MaxValue)
     {
         throw new OverflowException("MaxCapacity");
     }
     _maxArraySegmentLength = maxArraySegmentLength;
     _maxCapacity           = maxCapacity;
     _isAutoResize          = autoResize;
     _currentPool           = new _pool()
     {
         ArrayLayout = new int[initialCapacity], Array = new T[_maxArraySegmentLength * initialCapacity]
     };
 }