Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Linq / Parallel / Utils / Lookup.cs / 1305376 / Lookup.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // Lookup.cs // //[....] // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; namespace System.Linq.Parallel { ////// Lookup class implements the ILookup interface. Lookup is very similar to a dictionary /// except multiple values are allowed to map to the same key, and null keys are supported. /// /// Support for null keys adds an issue because the Dictionary class Lookup uses for /// storage does not support null keys. So, we need to treat null keys separately. /// Unfortunately, since TKey may be a value type, we cannot test whether the key is null /// using the user-specified equality comparer. /// /// C# does allow us to compare the key against null using the == operator, but there is a /// possibility that the user's equality comparer considers null to be equal to other values. /// Now, MSDN documentation specifies that if IEqualityComparer.Equals(x,y) returns true, it /// must be the case that x and y have the same hash code, and null has no hash code. Despite /// that, we might as well support the use case, even if it is bad practice. /// /// The solution the Lookup class uses is to treat the key default(TKey) as a special case, /// and hold its associated grouping - if any - in a special field instead of inserting it /// into a dictionary. /// ////// internal class Lookup : ILookup { private IDictionary > m_dict; private IEqualityComparer m_comparer; private IGrouping m_defaultKeyGrouping = null; internal Lookup(IEqualityComparer comparer) { m_comparer = comparer; m_dict = new Dictionary >(m_comparer); } public int Count { get { int count = m_dict.Count; if (m_defaultKeyGrouping != null) { count++; } return count; } } // Returns an empty sequence if the key is not in the lookup. public IEnumerable this[TKey key] { get { if (m_comparer.Equals(key, default(TKey))) { if (m_defaultKeyGrouping != null) { return m_defaultKeyGrouping; } return Enumerable.Empty (); } else { IGrouping grouping; if (m_dict.TryGetValue(key, out grouping)) { return grouping; } return Enumerable.Empty (); } } } public bool Contains(TKey key) { if (m_comparer.Equals(key, default(TKey))) { return m_defaultKeyGrouping != null; } else { return m_dict.ContainsKey(key); } } // // Adds a grouping to the lookup // // Note: The grouping should be cheap to enumerate (IGrouping extends IEnumerable), as // it may be enumerated multiple times depending how the user manipulates the lookup. // Our code must guarantee that we never attempt to insert two groupings with the same // key into a lookup. // internal void Add(IGrouping grouping) { if (m_comparer.Equals(grouping.Key, default(TKey))) { Contract.Assert(m_defaultKeyGrouping == null, "Cannot insert two groupings with the default key into a lookup."); m_defaultKeyGrouping = grouping; } else { Contract.Assert(!m_dict.ContainsKey(grouping.Key)); m_dict.Add(grouping.Key, grouping); } } public IEnumerator > GetEnumerator() { // First iterate over the groupings in the dictionary, and then over the default-key // grouping, if there is one. foreach (IGrouping grouping in m_dict.Values) { yield return grouping; } if (m_defaultKeyGrouping != null) { yield return m_defaultKeyGrouping; } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable >)this).GetEnumerator(); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // Lookup.cs // // [....] // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; namespace System.Linq.Parallel { ////// Lookup class implements the ILookup interface. Lookup is very similar to a dictionary /// except multiple values are allowed to map to the same key, and null keys are supported. /// /// Support for null keys adds an issue because the Dictionary class Lookup uses for /// storage does not support null keys. So, we need to treat null keys separately. /// Unfortunately, since TKey may be a value type, we cannot test whether the key is null /// using the user-specified equality comparer. /// /// C# does allow us to compare the key against null using the == operator, but there is a /// possibility that the user's equality comparer considers null to be equal to other values. /// Now, MSDN documentation specifies that if IEqualityComparer.Equals(x,y) returns true, it /// must be the case that x and y have the same hash code, and null has no hash code. Despite /// that, we might as well support the use case, even if it is bad practice. /// /// The solution the Lookup class uses is to treat the key default(TKey) as a special case, /// and hold its associated grouping - if any - in a special field instead of inserting it /// into a dictionary. /// ////// internal class Lookup : ILookup { private IDictionary > m_dict; private IEqualityComparer m_comparer; private IGrouping m_defaultKeyGrouping = null; internal Lookup(IEqualityComparer comparer) { m_comparer = comparer; m_dict = new Dictionary >(m_comparer); } public int Count { get { int count = m_dict.Count; if (m_defaultKeyGrouping != null) { count++; } return count; } } // Returns an empty sequence if the key is not in the lookup. public IEnumerable this[TKey key] { get { if (m_comparer.Equals(key, default(TKey))) { if (m_defaultKeyGrouping != null) { return m_defaultKeyGrouping; } return Enumerable.Empty (); } else { IGrouping grouping; if (m_dict.TryGetValue(key, out grouping)) { return grouping; } return Enumerable.Empty (); } } } public bool Contains(TKey key) { if (m_comparer.Equals(key, default(TKey))) { return m_defaultKeyGrouping != null; } else { return m_dict.ContainsKey(key); } } // // Adds a grouping to the lookup // // Note: The grouping should be cheap to enumerate (IGrouping extends IEnumerable), as // it may be enumerated multiple times depending how the user manipulates the lookup. // Our code must guarantee that we never attempt to insert two groupings with the same // key into a lookup. // internal void Add(IGrouping grouping) { if (m_comparer.Equals(grouping.Key, default(TKey))) { Contract.Assert(m_defaultKeyGrouping == null, "Cannot insert two groupings with the default key into a lookup."); m_defaultKeyGrouping = grouping; } else { Contract.Assert(!m_dict.ContainsKey(grouping.Key)); m_dict.Add(grouping.Key, grouping); } } public IEnumerator > GetEnumerator() { // First iterate over the groupings in the dictionary, and then over the default-key // grouping, if there is one. foreach (IGrouping grouping in m_dict.Values) { yield return grouping; } if (m_defaultKeyGrouping != null) { yield return m_defaultKeyGrouping; } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable >)this).GetEnumerator(); } } } // 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
- Types.cs
- DiscoveryClientBindingElement.cs
- TaskDesigner.cs
- LateBoundBitmapDecoder.cs
- WebPartZoneCollection.cs
- BrushConverter.cs
- SoapFormatter.cs
- CorePropertiesFilter.cs
- UserControlBuildProvider.cs
- IsolatedStorage.cs
- DBProviderConfigurationHandler.cs
- SystemIPGlobalProperties.cs
- KeyNotFoundException.cs
- HitTestResult.cs
- CollectionViewProxy.cs
- DrawListViewColumnHeaderEventArgs.cs
- EncoderBestFitFallback.cs
- HwndSourceKeyboardInputSite.cs
- _SingleItemRequestCache.cs
- ProxyWebPartConnectionCollection.cs
- SkipStoryboardToFill.cs
- RadioButtonRenderer.cs
- ApplicationFileCodeDomTreeGenerator.cs
- TreeNode.cs
- StaticTextPointer.cs
- NativeStructs.cs
- WindowsStatusBar.cs
- StoreItemCollection.Loader.cs
- XmlMemberMapping.cs
- SynchronousChannel.cs
- InputLanguageSource.cs
- _NegoState.cs
- SurrogateSelector.cs
- SignatureToken.cs
- GridViewColumnHeader.cs
- ScriptIgnoreAttribute.cs
- CalloutQueueItem.cs
- XmlSchemaFacet.cs
- EntityDataReader.cs
- MenuItem.cs
- HttpValueCollection.cs
- ListItemsPage.cs
- CapabilitiesState.cs
- NominalTypeEliminator.cs
- EventMappingSettingsCollection.cs
- AutomationElement.cs
- CommandManager.cs
- PersonalizationProviderCollection.cs
- PersistenceTypeAttribute.cs
- MetaColumn.cs
- PersonalizablePropertyEntry.cs
- HiddenField.cs
- DynamicUpdateCommand.cs
- SrgsRulesCollection.cs
- CSharpCodeProvider.cs
- DataMemberConverter.cs
- XmlValidatingReader.cs
- ProxyGenerationError.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- DBSqlParser.cs
- EntityKeyElement.cs
- TranslateTransform.cs
- LockedActivityGlyph.cs
- NavigationHelper.cs
- CaseStatement.cs
- FileDialog_Vista_Interop.cs
- ResourceManagerWrapper.cs
- SqlBulkCopy.cs
- ScrollItemProviderWrapper.cs
- StylusShape.cs
- XPathNavigatorKeyComparer.cs
- DataContext.cs
- PeerTransportCredentialType.cs
- WebPartCancelEventArgs.cs
- XmlEncodedRawTextWriter.cs
- BasicCommandTreeVisitor.cs
- MemberDescriptor.cs
- TrustManager.cs
- SplitterCancelEvent.cs
- GuidelineCollection.cs
- ForeignConstraint.cs
- ScriptReferenceEventArgs.cs
- PenThread.cs
- serverconfig.cs
- WebPartEditorOkVerb.cs
- XmlSchemaImport.cs
- XPathException.cs
- httpapplicationstate.cs
- MemberInitExpression.cs
- FontStretchConverter.cs
- HtmlTextViewAdapter.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- TemplateField.cs
- InternalTypeHelper.cs
- Int64AnimationBase.cs
- DefaultBinder.cs
- KeyProperty.cs
- GenerateTemporaryTargetAssembly.cs
- TrayIconDesigner.cs
- PreviewPrintController.cs