Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / PropertyStore.cs / 1305376 / PropertyStore.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Windows.Forms { using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; ////// This is a small class that can efficiently store property values. /// It tries to optimize for size first, "get" access second, and /// "set" access third. /// internal class PropertyStore { private static int currentKey; private IntegerEntry[] intEntries; private ObjectEntry[] objEntries; ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public bool ContainsInteger(int key) { bool found; GetInteger(key, out found); return found; } ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public bool ContainsObject(int key) { bool found; GetObject(key, out found); return found; } ////// Creates a new key for this property store. This is NOT /// guarded by any thread safety so if you are calling it on /// multiple threads you should guard. For our purposes, /// we're fine because this is designed to be called in a class /// initializer, and we never have the same class hierarchy /// initializing on multiple threads at once. /// public static int CreateKey() { return currentKey++; } public Color GetColor(int key) { bool found; return GetColor(key, out found); } // this is a wrapper around GetObject designed to // reduce the boxing hit public Color GetColor(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { ColorWrapper wrapper = storedObject as ColorWrapper; if (wrapper != null) { return wrapper.Color; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a color wrapper stored in a color entry!\r\nDid someone SetObject instead of SetColor?"); } #endif } // we didnt actually find a non-null color wrapper. found = false; return Color.Empty; } public Padding GetPadding(int key) { bool found; return GetPadding(key, out found); } // this is a wrapper around GetObject designed to // reduce the boxing hit public Padding GetPadding(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { PaddingWrapper wrapper = storedObject as PaddingWrapper; if (wrapper != null) { return wrapper.Padding; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a padding wrapper stored in a padding entry!\r\nDid someone SetObject instead of SetPadding?"); } #endif } // we didnt actually find a non-null padding wrapper. found = false; return Padding.Empty; } #if false // FXCOP currently not used public Size GetSize(int key) { bool found; return GetSize(key, out found); } #endif // this is a wrapper around GetObject designed to // reduce the boxing hit public Size GetSize(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { SizeWrapper wrapper = storedObject as SizeWrapper; if (wrapper != null) { return wrapper.Size; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a padding wrapper stored in a padding entry!\r\nDid someone SetObject instead of SetPadding?"); } #endif } // we didnt actually find a non-null size wrapper. found = false; return Size.Empty; } public Rectangle GetRectangle(int key) { bool found; return GetRectangle(key, out found); } // this is a wrapper around GetObject designed to // reduce the boxing hit public Rectangle GetRectangle(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { RectangleWrapper wrapper = storedObject as RectangleWrapper; if (wrapper != null) { return wrapper.Rectangle; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a Rectangle wrapper stored in a Rectangle entry!\r\nDid someone SetObject instead of SetRectangle?"); } #endif } // we didnt actually find a non-null rectangle wrapper. found = false; return Rectangle.Empty; } ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public int GetInteger(int key) { bool found; return GetInteger(key, out found); } ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public int GetInteger(int key, out bool found) { int value = 0; int index; short element; short keyIndex = SplitKey(key, out element); found = false; if (LocateIntegerEntry(keyIndex, out index)) { // We have found the relevant entry. See if // the bitmask indicates the value is used. // if (((1 << element) & intEntries[index].Mask) != 0) { found = true; switch(element) { case 0: value = intEntries[index].Value1; break; case 1: value = intEntries[index].Value2; break; case 2: value = intEntries[index].Value3; break; case 3: value = intEntries[index].Value4; break; default: Debug.Fail("Invalid element obtained from LocateIntegerEntry"); break; } } } return value; } ////// Retrieves an object value from our property list. /// This will set value to null and return false if the /// list does not contain the given key. /// public object GetObject(int key) { bool found; return GetObject(key, out found); } ////// Retrieves an object value from our property list. /// This will set value to null and return false if the /// list does not contain the given key. /// public object GetObject(int key, out bool found) { object value = null; int index; short element; short keyIndex = SplitKey(key, out element); found = false; if (LocateObjectEntry(keyIndex, out index)) { // We have found the relevant entry. See if // the bitmask indicates the value is used. // if (((1 << element) & objEntries[index].Mask) != 0) { found = true; switch(element) { case 0: value = objEntries[index].Value1; break; case 1: value = objEntries[index].Value2; break; case 2: value = objEntries[index].Value3; break; case 3: value = objEntries[index].Value4; break; default: Debug.Fail("Invalid element obtained from LocateObjectEntry"); break; } } } return value; } ////// Locates the requested entry in our array if entries. This does /// not do the mask check to see if the entry is currently being used, /// but it does locate the entry. If the entry is found, this returns /// true and fills in index and element. If the entry is not found, /// this returns false. If the entry is not found, index will contain /// the insert point at which one would add a new element. /// private bool LocateIntegerEntry(short entryKey, out int index) { if (intEntries != null) { int length = intEntries.Length; if (length <= 16) { //if the array is small enough, we unroll the binary search to be more efficient. //usually the performance gain is around 10% to 20% //DON'T change this code unless you are very confident! index = 0; int midPoint = length / 2; if (intEntries[midPoint].Key <= entryKey) { index = midPoint; } //we don't move this inside the previous if branch since this catches both the case //index == 0 and index = midPoint if (intEntries[index].Key == entryKey) { return true; } midPoint = (length + 1) / 4; if (intEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (intEntries[index].Key == entryKey) { return true; } } midPoint = (length + 3) / 8; if (intEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (intEntries[index].Key == entryKey) { return true; } } midPoint = (length + 7) / 16; if (intEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (intEntries[index].Key == entryKey) { return true; } } Debug.Assert(index < length); if (entryKey > intEntries[index].Key) { index++; } Debug_VerifyLocateIntegerEntry(index, entryKey, length); return false; } else { // Entries are stored in numerical order by key index so we can // do a binary search on them. // int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = intEntries[idx].Key; if (currentKeyIndex == entryKey) { index = idx; return true; } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); // Didn't find the index. Setup our output // appropriately // index = idx; if (entryKey > intEntries[idx].Key) { index++; } return false; } } else { index = 0; return false; } } ////// Locates the requested entry in our array if entries. This does /// not do the mask check to see if the entry is currently being used, /// but it does locate the entry. If the entry is found, this returns /// true and fills in index and element. If the entry is not found, /// this returns false. If the entry is not found, index will contain /// the insert point at which one would add a new element. /// private bool LocateObjectEntry(short entryKey, out int index) { if (objEntries != null) { int length = objEntries.Length; Debug.Assert(length > 0); if (length <= 16) { //if the array is small enough, we unroll the binary search to be more efficient. //usually the performance gain is around 10% to 20% //DON'T change this code unless you are very confident! index = 0; int midPoint = length / 2; if (objEntries[midPoint].Key <= entryKey) { index = midPoint; } //we don't move this inside the previous if branch since this catches both the case //index == 0 and index = midPoint if (objEntries[index].Key == entryKey) { return true; } midPoint = (length + 1) / 4; if (objEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (objEntries[index].Key == entryKey) { return true; } } midPoint = (length + 3) / 8; if (objEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (objEntries[index].Key == entryKey) { return true; } } midPoint = (length + 7) / 16; if (objEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (objEntries[index].Key == entryKey) { return true; } } Debug.Assert(index < length); if (entryKey > objEntries[index].Key) { index++; } Debug_VerifyLocateObjectEntry(index, entryKey, length); return false; } else { // Entries are stored in numerical order by key index so we can // do a binary search on them. // int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = objEntries[idx].Key; if (currentKeyIndex == entryKey) { index = idx; return true; } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); // Didn't find the index. Setup our output // appropriately // index = idx; if (entryKey > objEntries[idx].Key) { index++; } return false; } } else { index = 0; return false; } } /* public Color RemoveColor(int key) { RemoveObject(key); } */ ////// Removes the given key from the array /// public void RemoveInteger(int key) { int index; short element; short entryKey = SplitKey(key, out element); if (LocateIntegerEntry(entryKey, out index)) { if (((1 << element) & intEntries[index].Mask) == 0) { // this element is not being used - return right away return; } // declare that the element is no longer used intEntries[index].Mask &= (short) (~((short)(1 << element))); if (intEntries[index].Mask == 0) { // this object entry is no longer in use - let's remove it all together // not great for perf but very simple and we don't expect to remove much IntegerEntry[] newEntries = new IntegerEntry[intEntries.Length - 1]; if (index > 0) { Array.Copy(intEntries, 0, newEntries, 0, index); } if (index < newEntries.Length) { Debug.Assert(intEntries.Length - index - 1 > 0); Array.Copy(intEntries, index + 1, newEntries, index, intEntries.Length - index - 1); } intEntries = newEntries; } else { // this object entry is still in use - let's just clean up the deleted element switch (element) { case 0: intEntries[index].Value1 = 0; break; case 1: intEntries[index].Value2 = 0; break; case 2: intEntries[index].Value3 = 0; break; case 3: intEntries[index].Value4 = 0; break; default: Debug.Fail("Invalid element obtained from LocateIntegerEntry"); break; } } } } ////// Removes the given key from the array /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public void RemoveObject(int key) { int index; short element; short entryKey = SplitKey(key, out element); if (LocateObjectEntry(entryKey, out index)) { if (((1 << element) & objEntries[index].Mask) == 0) { // this element is not being used - return right away return; } // declare that the element is no longer used objEntries[index].Mask &= (short)(~((short)(1 << element))); if (objEntries[index].Mask == 0) { // this object entry is no longer in use - let's remove it all together // not great for perf but very simple and we don't expect to remove much if (objEntries.Length == 1) { // instead of allocating an array of length 0, we simply reset the array to null. objEntries = null; } else { ObjectEntry[] newEntries = new ObjectEntry[objEntries.Length - 1]; if (index > 0) { Array.Copy(objEntries, 0, newEntries, 0, index); } if (index < newEntries.Length) { Debug.Assert(objEntries.Length - index - 1 > 0); Array.Copy(objEntries, index + 1, newEntries, index, objEntries.Length - index - 1); } objEntries = newEntries; } } else { // this object entry is still in use - let's just clean up the deleted element switch (element) { case 0: objEntries[index].Value1 = null; break; case 1: objEntries[index].Value2 = null; break; case 2: objEntries[index].Value3 = null; break; case 3: objEntries[index].Value4 = null; break; default: Debug.Fail("Invalid element obtained from LocateObjectEntry"); break; } } } } public void SetColor(int key, Color value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new ColorWrapper(value)); } else { ColorWrapper wrapper = storedObject as ColorWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Color = value; } else { Debug.Assert(storedObject == null, "object should either be null or ColorWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new ColorWrapper(value)); } } } public void SetPadding(int key, Padding value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new PaddingWrapper(value)); } else { PaddingWrapper wrapper = storedObject as PaddingWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Padding = value; } else { Debug.Assert(storedObject == null, "object should either be null or PaddingWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new PaddingWrapper(value)); } } } public void SetRectangle(int key, Rectangle value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new RectangleWrapper(value)); } else { RectangleWrapper wrapper = storedObject as RectangleWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Rectangle = value; } else { Debug.Assert(storedObject == null, "object should either be null or RectangleWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new RectangleWrapper(value)); } } } public void SetSize(int key, Size value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new SizeWrapper(value)); } else { SizeWrapper wrapper = storedObject as SizeWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Size = value; } else { Debug.Assert(storedObject == null, "object should either be null or SizeWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new SizeWrapper(value)); } } } ////// Stores the given value in the key. /// public void SetInteger(int key, int value) { int index; short element; short entryKey = SplitKey(key, out element); if (!LocateIntegerEntry(entryKey, out index)) { // We must allocate a new entry. // if (intEntries != null) { IntegerEntry[] newEntries = new IntegerEntry[intEntries.Length + 1]; if (index > 0) { Array.Copy(intEntries, 0, newEntries, 0, index); } if (intEntries.Length - index > 0) { Array.Copy(intEntries, index, newEntries, index + 1, intEntries.Length - index); } intEntries = newEntries; } else { intEntries = new IntegerEntry[1]; Debug.Assert(index == 0, "LocateIntegerEntry should have given us a zero index."); } intEntries[index].Key = entryKey; } // Now determine which value to set. // switch(element) { case 0: intEntries[index].Value1 = value; break; case 1: intEntries[index].Value2 = value; break; case 2: intEntries[index].Value3 = value; break; case 3: intEntries[index].Value4 = value; break; default: Debug.Fail("Invalid element obtained from LocateIntegerEntry"); break; } intEntries[index].Mask = (short)((1 << element) | (ushort)(intEntries[index].Mask)); } ////// Stores the given value in the key. /// public void SetObject(int key, object value) { int index; short element; short entryKey = SplitKey(key, out element); if (!LocateObjectEntry(entryKey, out index)) { // We must allocate a new entry. // if (objEntries != null) { ObjectEntry[] newEntries = new ObjectEntry[objEntries.Length + 1]; if (index > 0) { Array.Copy(objEntries, 0, newEntries, 0, index); } if (objEntries.Length - index > 0) { Array.Copy(objEntries, index, newEntries, index + 1, objEntries.Length - index); } objEntries = newEntries; } else { objEntries = new ObjectEntry[1]; Debug.Assert(index == 0, "LocateObjectEntry should have given us a zero index."); } objEntries[index].Key = entryKey; } // Now determine which value to set. // switch(element) { case 0: objEntries[index].Value1 = value; break; case 1: objEntries[index].Value2 = value; break; case 2: objEntries[index].Value3 = value; break; case 3: objEntries[index].Value4 = value; break; default: Debug.Fail("Invalid element obtained from LocateObjectEntry"); break; } objEntries[index].Mask = (short)((ushort)(objEntries[index].Mask)|(1 << element)); } ////// Takes the given key and splits it into an index /// and an element. /// private short SplitKey(int key, out short element) { element = (short)(key & 0x00000003); return (short)(key & 0xFFFFFFFC); } [Conditional("DEBUG_PROPERTYSTORE")] private void Debug_VerifyLocateIntegerEntry(int index, short entryKey, int length) { int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = intEntries[idx].Key; if (currentKeyIndex == entryKey) { Debug.Assert(index == idx, "GetIntegerEntry in property store broken. index is " + index + " while it should be " + idx + "length of the array is " + length); } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); // shouldn't find the index if we run this debug code if (entryKey > intEntries[idx].Key) { idx++; } Debug.Assert(index == idx, "GetIntegerEntry in property store broken. index is " + index + " while it should be " + idx + "length of the array is " + length); } [Conditional("DEBUG_PROPERTYSTORE")] private void Debug_VerifyLocateObjectEntry(int index, short entryKey, int length) { int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = objEntries[idx].Key; if (currentKeyIndex == entryKey) { Debug.Assert(index == idx, "GetObjEntry in property store broken. index is " + index + " while is should be " + idx + "length of the array is " + length); } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); if (entryKey > objEntries[idx].Key) { idx++; } Debug.Assert(index == idx, "GetObjEntry in property store broken. index is " + index + " while is should be " + idx + "length of the array is " + length); } ////// Stores the relationship between a key and a value. /// We do not want to be so inefficient that we require /// four bytes for each four byte property, so use an algorithm /// that uses the bottom two bits of the key to identify /// one of four elements in an entry. /// private struct IntegerEntry { public short Key; public short Mask; // only lower four bits are used; mask of used values. public int Value1; public int Value2; public int Value3; public int Value4; } ////// Stores the relationship between a key and a value. /// We do not want to be so inefficient that we require /// four bytes for each four byte property, so use an algorithm /// that uses the bottom two bits of the key to identify /// one of four elements in an entry. /// private struct ObjectEntry { public short Key; public short Mask; // only lower four bits are used; mask of used values. public object Value1; public object Value2; public object Value3; public object Value4; } private sealed class ColorWrapper { public Color Color; public ColorWrapper(Color color){ this.Color = color; } } private sealed class PaddingWrapper{ public Padding Padding; public PaddingWrapper(Padding padding){ this.Padding = padding; } } private sealed class RectangleWrapper{ public Rectangle Rectangle; public RectangleWrapper(Rectangle rectangle){ this.Rectangle = rectangle; } } private sealed class SizeWrapper { public Size Size; public SizeWrapper(Size size){ this.Size = size; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Windows.Forms { using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; ////// This is a small class that can efficiently store property values. /// It tries to optimize for size first, "get" access second, and /// "set" access third. /// internal class PropertyStore { private static int currentKey; private IntegerEntry[] intEntries; private ObjectEntry[] objEntries; ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public bool ContainsInteger(int key) { bool found; GetInteger(key, out found); return found; } ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public bool ContainsObject(int key) { bool found; GetObject(key, out found); return found; } ////// Creates a new key for this property store. This is NOT /// guarded by any thread safety so if you are calling it on /// multiple threads you should guard. For our purposes, /// we're fine because this is designed to be called in a class /// initializer, and we never have the same class hierarchy /// initializing on multiple threads at once. /// public static int CreateKey() { return currentKey++; } public Color GetColor(int key) { bool found; return GetColor(key, out found); } // this is a wrapper around GetObject designed to // reduce the boxing hit public Color GetColor(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { ColorWrapper wrapper = storedObject as ColorWrapper; if (wrapper != null) { return wrapper.Color; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a color wrapper stored in a color entry!\r\nDid someone SetObject instead of SetColor?"); } #endif } // we didnt actually find a non-null color wrapper. found = false; return Color.Empty; } public Padding GetPadding(int key) { bool found; return GetPadding(key, out found); } // this is a wrapper around GetObject designed to // reduce the boxing hit public Padding GetPadding(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { PaddingWrapper wrapper = storedObject as PaddingWrapper; if (wrapper != null) { return wrapper.Padding; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a padding wrapper stored in a padding entry!\r\nDid someone SetObject instead of SetPadding?"); } #endif } // we didnt actually find a non-null padding wrapper. found = false; return Padding.Empty; } #if false // FXCOP currently not used public Size GetSize(int key) { bool found; return GetSize(key, out found); } #endif // this is a wrapper around GetObject designed to // reduce the boxing hit public Size GetSize(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { SizeWrapper wrapper = storedObject as SizeWrapper; if (wrapper != null) { return wrapper.Size; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a padding wrapper stored in a padding entry!\r\nDid someone SetObject instead of SetPadding?"); } #endif } // we didnt actually find a non-null size wrapper. found = false; return Size.Empty; } public Rectangle GetRectangle(int key) { bool found; return GetRectangle(key, out found); } // this is a wrapper around GetObject designed to // reduce the boxing hit public Rectangle GetRectangle(int key, out bool found) { object storedObject = GetObject(key, out found); if (found) { RectangleWrapper wrapper = storedObject as RectangleWrapper; if (wrapper != null) { return wrapper.Rectangle; } #if DEBUG else if (storedObject != null) { Debug.Fail("Have non-null object that isnt a Rectangle wrapper stored in a Rectangle entry!\r\nDid someone SetObject instead of SetRectangle?"); } #endif } // we didnt actually find a non-null rectangle wrapper. found = false; return Rectangle.Empty; } ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public int GetInteger(int key) { bool found; return GetInteger(key, out found); } ////// Retrieves an integer value from our property list. /// This will set value to zero and return false if the /// list does not contain the given key. /// public int GetInteger(int key, out bool found) { int value = 0; int index; short element; short keyIndex = SplitKey(key, out element); found = false; if (LocateIntegerEntry(keyIndex, out index)) { // We have found the relevant entry. See if // the bitmask indicates the value is used. // if (((1 << element) & intEntries[index].Mask) != 0) { found = true; switch(element) { case 0: value = intEntries[index].Value1; break; case 1: value = intEntries[index].Value2; break; case 2: value = intEntries[index].Value3; break; case 3: value = intEntries[index].Value4; break; default: Debug.Fail("Invalid element obtained from LocateIntegerEntry"); break; } } } return value; } ////// Retrieves an object value from our property list. /// This will set value to null and return false if the /// list does not contain the given key. /// public object GetObject(int key) { bool found; return GetObject(key, out found); } ////// Retrieves an object value from our property list. /// This will set value to null and return false if the /// list does not contain the given key. /// public object GetObject(int key, out bool found) { object value = null; int index; short element; short keyIndex = SplitKey(key, out element); found = false; if (LocateObjectEntry(keyIndex, out index)) { // We have found the relevant entry. See if // the bitmask indicates the value is used. // if (((1 << element) & objEntries[index].Mask) != 0) { found = true; switch(element) { case 0: value = objEntries[index].Value1; break; case 1: value = objEntries[index].Value2; break; case 2: value = objEntries[index].Value3; break; case 3: value = objEntries[index].Value4; break; default: Debug.Fail("Invalid element obtained from LocateObjectEntry"); break; } } } return value; } ////// Locates the requested entry in our array if entries. This does /// not do the mask check to see if the entry is currently being used, /// but it does locate the entry. If the entry is found, this returns /// true and fills in index and element. If the entry is not found, /// this returns false. If the entry is not found, index will contain /// the insert point at which one would add a new element. /// private bool LocateIntegerEntry(short entryKey, out int index) { if (intEntries != null) { int length = intEntries.Length; if (length <= 16) { //if the array is small enough, we unroll the binary search to be more efficient. //usually the performance gain is around 10% to 20% //DON'T change this code unless you are very confident! index = 0; int midPoint = length / 2; if (intEntries[midPoint].Key <= entryKey) { index = midPoint; } //we don't move this inside the previous if branch since this catches both the case //index == 0 and index = midPoint if (intEntries[index].Key == entryKey) { return true; } midPoint = (length + 1) / 4; if (intEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (intEntries[index].Key == entryKey) { return true; } } midPoint = (length + 3) / 8; if (intEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (intEntries[index].Key == entryKey) { return true; } } midPoint = (length + 7) / 16; if (intEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (intEntries[index].Key == entryKey) { return true; } } Debug.Assert(index < length); if (entryKey > intEntries[index].Key) { index++; } Debug_VerifyLocateIntegerEntry(index, entryKey, length); return false; } else { // Entries are stored in numerical order by key index so we can // do a binary search on them. // int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = intEntries[idx].Key; if (currentKeyIndex == entryKey) { index = idx; return true; } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); // Didn't find the index. Setup our output // appropriately // index = idx; if (entryKey > intEntries[idx].Key) { index++; } return false; } } else { index = 0; return false; } } ////// Locates the requested entry in our array if entries. This does /// not do the mask check to see if the entry is currently being used, /// but it does locate the entry. If the entry is found, this returns /// true and fills in index and element. If the entry is not found, /// this returns false. If the entry is not found, index will contain /// the insert point at which one would add a new element. /// private bool LocateObjectEntry(short entryKey, out int index) { if (objEntries != null) { int length = objEntries.Length; Debug.Assert(length > 0); if (length <= 16) { //if the array is small enough, we unroll the binary search to be more efficient. //usually the performance gain is around 10% to 20% //DON'T change this code unless you are very confident! index = 0; int midPoint = length / 2; if (objEntries[midPoint].Key <= entryKey) { index = midPoint; } //we don't move this inside the previous if branch since this catches both the case //index == 0 and index = midPoint if (objEntries[index].Key == entryKey) { return true; } midPoint = (length + 1) / 4; if (objEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (objEntries[index].Key == entryKey) { return true; } } midPoint = (length + 3) / 8; if (objEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (objEntries[index].Key == entryKey) { return true; } } midPoint = (length + 7) / 16; if (objEntries[index + midPoint].Key <= entryKey) { index += midPoint; if (objEntries[index].Key == entryKey) { return true; } } Debug.Assert(index < length); if (entryKey > objEntries[index].Key) { index++; } Debug_VerifyLocateObjectEntry(index, entryKey, length); return false; } else { // Entries are stored in numerical order by key index so we can // do a binary search on them. // int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = objEntries[idx].Key; if (currentKeyIndex == entryKey) { index = idx; return true; } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); // Didn't find the index. Setup our output // appropriately // index = idx; if (entryKey > objEntries[idx].Key) { index++; } return false; } } else { index = 0; return false; } } /* public Color RemoveColor(int key) { RemoveObject(key); } */ ////// Removes the given key from the array /// public void RemoveInteger(int key) { int index; short element; short entryKey = SplitKey(key, out element); if (LocateIntegerEntry(entryKey, out index)) { if (((1 << element) & intEntries[index].Mask) == 0) { // this element is not being used - return right away return; } // declare that the element is no longer used intEntries[index].Mask &= (short) (~((short)(1 << element))); if (intEntries[index].Mask == 0) { // this object entry is no longer in use - let's remove it all together // not great for perf but very simple and we don't expect to remove much IntegerEntry[] newEntries = new IntegerEntry[intEntries.Length - 1]; if (index > 0) { Array.Copy(intEntries, 0, newEntries, 0, index); } if (index < newEntries.Length) { Debug.Assert(intEntries.Length - index - 1 > 0); Array.Copy(intEntries, index + 1, newEntries, index, intEntries.Length - index - 1); } intEntries = newEntries; } else { // this object entry is still in use - let's just clean up the deleted element switch (element) { case 0: intEntries[index].Value1 = 0; break; case 1: intEntries[index].Value2 = 0; break; case 2: intEntries[index].Value3 = 0; break; case 3: intEntries[index].Value4 = 0; break; default: Debug.Fail("Invalid element obtained from LocateIntegerEntry"); break; } } } } ////// Removes the given key from the array /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public void RemoveObject(int key) { int index; short element; short entryKey = SplitKey(key, out element); if (LocateObjectEntry(entryKey, out index)) { if (((1 << element) & objEntries[index].Mask) == 0) { // this element is not being used - return right away return; } // declare that the element is no longer used objEntries[index].Mask &= (short)(~((short)(1 << element))); if (objEntries[index].Mask == 0) { // this object entry is no longer in use - let's remove it all together // not great for perf but very simple and we don't expect to remove much if (objEntries.Length == 1) { // instead of allocating an array of length 0, we simply reset the array to null. objEntries = null; } else { ObjectEntry[] newEntries = new ObjectEntry[objEntries.Length - 1]; if (index > 0) { Array.Copy(objEntries, 0, newEntries, 0, index); } if (index < newEntries.Length) { Debug.Assert(objEntries.Length - index - 1 > 0); Array.Copy(objEntries, index + 1, newEntries, index, objEntries.Length - index - 1); } objEntries = newEntries; } } else { // this object entry is still in use - let's just clean up the deleted element switch (element) { case 0: objEntries[index].Value1 = null; break; case 1: objEntries[index].Value2 = null; break; case 2: objEntries[index].Value3 = null; break; case 3: objEntries[index].Value4 = null; break; default: Debug.Fail("Invalid element obtained from LocateObjectEntry"); break; } } } } public void SetColor(int key, Color value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new ColorWrapper(value)); } else { ColorWrapper wrapper = storedObject as ColorWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Color = value; } else { Debug.Assert(storedObject == null, "object should either be null or ColorWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new ColorWrapper(value)); } } } public void SetPadding(int key, Padding value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new PaddingWrapper(value)); } else { PaddingWrapper wrapper = storedObject as PaddingWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Padding = value; } else { Debug.Assert(storedObject == null, "object should either be null or PaddingWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new PaddingWrapper(value)); } } } public void SetRectangle(int key, Rectangle value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new RectangleWrapper(value)); } else { RectangleWrapper wrapper = storedObject as RectangleWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Rectangle = value; } else { Debug.Assert(storedObject == null, "object should either be null or RectangleWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new RectangleWrapper(value)); } } } public void SetSize(int key, Size value) { bool found; object storedObject = GetObject(key, out found); if (!found) { SetObject(key, new SizeWrapper(value)); } else { SizeWrapper wrapper = storedObject as SizeWrapper; if(wrapper != null) { // re-using the wrapper reduces the boxing hit. wrapper.Size = value; } else { Debug.Assert(storedObject == null, "object should either be null or SizeWrapper"); // could someone have SetObject to this key behind our backs? SetObject(key, new SizeWrapper(value)); } } } ////// Stores the given value in the key. /// public void SetInteger(int key, int value) { int index; short element; short entryKey = SplitKey(key, out element); if (!LocateIntegerEntry(entryKey, out index)) { // We must allocate a new entry. // if (intEntries != null) { IntegerEntry[] newEntries = new IntegerEntry[intEntries.Length + 1]; if (index > 0) { Array.Copy(intEntries, 0, newEntries, 0, index); } if (intEntries.Length - index > 0) { Array.Copy(intEntries, index, newEntries, index + 1, intEntries.Length - index); } intEntries = newEntries; } else { intEntries = new IntegerEntry[1]; Debug.Assert(index == 0, "LocateIntegerEntry should have given us a zero index."); } intEntries[index].Key = entryKey; } // Now determine which value to set. // switch(element) { case 0: intEntries[index].Value1 = value; break; case 1: intEntries[index].Value2 = value; break; case 2: intEntries[index].Value3 = value; break; case 3: intEntries[index].Value4 = value; break; default: Debug.Fail("Invalid element obtained from LocateIntegerEntry"); break; } intEntries[index].Mask = (short)((1 << element) | (ushort)(intEntries[index].Mask)); } ////// Stores the given value in the key. /// public void SetObject(int key, object value) { int index; short element; short entryKey = SplitKey(key, out element); if (!LocateObjectEntry(entryKey, out index)) { // We must allocate a new entry. // if (objEntries != null) { ObjectEntry[] newEntries = new ObjectEntry[objEntries.Length + 1]; if (index > 0) { Array.Copy(objEntries, 0, newEntries, 0, index); } if (objEntries.Length - index > 0) { Array.Copy(objEntries, index, newEntries, index + 1, objEntries.Length - index); } objEntries = newEntries; } else { objEntries = new ObjectEntry[1]; Debug.Assert(index == 0, "LocateObjectEntry should have given us a zero index."); } objEntries[index].Key = entryKey; } // Now determine which value to set. // switch(element) { case 0: objEntries[index].Value1 = value; break; case 1: objEntries[index].Value2 = value; break; case 2: objEntries[index].Value3 = value; break; case 3: objEntries[index].Value4 = value; break; default: Debug.Fail("Invalid element obtained from LocateObjectEntry"); break; } objEntries[index].Mask = (short)((ushort)(objEntries[index].Mask)|(1 << element)); } ////// Takes the given key and splits it into an index /// and an element. /// private short SplitKey(int key, out short element) { element = (short)(key & 0x00000003); return (short)(key & 0xFFFFFFFC); } [Conditional("DEBUG_PROPERTYSTORE")] private void Debug_VerifyLocateIntegerEntry(int index, short entryKey, int length) { int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = intEntries[idx].Key; if (currentKeyIndex == entryKey) { Debug.Assert(index == idx, "GetIntegerEntry in property store broken. index is " + index + " while it should be " + idx + "length of the array is " + length); } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); // shouldn't find the index if we run this debug code if (entryKey > intEntries[idx].Key) { idx++; } Debug.Assert(index == idx, "GetIntegerEntry in property store broken. index is " + index + " while it should be " + idx + "length of the array is " + length); } [Conditional("DEBUG_PROPERTYSTORE")] private void Debug_VerifyLocateObjectEntry(int index, short entryKey, int length) { int max = length - 1; int min = 0; int idx = 0; do { idx = (max + min) / 2; short currentKeyIndex = objEntries[idx].Key; if (currentKeyIndex == entryKey) { Debug.Assert(index == idx, "GetObjEntry in property store broken. index is " + index + " while is should be " + idx + "length of the array is " + length); } else if (entryKey < currentKeyIndex) { max = idx - 1; } else { min = idx + 1; } } while (max >= min); if (entryKey > objEntries[idx].Key) { idx++; } Debug.Assert(index == idx, "GetObjEntry in property store broken. index is " + index + " while is should be " + idx + "length of the array is " + length); } ////// Stores the relationship between a key and a value. /// We do not want to be so inefficient that we require /// four bytes for each four byte property, so use an algorithm /// that uses the bottom two bits of the key to identify /// one of four elements in an entry. /// private struct IntegerEntry { public short Key; public short Mask; // only lower four bits are used; mask of used values. public int Value1; public int Value2; public int Value3; public int Value4; } ////// Stores the relationship between a key and a value. /// We do not want to be so inefficient that we require /// four bytes for each four byte property, so use an algorithm /// that uses the bottom two bits of the key to identify /// one of four elements in an entry. /// private struct ObjectEntry { public short Key; public short Mask; // only lower four bits are used; mask of used values. public object Value1; public object Value2; public object Value3; public object Value4; } private sealed class ColorWrapper { public Color Color; public ColorWrapper(Color color){ this.Color = color; } } private sealed class PaddingWrapper{ public Padding Padding; public PaddingWrapper(Padding padding){ this.Padding = padding; } } private sealed class RectangleWrapper{ public Rectangle Rectangle; public RectangleWrapper(Rectangle rectangle){ this.Rectangle = rectangle; } } private sealed class SizeWrapper { public Size Size; public SizeWrapper(Size size){ this.Size = size; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ColumnWidthChangingEvent.cs
- RawStylusActions.cs
- SqlDataSourceSelectingEventArgs.cs
- RtfToXamlReader.cs
- UpdateProgress.cs
- JulianCalendar.cs
- OLEDB_Enum.cs
- ValueTypeFixupInfo.cs
- StickyNote.cs
- MsmqMessageSerializationFormat.cs
- MergablePropertyAttribute.cs
- SByteConverter.cs
- SessionEndingCancelEventArgs.cs
- DynamicValueConverter.cs
- WebUtil.cs
- COM2FontConverter.cs
- XmlSignificantWhitespace.cs
- ToolStripMenuItem.cs
- ControlParameter.cs
- BitmapEffectDrawing.cs
- CharKeyFrameCollection.cs
- Typography.cs
- CodeNamespaceCollection.cs
- WebPartVerb.cs
- RootDesignerSerializerAttribute.cs
- IPHostEntry.cs
- WCFServiceClientProxyGenerator.cs
- Pipe.cs
- ClipboardData.cs
- TextRangeAdaptor.cs
- ModelTreeEnumerator.cs
- NetworkInformationException.cs
- QueueProcessor.cs
- ListViewAutomationPeer.cs
- InputBuffer.cs
- Win32.cs
- SpecialTypeDataContract.cs
- XmlDataImplementation.cs
- AsyncPostBackErrorEventArgs.cs
- SerialReceived.cs
- Transactions.cs
- SymLanguageType.cs
- WorkItem.cs
- TreeNodeBindingCollection.cs
- ConfigXmlAttribute.cs
- ExecutionEngineException.cs
- DataGridBoundColumn.cs
- ImageListStreamer.cs
- ThrowHelper.cs
- ExpandableObjectConverter.cs
- ISAPIApplicationHost.cs
- HostingEnvironment.cs
- TreeChangeInfo.cs
- BitmapMetadataEnumerator.cs
- ToolZone.cs
- BuildResultCache.cs
- UnionQueryOperator.cs
- EditorZoneBase.cs
- ValueTable.cs
- ManagedWndProcTracker.cs
- StoreItemCollection.cs
- RuleInfoComparer.cs
- PerformanceCounterNameAttribute.cs
- VectorCollection.cs
- DateTimeOffset.cs
- RangeValueProviderWrapper.cs
- Profiler.cs
- Substitution.cs
- CodeComment.cs
- MailHeaderInfo.cs
- LambdaCompiler.Logical.cs
- InstancePersistenceException.cs
- GridViewSelectEventArgs.cs
- LinearGradientBrush.cs
- Effect.cs
- securitymgrsite.cs
- CodeBlockBuilder.cs
- TreeNodeBindingDepthConverter.cs
- Repeater.cs
- ListQueryResults.cs
- PerformanceCounterManager.cs
- NotifyInputEventArgs.cs
- TaskbarItemInfo.cs
- X509Utils.cs
- SortFieldComparer.cs
- ThreadStaticAttribute.cs
- DisplayMemberTemplateSelector.cs
- Model3DGroup.cs
- panel.cs
- QueryStringParameter.cs
- Track.cs
- ActivityTrace.cs
- NamedPipeHostedTransportConfiguration.cs
- HttpWebRequestElement.cs
- DataSourceControl.cs
- SeparatorAutomationPeer.cs
- TypeCacheManager.cs
- WebAdminConfigurationHelper.cs
- XmlSchemaImport.cs
- KeyGestureValueSerializer.cs