internal int SelectBucketIndex(int bufferSize) { Debug.Assert(bufferSize >= 0); var intUtil = Math.Max(0, (32 - IntUtil.NumberOfLeadingZeros(bufferSize - 1)) - _minBufferLengthPow2); #if DEBUG // TODO remove this check after some usage, see if this is not the same on some edge case // bufferSize of 0 will underflow here, causing a huge // index which the caller will discard because it is not // within the bounds of the bucket array. uint bitsRemaining = ((uint)bufferSize - 1) >> _minBufferLengthPow2; int poolIndex = 0; if (bitsRemaining > 0xFFFF) { bitsRemaining >>= 16; poolIndex = 16; } if (bitsRemaining > 0xFF) { bitsRemaining >>= 8; poolIndex += 8; } if (bitsRemaining > 0xF) { bitsRemaining >>= 4; poolIndex += 4; } if (bitsRemaining > 0x3) { bitsRemaining >>= 2; poolIndex += 2; } if (bitsRemaining > 0x1) { bitsRemaining >>= 1; poolIndex += 1; } var manual = poolIndex + (int)bitsRemaining; Debug.Assert(manual == intUtil); #endif return(intUtil); }
public static int FindNextPositivePowerOfTwo(int value) { return(1 << (32 - IntUtil.NumberOfLeadingZeros(value - 1))); }
public RetainableMemoryPool(Func <RetainableMemoryPool <T>, int, RetainableMemory <T> > factory, int minLength, int maxLength, int maxBuffersPerBucket, int maxBucketsToTry = 2, bool pin = false, bool rentAlwaysClean = false) { IsRentAlwaysClean = rentAlwaysClean; _factory = factory; if (minLength <= 16) { minLength = 16; } _minBufferLengthPow2 = 32 - IntUtil.NumberOfLeadingZeros(minLength - 1); _minBufferLength = 1 << _minBufferLengthPow2; if (maxBucketsToTry < 0) { maxBucketsToTry = 0; } if (maxBucketsToTry > 4) { maxBucketsToTry = 4; } _maxBucketsToTry = maxBucketsToTry; if (pin && !TypeHelper <T> .IsPinnable) { ThrowHelper.ThrowInvalidOperationException($"Type {typeof(T).Name} is not pinnable. Cannot create RetainableMemoryPool with pinnable option."); } _pin = pin; if (maxLength <= 0) { throw new ArgumentOutOfRangeException(nameof(maxLength)); } if (maxBuffersPerBucket <= 0) { throw new ArgumentOutOfRangeException(nameof(maxBuffersPerBucket)); } // Our bucketing algorithm has a min length of 2^4 and a max length of 2^30. // Constrain the actual max used to those values. const int maximumArrayLength = 0x40000000; if (maxLength > maximumArrayLength) { maxLength = maximumArrayLength; } else if (maxLength < minLength) { maxLength = minLength; } _maxBufferLength = maxLength; // Create the buckets. int poolId = Id; int maxBuckets = SelectBucketIndex(maxLength); var buckets = new Bucket[maxBuckets + 1]; for (int i = 0; i < buckets.Length; i++) { buckets[i] = new Bucket(this, _factory, GetMaxSizeForBucket(i), maxBuffersPerBucket, poolId); } _buckets = buckets; lock (KnownPools) { // start from 2, // pool idx == 0 is always null which means a buffer is not from pool // pool idx == 1 means a buffer is from default pool, e.g. static array pool for (int i = 2; i < KnownPools.Length; i++) { if (KnownPools[i] == null) { PoolIdx = checked ((byte)i); KnownPools[i] = this; return; } } ThrowHelper.ThrowInvalidOperationException("KnownPools slots exhausted. 254 pools ought to be enough for anybody."); } }
public void LzcntNegative() { Assert.AreEqual(0, IntUtil.NumberOfLeadingZeros(-1)); Console.WriteLine(IntUtil.NumberOfLeadingZeros(-1)); }