Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Data / System / Data / Selection.cs / 4 / Selection.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data { using System; using System.Diagnostics; using System.ComponentModel; using System.Collections.Generic; using System.Threading; internal struct IndexField { public readonly DataColumn Column; public readonly bool IsDescending; // false = Asc; true = Desc what is default value for this? internal IndexField(DataColumn column, bool isDescending) { Column = column; IsDescending = isDescending; } } internal sealed class Index { private sealed class IndexTree : RBTree{ private readonly Index _index; internal IndexTree(Index index) : base(TreeAccessMethod.KEY_SEARCH_AND_INDEX) { _index = index; } protected override int CompareNode (int record1, int record2) { return _index.CompareRecords(record1, record2); } protected override int CompareSateliteTreeNode (int record1, int record2) { return _index.CompareDuplicateRecords(record1, record2); } } // these constants are used to patch a DataRow when the record and Row are known, but don't match private const int DoNotReplaceCompareRecord = 0; private const int ReplaceNewRecordForCompare = 1; private const int ReplaceOldRecordForCompare = 2; private readonly DataTable table; internal readonly int[] IndexDesc; internal readonly IndexField[] IndexFields; /// Allow a user implemented comparision of two DataRow ///User must use correct DataRowVersion in comparison or index corruption will happen private readonly System.Comparison_comparison; private readonly DataViewRowState recordStates; private WeakReference rowFilter; private IndexTree records; private int recordCount; private int refCount; private Listeners _listeners; private bool suspendEvents; private readonly static object[] zeroObjects = new object[0]; private readonly bool isSharable; private readonly bool _hasRemoteAggregate; internal const Int32 MaskBits = unchecked((int)0x7FFFFFFF); private static int _objectTypeCount; // Bid counter private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); public Index(DataTable table, IndexField[] indexFields, DataViewRowState recordStates, IFilter rowFilter) : this(table, null, indexFields, recordStates, rowFilter) { } public Index(DataTable table, int[] ndexDesc, IndexField[] indexFields, DataViewRowState recordStates, IFilter rowFilter) : this(table, ndexDesc, indexFields, null, recordStates, rowFilter) { } public Index(DataTable table, System.Comparison comparison, DataViewRowState recordStates, IFilter rowFilter) : this(table, null, GetAllFields(table.Columns), comparison, recordStates, rowFilter) { } // for the delegate methods, we don't know what the dependent columns are - so all columns are dependent private static IndexField[] GetAllFields(DataColumnCollection columns) { IndexField[] fields = new IndexField[columns.Count]; for(int i = 0; i < fields.Length; ++i) { fields[i] = new IndexField(columns[i], false); } return fields; } private Index(DataTable table, int[] ndexDesc, IndexField[] indexFields, System.Comparison comparison, DataViewRowState recordStates, IFilter rowFilter) { Bid.Trace(" %d#, table=%d, recordStates=%d{ds.DataViewRowState}\n", ObjectID, (table != null) ? table.ObjectID : 0, (int)recordStates); Debug.Assert(indexFields != null); Debug.Assert(null != table, "null table"); if ((recordStates & (~(DataViewRowState.CurrentRows | DataViewRowState.OriginalRows))) != 0) { throw ExceptionBuilder.RecordStateRange(); } this.table = table; _listeners = new Listeners (ObjectID, delegate(DataViewListener listener) { return (null != listener); }); IndexDesc = ndexDesc; IndexFields = indexFields; if (null == ndexDesc) { IndexDesc = Select.ConvertIndexFieldtoIndexDesc(indexFields); } this.recordStates = recordStates; _comparison = comparison; DataColumnCollection columns = table.Columns; isSharable = (rowFilter == null) && (comparison == null); // a filter or comparison make an index unsharable if (null != rowFilter) { this.rowFilter = new WeakReference(rowFilter); DataExpression expr = (rowFilter as DataExpression); if (null != expr) { _hasRemoteAggregate = expr.HasRemoteAggregate(); } } InitRecords(rowFilter); // do not AddRef in ctor, every caller should be responsible to AddRef it // if caller does not AddRef, it is expected to be a one-time read operation because the index won't be maintained on writes } public bool Equal(IndexField[] indexDesc, DataViewRowState recordStates, IFilter rowFilter) { if ( !isSharable || IndexFields.Length != indexDesc.Length || this.recordStates != recordStates || null != rowFilter ) { return false; } for (int loop = 0; loop < IndexFields.Length; loop++) { if (IndexFields[loop].Column!= indexDesc[loop].Column || IndexFields[loop].IsDescending != indexDesc[loop].IsDescending) { return false; } } return true; } internal bool HasRemoteAggregate { get { return _hasRemoteAggregate; } } internal int ObjectID { get { return _objectID; } } public DataViewRowState RecordStates { get { return recordStates; } } public IFilter RowFilter { get { return (IFilter)((null != rowFilter) ? rowFilter.Target : null); } } public int GetRecord(int recordIndex) { Debug.Assert (recordIndex >= 0 && recordIndex < recordCount, "recordIndex out of range"); return records[recordIndex]; } public bool HasDuplicates { get { return records.HasDuplicates; } } public int RecordCount { get { return recordCount; } } public bool IsSharable { get { return isSharable; } } private bool AcceptRecord(int record) { return AcceptRecord(record, RowFilter); } private bool AcceptRecord(int record, IFilter filter) { Bid.Trace(" %d#, record=%d\n", ObjectID, record); if (filter == null) return true; DataRow row = table.recordManager[record]; if (row == null) return true; // DataRowVersion version = DataRowVersion.Default; if (row.oldRecord == record) { version = DataRowVersion.Original; } else if (row.newRecord == record) { version = DataRowVersion.Current; } else if (row.tempRecord == record) { version = DataRowVersion.Proposed; } return filter.Invoke(row, version); } /// Only call from inside a lock(this) internal void ListChangedAdd(DataViewListener listener) { _listeners.Add(listener); } ///Only call from inside a lock(this) internal void ListChangedRemove(DataViewListener listener) { _listeners.Remove(listener); } public int RefCount { get { return refCount; } } public void AddRef() { Bid.Trace("%d#\n", ObjectID); LockCookie lc = table.indexesLock.UpgradeToWriterLock(-1); try { Debug.Assert(0 <= refCount, "AddRef on disposed index"); Debug.Assert(null != records, "null records"); if (refCount == 0) { table.ShadowIndexCopy(); table.indexes.Add(this); } refCount++; } finally { table.indexesLock.DowngradeFromWriterLock(ref lc); } } public int RemoveRef() { Bid.Trace(" %d#\n", ObjectID); int count; LockCookie lc = table.indexesLock.UpgradeToWriterLock(-1); try { count = --refCount; if (refCount <= 0) { table.ShadowIndexCopy(); bool flag = table.indexes.Remove(this); Debug.Assert(flag, "Index did not exist in index collection"); } } finally { table.indexesLock.DowngradeFromWriterLock(ref lc); } return count; } private void ApplyChangeAction(int record, int action, int changeRecord) { if (action != 0) { if (action > 0) { if (AcceptRecord(record)) { InsertRecord(record, true); } } else if ((null != _comparison) && (-1 != record)) { // when removing a record, the DataRow has already been updated to the newer record // depending on changeRecord, either the new or old record needs be backdated to record // for Comparison to operate correctly DeleteRecord(GetIndex(record, changeRecord)); } else { // unnecessary codepath other than keeping original code path for redbits DeleteRecord(GetIndex(record)); } } } public bool CheckUnique() { #if DEBUG Debug.Assert(records.CheckUnique(records.root) != HasDuplicates, "CheckUnique difference"); #endif return !HasDuplicates; } // only used for main tree compare, not satalite tree private int CompareRecords(int record1, int record2) { if (null != _comparison) { return CompareDataRows(record1, record2); } if (0 < IndexFields.Length) { for (int i = 0; i < IndexFields.Length; i++) { int c = IndexFields[i].Column.Compare(record1, record2); if (c != 0) { return (IndexFields[i].IsDescending ? -c : c); } } return 0; } else { Debug.Assert(null != table.recordManager[record1], "record1 no datarow"); Debug.Assert(null != table.recordManager[record2], "record2 no datarow"); // DataRow needs to always patched appropriately via GetIndex(int,int) //table.recordManager.VerifyRecord(record1, table.recordManager[record1]); //table.recordManager.VerifyRecord(record2, table.recordManager[record2]); // Need to use compare because subtraction will wrap // to positive for very large neg numbers, etc. return table.Rows.IndexOf(table.recordManager[record1]).CompareTo(table.Rows.IndexOf(table.recordManager[record2])); } } private int CompareDataRows(int record1, int record2) { table.recordManager.VerifyRecord(record1, table.recordManager[record1]); table.recordManager.VerifyRecord(record2, table.recordManager[record2]); return _comparison(table.recordManager[record1], table.recordManager[record2]); } // PS: same as previous CompareRecords, except it compares row state if needed // only used for satalite tree compare private int CompareDuplicateRecords(int record1, int record2) { #if DEBUG if (null != _comparison) { Debug.Assert(0 == CompareDataRows(record1, record2), "duplicate record not a duplicate by user function"); } else if (record1 != record2) { for (int i = 0; i < IndexFields.Length; i++) { int c = IndexFields[i].Column.Compare(record1, record2); Debug.Assert(0 == c, "duplicate record not a duplicate"); } } #endif Debug.Assert(null != table.recordManager[record1], "record1 no datarow"); Debug.Assert(null != table.recordManager[record2], "record2 no datarow"); // DataRow needs to always patched appropriately via GetIndex(int,int) //table.recordManager.VerifyRecord(record1, table.recordManager[record1]); //table.recordManager.VerifyRecord(record2, table.recordManager[record2]); if (null == table.recordManager[record1]) { return ((null == table.recordManager[record2]) ? 0 : -1); } else if (null == table.recordManager[record2]) { return 1; } // Need to use compare because subtraction will wrap // to positive for very large neg numbers, etc. int diff = table.recordManager[record1].rowID.CompareTo(table.recordManager[record2].rowID); // if they're two records in the same row, we need to be able to distinguish them. if ((diff == 0) && (record1 != record2)) { diff = ((int)table.recordManager[record1].GetRecordState(record1)).CompareTo((int)table.recordManager[record2].GetRecordState(record2)); } return diff; } private int CompareRecordToKey(int record1, object[] vals) { for (int i = 0; i < IndexFields.Length; i++) { int c = IndexFields[i].Column.CompareValueTo(record1, vals[i]); if (c != 0) { return (IndexFields[i].IsDescending ? -c : c); } } return 0; } // DeleteRecordFromIndex deletes the given record from index and does not fire any Event. IT SHOULD NOT FIRE EVENT // I added this since I can not use existing DeleteRecord which is not silent operation public void DeleteRecordFromIndex(int recordIndex) { // this is for expression use, to maintain expression columns's sort , filter etc. do not fire event DeleteRecord(recordIndex, false); } // old and existing DeleteRecord behavior, we can not use this for silently deleting private void DeleteRecord(int recordIndex) { DeleteRecord(recordIndex, true); } private void DeleteRecord(int recordIndex, bool fireEvent) { Bid.Trace(" %d#, recordIndex=%d, fireEvent=%d{bool}\n", ObjectID, recordIndex, fireEvent); if (recordIndex >= 0) { recordCount--; int record = records.DeleteByIndex(recordIndex); MaintainDataView(ListChangedType.ItemDeleted, record, !fireEvent); if (fireEvent) { // 1) Webdata 104939 do not fix this, it would be breaking change // 2) newRecord = -1, oldrecord = recordIndex; OnListChanged(ListChangedType.ItemDeleted, recordIndex); } } } // public RBTree .RBTreeEnumerator GetEnumerator(int startIndex) { return new IndexTree.RBTreeEnumerator(records, startIndex); } // What it actually does is find the index in the records[] that // this record inhabits, and if it doesn't, suggests what index it would // inhabit while setting the high bit. // public int GetIndex(int record) { int index = records.GetIndexByKey(record); return index; } /// /// When searching by value for a specific record, the DataRow may require backdating to reflect the appropriate state /// otherwise on Delete of a DataRow in the Added state, would result in the private int GetIndex(int record, int changeRecord) { Debug.Assert(null != _comparison, "missing comparison"); int index; DataRow row = table.recordManager[record]; int a = row.newRecord; int b = row.oldRecord; try { switch(changeRecord) { case ReplaceNewRecordForCompare: row.newRecord = record; break; case ReplaceOldRecordForCompare: row.oldRecord = record; break; } table.recordManager.VerifyRecord(record, row); index = records.GetIndexByKey(record); } finally { switch(changeRecord) { case ReplaceNewRecordForCompare: Debug.Assert(record == row.newRecord, "newRecord has change during GetIndex"); row.newRecord = a; break; case ReplaceOldRecordForCompare: Debug.Assert(record == row.oldRecord, "oldRecord has change during GetIndex"); row.oldRecord = b; break; } #if DEBUG if (-1 != a) { table.recordManager.VerifyRecord(a, row); } #endif } return index; } public object[] GetUniqueKeyValues() { if (IndexFields == null || IndexFields.Length == 0) { return zeroObjects; } Listwhere the row /// reflection record would be in the Detatched instead of Added state. ///
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Flowchart.cs
- ConfigViewGenerator.cs
- MimeMapping.cs
- MembershipSection.cs
- ScriptMethodAttribute.cs
- AsyncCodeActivityContext.cs
- EntryPointNotFoundException.cs
- AddInToken.cs
- TextServicesCompartmentContext.cs
- ClientTargetSection.cs
- ConfigXmlText.cs
- _OSSOCK.cs
- OrderedDictionary.cs
- Object.cs
- Clause.cs
- WaitHandleCannotBeOpenedException.cs
- DataGridTableCollection.cs
- XmlSiteMapProvider.cs
- PartitionedStream.cs
- ServicePerformanceCounters.cs
- ProxyWebPartConnectionCollection.cs
- RSAPKCS1SignatureDeformatter.cs
- SmtpSection.cs
- ForEachAction.cs
- TreeViewImageKeyConverter.cs
- ConfigurationSectionCollection.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- UserNameSecurityTokenProvider.cs
- FormParameter.cs
- ObjectListCommandCollection.cs
- DataGridViewLinkColumn.cs
- MediaTimeline.cs
- FileUtil.cs
- XmlSchemaObject.cs
- QueuePathDialog.cs
- ReturnValue.cs
- WsatConfiguration.cs
- DataSpaceManager.cs
- StreamInfo.cs
- DSASignatureDeformatter.cs
- IdnMapping.cs
- sqlcontext.cs
- SerializationInfo.cs
- InfiniteTimeSpanConverter.cs
- ValueProviderWrapper.cs
- InputScopeAttribute.cs
- WorkflowRuntimeServiceElement.cs
- ErrorFormatterPage.cs
- CodeNamespaceImport.cs
- ConfigXmlWhitespace.cs
- SecurityKeyUsage.cs
- Query.cs
- SafeJobHandle.cs
- HtmlTable.cs
- NonPrimarySelectionGlyph.cs
- RegexCode.cs
- While.cs
- MethodAccessException.cs
- TableRow.cs
- NullRuntimeConfig.cs
- MailWebEventProvider.cs
- SplineKeyFrames.cs
- AlignmentXValidation.cs
- DefinitionBase.cs
- DataGridHeaderBorder.cs
- InfoCardAsymmetricCrypto.cs
- ToolBarTray.cs
- DataSvcMapFile.cs
- MetadataSource.cs
- SecurityException.cs
- InkSerializer.cs
- LookupBindingPropertiesAttribute.cs
- WebPartCatalogAddVerb.cs
- ObjectDataSource.cs
- AttachedPropertyMethodSelector.cs
- ButtonChrome.cs
- RSAPKCS1SignatureFormatter.cs
- RawKeyboardInputReport.cs
- InternalControlCollection.cs
- MethodToken.cs
- FocusWithinProperty.cs
- QueryContinueDragEvent.cs
- PersonalizationStateInfoCollection.cs
- HwndAppCommandInputProvider.cs
- PropertyItem.cs
- _UriTypeConverter.cs
- StylusTip.cs
- SelectorAutomationPeer.cs
- DocumentEventArgs.cs
- Membership.cs
- WindowsRegion.cs
- WmlLabelAdapter.cs
- FolderBrowserDialog.cs
- MetadataFile.cs
- UpdateEventArgs.cs
- LassoHelper.cs
- MutexSecurity.cs
- GcSettings.cs
- ColorBlend.cs
- NameValueSectionHandler.cs