| File: MS\Internal\UncommonValueTable.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // // Description: A table for storing up to 32 uncommon values. // using System.Windows; namespace MS.Internal { // An economical table for "uncommon values", identified by integers in the range [0,32). // Unused values incur no memory allocation internal struct UncommonValueTable { public bool HasValue(int id) { return (_bitmask & (0x1u << id)) != 0; } public object GetValue(int id) { return GetValue(id, DependencyProperty.UnsetValue); } public object GetValue(int id, object defaultValue) { int index = IndexOf(id); return (index < 0) ? defaultValue : _table[index]; } public void SetValue(int id, object value) { int index = Find(id); if (index < 0) { // new entry - grow the array if (_table == null) { _table = new object[1]; index = 0; } else { int n = _table.Length; object[] newTable = new object[n + 1]; index = ~index; Array.Copy(_table, 0, newTable, 0, index); Array.Copy(_table, index, newTable, index+1, n-index); _table = newTable; } // mark the id as present _bitmask |= (0x1u << id); } // store the new value _table[index] = value; } public void ClearValue(int id) { int index = Find(id); if (index >= 0) { // remove the value int n = _table.Length - 1; if (n == 0) { _table = null; } else { object[] newTable = new object[n]; Array.Copy(_table, 0, newTable, 0, index); Array.Copy(_table, index+1, newTable, index, n-index); _table = newTable; } // mark the id as absent _bitmask &= ~(0x1u << id); } } // return the index within the table, -1 if not present private int IndexOf(int id) { return HasValue(id) ? GetIndex(id) : -1; } // return the index within the table, 1's complement if not present private int Find(int id) { int index = GetIndex(id); if (!HasValue(id)) { index = ~index; } return index; } // get the index for the given id: the number of 1-bits in _bitmask // to the right of the bit for the id. private int GetIndex(int id) { unchecked // the multiplication in step 5 will overflow - we don't need the overflowing bits { // we count the bits in parallel, using 32-bit operations. This // is an old technique - Knuth says it was known in the 1950's. // See The Art of Computer Programming 7.1.3-(62). // 1. Discard the bits at or above the given id uint x = (_bitmask << (31 - id)) << 1; // (x<<32) is undefined // 2. Replace each 2-bit chunk with the count of 1's in that chunk x -= (x>>1) & 0x55555555u; // 3. Accumulate the counts within each 4-bit chunk x = (x & 0x33333333u) + ((x>>2) & 0x33333333u); // 4. Accumulate the counts within each 8-bit chunk (i.e. byte) x = (x + (x>>4)) & 0x0F0F0F0Fu; // 5. Sum the byte counts into the msb, and move the answer back to the lsb return (int) ((x * 0x01010101u) >> 24); // this method is often better than table-lookup methods, as it avoids // cache-misses on the table. Everything happens in registers. } } private object[] _table; private uint _bitmask; } }