| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026 |
- //------------------------------------------------------------------------------
- // <copyright file="Selection.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</owner>
- //------------------------------------------------------------------------------
- #if DEBUG
- //#define VerifyIndex
- #define VerifyPath
- #define VerifySort
- #endif
- namespace System.Data
- {
- using System;
- using System.Collections;
- using System.Data.Common;
- using System.Diagnostics;
- internal enum RBTreeError {
- InvalidPageSize = 1,
- // InvalidCompareDelegate = 2,
- PagePositionInSlotInUse = 3,
- NoFreeSlots = 4,
- InvalidStateinInsert = 5,
- // InvalidStateinEndInsert = 6,
- InvalidNextSizeInDelete = 7,
- InvalidStateinDelete = 8,
- InvalidNodeSizeinDelete = 9,
- InvalidStateinEndDelete = 10,
- CannotRotateInvalidsuccessorNodeinDelete = 11,
- // IndexOutOfRange = 12,
- IndexOutOFRangeinGetNodeByIndex = 13,
- RBDeleteFixup = 14,
- UnsupportedAccessMethod1 = 15,
- UnsupportedAccessMethod2 = 16,
- UnsupportedAccessMethodInNonNillRootSubtree = 17,
- AttachedNodeWithZerorbTreeNodeId = 18, // DataRowCollection
- CompareNodeInDataRowTree = 19, // DataRowCollection
- CompareSateliteTreeNodeInDataRowTree = 20, // DataRowCollection
- NestedSatelliteTreeEnumerator = 21,
- }
- internal enum TreeAccessMethod{
- KEY_SEARCH_AND_INDEX = 1,
- INDEX_ONLY = 2,
- }
- // an index represents location the tree
- // a tree has an array of pages (max 2^16) (top 16 bits)
- // a page has an array of nodes (max 2^16) (bottom 16 bits)
- // nodes are indexed by RBTree.PageTable[index>>16].Slots[index&0xFFFF]
- // a tree has an PageTableBitmap to indicate which allocated pages have free nodes
- // a page has a SlotBitmap to indicate which slots are free
- // intial page allocation (assuming no deletes)
- // #page * #slot = #total, #cumulative
- // ( 4) * 32 = 128, 127 (subtract 1 for NIL node)
- // ( 32 - 4) * 256 = 7168, 7,295
- // ( 128 - 32) * 1024 = 98304, 105,599
- // ( 4096 - 128) * 4096 = 16252928, 16,358,527
- // (32768 - 4096) * 8192 = 234881024, 251,239,551
- // (65535 - 32768) * 65536 = 2147418112, 2,398,657,663 (excess nodes 251,174,016 > Int32.MaxValue)
- // tree page size is GetIntValueFromBitMap(inUsePageCount) // return highest bit in array
- //private static readonly int[] PageSize = new int[17] { // nobit + 16 bits == 17 position
- // 32, 32, 32, // inUsePageCount < 4 0, 1, 2,
- // 256, 256, 256, // inUsePageCount < 32 4, 8, 16,
- // 1024, 1024, // inUsePageCount < 128 32, 64,
- // 4096, 4096, 4096, 4096, 4096, // inUsePageCount < 4096 128, 256, 512, 1024, 2048,
- // 8192, 8192, 8192, // inUsePageCount < 32768 4096, 8192, 16384
- // 65535 // inUsePageCount <= 65535
- //};
- // the in-ordering of nodes in the tree (the second graph has duplicate nodes)
- // for the satellite tree, the main tree node is the clone, GetNodeByIndex always returns the satelliteRootid
- // 4 | 4
- // / \ | / \
- // 2 6 | 3 - 3 7
- // / \ / \ | / \ / \ / \
- // 1 3 5 7 | 1 5 2 4 8 9
- // PageTable (starting at 32) doubles in size on demand (^16 - ^5 = 11 grows to reach max PageTable size)
- // if a page has no allocated slots, it will be dropped
- // worst case scenario is to repeatedly add/remove on a boundary condition
- // the primary change to support Index using Predicate<DataRow> or Comparison<DataRow> was to eliminate all
- // unnecessary searching for the node in the main tree when operating on a node in the satellite branch
- // in all cases except GetNodeByKey(K)& GetIndexByNode(int), we know what that mainTreeNodeID is and can avoid searching
- internal abstract class RBTree<K> : System.Collections.IEnumerable {
- // 2^16 #pages * 2^n == total number of nodes. 512 = 32 million, 1024 = 64 million, 2048 = 128m, 4096=256m, 8192=512m, 16284=1 billion
- // 32K=2 billion.
- internal const int DefaultPageSize = 32; /* 512 = 2^9 32 million nodes*/
- internal const int NIL = 0; // 0th page, 0th slot for each tree till CLR static & generics issue is fixed
- private TreePage[] _pageTable; // initial size 4, then doubles (grows) - it never shrinks
- private Int32[] _pageTableMap;
- private int _inUsePageCount = 0; // contains count of allocated pages per tree, its <= the capacity of pageTable
- private int nextFreePageLine; // used for keeping track of position of last used free page in pageTable
- public int root;
- private int _version;
- private int _inUseNodeCount = 0; // total number of nodes currently in use by this tree.
- private int _inUseSatelliteTreeCount = 0; // total number of satellite associated with this tree.
- private readonly TreeAccessMethod _accessMethod;
- protected abstract int CompareNode (K record1, K record2);
- protected abstract int CompareSateliteTreeNode (K record1, K record2);
- protected RBTree (TreeAccessMethod accessMethod) {
- _accessMethod = accessMethod;
- InitTree();
- }
- private void InitTree() {
- root = NIL;
- _pageTable = new TreePage[1 * TreePage.slotLineSize];
- _pageTableMap = new Int32[(_pageTable.Length + TreePage.slotLineSize - 1) / TreePage.slotLineSize]; // Ceiling(size)
- _inUsePageCount = 0;
- nextFreePageLine = 0;
- AllocPage (DefaultPageSize);
- // alloc storage for reserved NIL node. segment 0, slot 0; Initialize NIL
- _pageTable[0].Slots[0].nodeColor = NodeColor.black;
- _pageTable[0].SlotMap[0] = 0x1;
- _pageTable[0].InUseCount = 1;
- _inUseNodeCount = 1;
- _inUseSatelliteTreeCount = 0; // total number of satellite associated with this tree.
- }
- private void FreePage (TreePage page)
- {
- MarkPageFree (page);
- _pageTable[page.PageId] = null;
- _inUsePageCount--;
- }
- /* AllocPage()
- * size : Allocates a page of the specified size.
- *
- * Look for an unallocated page entry.
- * (1) If entry for an unallocated page exists in current pageTable - use it
- * (2) else extend pageTable
- */
- private TreePage AllocPage (int size)
- {
- int freePageIndex = GetIndexOfPageWithFreeSlot (false);
- if (freePageIndex != -1)
- {
- _pageTable[freePageIndex] = new TreePage (size);
- nextFreePageLine = freePageIndex / TreePage.slotLineSize;
- }
- else
- {
- // no free position found, increase pageTable size
- TreePage[] newPageTable = new TreePage[_pageTable.Length * 2];
- System.Array.Copy (_pageTable, 0, newPageTable, 0, _pageTable.Length);
- Int32[] newPageTableMap = new Int32[(newPageTable.Length + TreePage.slotLineSize - 1) / TreePage.slotLineSize];
- System.Array.Copy (_pageTableMap, 0, newPageTableMap, 0, _pageTableMap.Length);
- nextFreePageLine = _pageTableMap.Length;
- freePageIndex = _pageTable.Length;
- _pageTable = newPageTable;
- _pageTableMap = newPageTableMap;
- _pageTable[freePageIndex] = new TreePage (size);
- }
- _pageTable[freePageIndex].PageId = freePageIndex;
- _inUsePageCount++;
- return _pageTable[freePageIndex];
- }
- /* MarkPageFull()
- * Mark the specified page "Full" as all its slots aer in use
- */
- private void MarkPageFull (TreePage page)
- {
- // set bit associated with page to mark it as full
- /*
- int pageTableMapIndex = (page.PageId / TreePage.slotLineSize);
- int pageTableMapOffset = (page.PageId % TreePage.slotLineSize);
- Int32 pageBitMask = ((Int32)1) << pageTableMapOffset;
- _pageTableMap[pageTableMapIndex] |= (pageBitMask);
- */
- _pageTableMap[page.PageId / TreePage.slotLineSize] |= (1 << (page.PageId % TreePage.slotLineSize));
- }
- /* MarkPageFree()
- * Mark the specified page as "Free". It has atleast 1 available slot.
- */
- private void MarkPageFree (TreePage page)
- {
- // set bit associated with page to mark it as free
- /*
- int pageTableMapIndex = (page.PageId / TreePage.slotLineSize);
- int pageTableMapOffset = (page.PageId % TreePage.slotLineSize);
- Int32 pageBitMask = ((Int32)1) << pageTableMapOffset;
- _pageTableMap[pageTableMapIndex] &= ~(pageBitMask);
- */
- _pageTableMap[page.PageId / TreePage.slotLineSize] &= ~(1 << (page.PageId % TreePage.slotLineSize));
- }
- private static int GetIntValueFromBitMap (UInt32 bitMap)
- {
- Int32 value = 0; // 0 based slot position
- /*
- * Assumption: bitMap can have max, exactly 1 bit set.
- * convert bitMap to int value giving number of 0's to its right
- * return value between 0 and 31
- */
- if ((bitMap & 0xFFFF0000) != 0)
- {
- value += 16;
- bitMap >>=16;
- }
- if ((bitMap & 0x0000FF00) != 0)
- {
- value += 8;
- bitMap >>=8;
- }
- if ((bitMap & 0x000000F0) != 0)
- {
- value += 4;
- bitMap >>=4;
- }
- if ((bitMap & 0x0000000C) != 0)
- {
- value += 2;
- bitMap >>=2;
- }
- if ((bitMap & 0x00000002) != 0)
- value += 1;
- return value;
- }
- /*
- * FreeNode()
- * nodeId: The nodeId of the node to be freed
- */
- private void FreeNode (int nodeId)
- {
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex] = default(Node);
- // clear slotMap entry associated with nodeId
- page.SlotMap[slotIndex / TreePage.slotLineSize] &= ~( ((Int32)1) << (int)(slotIndex % TreePage.slotLineSize));
- page.InUseCount--;
- _inUseNodeCount--;
- if (page.InUseCount == 0)
- FreePage (page);
- else if (page.InUseCount == page.Slots.Length - 1)
- MarkPageFree (page); // With freeing of a node, a previous full page has a free slot.
- }
- /*
- * GetIndexOfPageWithFreeSlot()
- * allocatedPage: If true, look for an allocatedPage with free slot else look for an unallocated page entry in pageTable
- * return: if allocatedPage is true, return index of a page with at least 1 free slot
- * else return index of an unallocated page, pageTable[index] is empty.
- */
- private int GetIndexOfPageWithFreeSlot (bool allocatedPage)
- {
- int pageTableMapPos = nextFreePageLine;
- int pageIndex = -1;
- while (pageTableMapPos < _pageTableMap.Length)
- {
- if (((UInt32)_pageTableMap[pageTableMapPos]) < 0xFFFFFFFF)
- {
- UInt32 pageSegmentMap = (UInt32)_pageTableMap[pageTableMapPos];
- while ((pageSegmentMap ^ (0xFFFFFFFF)) != 0) //atleast one "0" is there (same as <0xFFFFFFFF)
- {
- UInt32 pageWithFreeSlot = (UInt32)((~(pageSegmentMap)) & (pageSegmentMap + 1));
- //
- if ((_pageTableMap[pageTableMapPos] & pageWithFreeSlot) != 0) //paranoia check
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.PagePositionInSlotInUse);
- pageIndex = (pageTableMapPos * TreePage.slotLineSize) + GetIntValueFromBitMap (pageWithFreeSlot); // segment + offset
- if (allocatedPage)
- {
- if (_pageTable[pageIndex] != null)
- return pageIndex;
- }
- else
- {
- if (_pageTable[pageIndex] == null)
- return pageIndex; // pageIndex points to an unallocated Page
- }
- pageIndex = -1;
- pageSegmentMap |= pageWithFreeSlot; // found "reset bit", but unallocated page, mark it as unavaiable and continue search
- }
- }
- pageTableMapPos++;
- }
- if (nextFreePageLine != 0)
- {
- //Try one more time, starting from 0th page segment position to locate a page with free slots
- nextFreePageLine = 0;
- pageIndex = GetIndexOfPageWithFreeSlot (allocatedPage);
- }
- return pageIndex;
- }
- public int Count {
- get {
- Debug.Assert(_inUseNodeCount-1 == SubTreeSize(root), "count mismatch");
- return (_inUseNodeCount-1);
- }
- }
- public bool HasDuplicates {
- get {
- return (0 != _inUseSatelliteTreeCount);
- }
- }
- /*
- * GetNewNode()
- * Allocate storage for a new node and assign in the specified key.
- *
- * Find a page with free slots or allocate a new page.
- * Use bitmap associated with page to allocate a slot.
- * mark the slot as used and return its index.
- */
- private int GetNewNode (K key)
- {
- // find page with free slots, if none, allocate a new page
- TreePage page = null;
- int freePageIndex = GetIndexOfPageWithFreeSlot (true);
- if (freePageIndex != -1)
- page = _pageTable[freePageIndex];
- else if (_inUsePageCount < (4))
- page = AllocPage (DefaultPageSize); // First 128 slots
- else if (_inUsePageCount < (32))
- page = AllocPage (256);
- else if (_inUsePageCount < (128))
- page = AllocPage (1024);
- else if (_inUsePageCount < (4096))
- page = AllocPage (4096);
- else if (_inUsePageCount < (32*1024))
- page = AllocPage (8192); // approximately First 16 million slots (2^24)
- else
- page = AllocPage (64*1024); // Page size to accomodate more than 16 million slots (Max 2 Billion and 16 million slots)
- // page contains atleast 1 free slot.
- int slotId = page.AllocSlot (this);
- //
- if (slotId == -1)
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.NoFreeSlots);
- // NodeId: Upper 16 bits pageId, lower bits slotId
- page.Slots[slotId].selfId = (int)(((UInt32)page.PageId) << 16) | slotId;
- Debug.Assert(page.Slots[slotId].leftId == NIL, "node not cleared");
- Debug.Assert(page.Slots[slotId].rightId == NIL, "node not cleared");
- Debug.Assert(page.Slots[slotId].parentId == NIL, "node not cleared");
- Debug.Assert(page.Slots[slotId].nextId == NIL, "node not cleared");
- page.Slots[slotId].subTreeSize = 1; // new Nodes have size 1.
- page.Slots[slotId].keyOfNode = key;
- Debug.Assert(page.Slots[slotId].nodeColor == NodeColor.red, "node not cleared");
- return page.Slots[slotId].selfId;
- }
- private int Successor (int x_id)
- {
- if (Right (x_id) != NIL)
- return Minimum (Right (x_id)); //return left most node in right sub-tree.
- int y_id = Parent (x_id);
- while (y_id != NIL && x_id == Right (y_id))
- {
- x_id = y_id;
- y_id = Parent (y_id);
- }
- return y_id;
- }
- private bool Successor(ref int nodeId, ref int mainTreeNodeId)
- {
- if (NIL == nodeId)
- { // find first node, using branchNodeId as the root
- nodeId = Minimum(mainTreeNodeId);
- mainTreeNodeId = NIL;
- }
- else
- { // find next node
- nodeId = Successor(nodeId);
- if ((NIL == nodeId) && (NIL != mainTreeNodeId))
- { // done with satellite branch, move back to main tree
- nodeId = Successor(mainTreeNodeId);
- mainTreeNodeId = NIL;
- }
- }
- if (NIL != nodeId)
- { // test for satellite branch
- if (NIL != Next(nodeId))
- { // find first node of satellite branch
- if (NIL != mainTreeNodeId)
- { // satellite branch has satellite branch - very bad
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.NestedSatelliteTreeEnumerator);
- }
- mainTreeNodeId = nodeId;
- nodeId = Minimum(Next(nodeId));
- }
- // has value
- return true;
- }
- // else no value, done with main tree
- return false;
- }
- private int Minimum (int x_id)
- {
- while (Left (x_id) != NIL) {
- x_id = Left (x_id);
- }
- return x_id;
- }
- /*
- * LeftRotate()
- *
- * It returns the node id for the root of the rotated tree
- */
- private int LeftRotate (int root_id, int x_id, int mainTreeNode)
- {
- int y_id = Right (x_id);
- // Turn y's left subtree into x's right subtree
- SetRight (x_id, Left (y_id));
- if (Left (y_id) != NIL) {
- SetParent (Left (y_id), x_id);
- }
- SetParent (y_id, Parent (x_id));
- if (Parent (x_id) == NIL) {
- if (root_id == NIL) {
- root = y_id;
- }
- else {
- SetNext (mainTreeNode, y_id);
- SetKey (mainTreeNode, Key (y_id));
- root_id = y_id;
- }
- }
- else if (x_id == Left (Parent (x_id))) { // x is left child of its parent
- SetLeft (Parent (x_id), y_id);
- }
- else {
- SetRight (Parent (x_id), y_id);
- }
- SetLeft (y_id, x_id);
- SetParent (x_id, y_id);
- //maintain size: y_id = parent & x_id == child
- if (x_id != NIL) {
- SetSubTreeSize(x_id, (SubTreeSize(Left(x_id)) + SubTreeSize(Right(x_id)) + (Next(x_id) == NIL ? 1 : SubTreeSize(Next(x_id)))));
- }
- if (y_id != NIL) {
- SetSubTreeSize(y_id, (SubTreeSize(Left(y_id)) + SubTreeSize(Right(y_id)) + (Next(y_id) == NIL ? 1 : SubTreeSize(Next(y_id)))));
- }
- return root_id;
- }
- /*
- * RightRotate()
- *
- * It returns the node id for the root of the rotated tree
- */
- private int RightRotate (int root_id, int x_id, int mainTreeNode)
- {
- int y_id = Left (x_id);
- SetLeft (x_id, Right (y_id)); // Turn y's right subtree into x's left subtree
- if (Right (y_id) != NIL) {
- SetParent (Right (y_id), x_id);
- }
- SetParent (y_id, Parent (x_id));
- if (Parent (x_id) == NIL) {
- if (root_id == NIL) {
- root = y_id;
- }
- else {
- SetNext (mainTreeNode, y_id);
- SetKey (mainTreeNode, Key (y_id));
- root_id = y_id;
- }
- }
- else if (x_id == Left (Parent (x_id))) // x is left child of its parent
- SetLeft (Parent (x_id), y_id);
- else
- SetRight (Parent (x_id), y_id);
- SetRight (y_id, x_id);
- SetParent (x_id, y_id);
- //maintain size: y_id == parent && x_id == child.
- if (x_id != NIL) {
- SetSubTreeSize(x_id, (SubTreeSize(Left(x_id)) + SubTreeSize(Right(x_id)) + (Next(x_id) == NIL ? 1 : SubTreeSize(Next(x_id)))));
- }
- if (y_id != NIL) {
- SetSubTreeSize(y_id, (SubTreeSize(Left(y_id)) + SubTreeSize(Right(y_id)) + (Next(y_id) == NIL ? 1 : SubTreeSize(Next(y_id)))));
- }
- return root_id;
- }
- #if VerifySort
- // This helps validate the sorting of the tree to help catch instances of corruption much sooner.
- // corruption happens when the data changes without telling the tree or when multi-threads do simultanous write operations
- private int Compare(int root_id, int x_id, int z_id) {
- Debug.Assert(NIL != x_id, "nil left");
- Debug.Assert(NIL != z_id, "nil right");
- return (root_id == NIL) ? CompareNode (Key (x_id), Key (z_id)) : CompareSateliteTreeNode (Key (x_id), Key (z_id));
- }
- #endif
- /*
- * RBInsert()
- * root_id: root_id of the tree to which a node has to be inserted. it is NIL for inserting to Main tree.
- * x_id : node_id of node to be inserted
- *
- * returns: The root of the tree to which the specified node was added. its NIL if the node was added to Main RBTree.
- *
- * if root_id is NIL -> use CompareNode else use CompareSateliteTreeNode
- *
- * Satelite tree creation:
- * First Duplicate value encountered. Create a *new* tree whose root will have the same key value as the current node.
- * The Duplicate tree nodes have same key when used with CompareRecords but distinct record ids.
- * The current record at all times will have the same *key* as the duplicate tree root.
- */
- private int RBInsert (int root_id, int x_id, int mainTreeNodeID, int position, bool append)
- {
- unchecked{_version++;}
- // Insert Node x at the appropriate position
- int y_id = NIL;
- int z_id = (root_id == NIL) ? root : root_id; //if non NIL, then use the specifid root_id as tree's root.
- if (_accessMethod == TreeAccessMethod.KEY_SEARCH_AND_INDEX && !append)
- {
- Debug.Assert(-1 == position, "KEY_SEARCH_AND_INDEX with bad position");
- while (z_id != NIL) // in-order traverse and find node with a NILL left or right child
- {
- IncreaseSize (z_id);
- y_id = z_id; // y_id set to the proposed parent of x_id
- int c = (root_id == NIL) ? CompareNode (Key (x_id), Key (z_id)) : CompareSateliteTreeNode (Key (x_id), Key (z_id));
- if (c < 0) {
- #if VerifySort
- Debug.Assert((NIL == Left(z_id)) || (0 > Compare(root_id, Left(z_id), z_id)), "Left is not left");
- #endif
- z_id = Left (z_id);
- }
- else if (c > 0) {
- #if VerifySort
- Debug.Assert((NIL == Right(z_id)) || (0 < Compare(root_id, Right(z_id), z_id)), "Right is not right");
- #endif
- z_id = Right (z_id);
- }
- else {
- // Multiple records with same key - insert it to the duplicate record tree associated with current node
- if (root_id != NIL) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.InvalidStateinInsert);
- }
- if (Next(z_id) != NIL) {
- root_id = RBInsert (Next (z_id), x_id, z_id, -1, false); // z_id is existing mainTreeNodeID
- SetKey (z_id, Key (Next (z_id)));
- #if VerifyPath
- (new NodePath(x_id, z_id)).VerifyPath(this); // verify x_id after its been added
- #endif
- }
- else {
- int newMainTreeNodeId = NIL;
- // The existing node is pushed into the Satellite Tree and a new Node
- // is created in the main tree, whose's next points to satellite root.
- newMainTreeNodeId = GetNewNode (Key (z_id));
- _inUseSatelliteTreeCount++;
- // copy contents of z_id to dupRootId (main tree node).
- SetNext(newMainTreeNodeId, z_id);
- SetColor(newMainTreeNodeId, color(z_id));
- SetParent(newMainTreeNodeId, Parent(z_id));
- SetLeft(newMainTreeNodeId, Left(z_id));
- SetRight(newMainTreeNodeId, Right(z_id));
- // Update z_id's non-nil parent
- if( Left(Parent(z_id))==z_id)
- SetLeft(Parent(z_id), newMainTreeNodeId);
- else if (Right(Parent(z_id))==z_id)
- SetRight(Parent(z_id), newMainTreeNodeId);
- // update children.
- if (Left(z_id) != NIL)
- SetParent(Left(z_id), newMainTreeNodeId);
- if (Right(z_id) != NIL)
- SetParent(Right(z_id), newMainTreeNodeId);
- if (root == z_id)
- root = newMainTreeNodeId;
- // Reset z_id's pointers to NIL. It will start as the satellite tree's root.
- SetColor(z_id, NodeColor.black);
- SetParent(z_id, NIL);
- SetLeft(z_id, NIL);
- SetRight(z_id, NIL);
- int savedSize = SubTreeSize(z_id);
- SetSubTreeSize(z_id, 1);
- // With z_id as satellite root, insert x_id
- root_id = RBInsert (z_id, x_id, newMainTreeNodeId, -1, false);
- SetSubTreeSize(newMainTreeNodeId, savedSize);
- #if VerifyPath
- (new NodePath(x_id, newMainTreeNodeId)).VerifyPath(this); // verify x_id after its been added
- #endif
- }
- return root_id;
- }
- }
- }
- else if (_accessMethod == TreeAccessMethod.INDEX_ONLY || append)
- {
- if (position == -1) {
- position = SubTreeSize(root); // append
- }
- while (z_id != NIL) // in-order traverse and find node with a NILL left or right child
- {
- IncreaseSize (z_id);
- y_id = z_id; // y_id set to the proposed parent of x_id
- //int c = (SubTreeSize(y_id)-(position)); // Actually it should be: SubTreeSize(y_id)+1 - (position + 1)
- int c = (position) - (SubTreeSize(Left(y_id)));
- if (c <= 0) {
- z_id = Left (z_id);
- }
- else {
- //position = position - SubTreeSize(z_id);
- z_id = Right (z_id);
- if (z_id != NIL) {
- position = c-1; //skip computation of position for leaf node
- }
- }
- }
- }
- else {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.UnsupportedAccessMethod1);
- }
- SetParent (x_id, y_id);
- if (y_id == NIL)
- {
- if (root_id == NIL) {
- root = x_id;
- }
- else
- {
- // technically we should never come here. Satellite tree always has a root and atleast 1 child.
- // if it has only root as it's node, then the satellite tree gets collapsed into the main tree.
- #if VerifyPath
- (new NodePath(x_id, mainTreeNodeID)).VerifyPath(this); // verify x_id after its been added
- #endif
- SetNext(mainTreeNodeID, x_id);
- SetKey(mainTreeNodeID, Key(x_id));
- root_id = x_id;
- }
- }
- else
- {
- int c=0;
- if (_accessMethod == TreeAccessMethod.KEY_SEARCH_AND_INDEX)
- c = (root_id == NIL) ? CompareNode (Key(x_id), Key(y_id)) : CompareSateliteTreeNode (Key (x_id), Key (y_id));
- else if (_accessMethod == TreeAccessMethod.INDEX_ONLY)
- c = (position <= 0) ? -1 : 1;
- else {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.UnsupportedAccessMethod2);
- }
- if (c < 0)
- SetLeft (y_id, x_id);
- else
- SetRight (y_id, x_id);
- }
- SetLeft (x_id, NIL);
- SetRight (x_id, NIL);
- SetColor (x_id, NodeColor.red);
- z_id = x_id; // for verification later
- // fix the tree
- while (color (Parent (x_id)) == NodeColor.red)
- {
- if (Parent (x_id) == Left (Parent (Parent (x_id)))) // if x.parent is a left child
- {
- y_id = Right (Parent (Parent (x_id))); // x.parent.parent.right;
- if (color (y_id) == NodeColor.red) // my right uncle is red
- {
- SetColor (Parent (x_id), NodeColor.black); // x.parent.color = Color.black;
- SetColor (y_id, NodeColor.black);
- SetColor (Parent (Parent (x_id)), NodeColor.red); // x.parent.parent.color = Color.red;
- x_id = Parent (Parent (x_id)); // x = x.parent.parent;
- }
- else
- { // my right uncle is black
- if (x_id == Right (Parent (x_id)))
- {
- x_id = Parent (x_id);
- root_id = LeftRotate (root_id, x_id, mainTreeNodeID);
- }
- SetColor (Parent (x_id), NodeColor.black); // x.parent.color = Color.black;
- SetColor (Parent (Parent (x_id)), NodeColor.red); // x.parent.parent.color = Color.red;
- root_id = RightRotate (root_id, Parent (Parent (x_id)), mainTreeNodeID); // RightRotate (x.parent.parent);
- }
- }
- else
- { // x.parent is a right child
- y_id = Left (Parent (Parent (x_id))); // y = x.parent.parent.left;
- if (color (y_id) == NodeColor.red) // if (y.color == Color.red) // my right uncle is red
- {
- SetColor (Parent (x_id), NodeColor.black);
- SetColor (y_id, NodeColor.black);
- SetColor (Parent (Parent (x_id)), NodeColor.red); // x.parent.parent.color = Color.red;
- x_id = Parent (Parent (x_id));
- }
- else
- {// my right uncle is black
- if (x_id == Left (Parent (x_id)))
- {
- x_id = Parent (x_id);
- root_id = RightRotate (root_id, x_id, mainTreeNodeID);
- }
- SetColor (Parent (x_id), NodeColor.black); // x.parent.color = Color.black;
- SetColor (Parent (Parent (x_id)), NodeColor.red); // x.parent.parent.color = Color.red;
- root_id = LeftRotate (root_id, Parent (Parent (x_id)), mainTreeNodeID);
- }
- }
- }
- if (root_id == NIL)
- SetColor (root, NodeColor.black);
- else
- SetColor (root_id, NodeColor.black);
- #if VerifyPath
- (new NodePath(z_id, mainTreeNodeID)).VerifyPath(this); // verify x_id after its been added
- #endif
- return root_id;
- } //Insert
- public void UpdateNodeKey(K currentKey, K newKey)
- {
- // swap oldRecord with NewRecord in nodeId associated with oldRecord
- // if the matched node is a satellite root then also change the key in the associated main tree node.
- NodePath x_id = GetNodeByKey (currentKey);
- if (Parent(x_id.NodeID) == NIL && x_id.NodeID != root) //determine if x_id is a satellite root.
- {
- #if VerifyPath
- x_id.VerifyPath(this);
- #endif
- SetKey(x_id.MainTreeNodeID, newKey);
- }
- SetKey (x_id.NodeID, newKey);
- }
- public K DeleteByIndex(int i)
- {
- // This check was not correct, it should have been ((uint)this.Count <= (uint)i)
- // Even then, the index will be checked by GetNodebyIndex which will throw either
- // using RowOutOfRange or InternalRBTreeError depending on _accessMethod
- //
- //if (i >= (_inUseNodeCount - 1)) {
- // throw ExceptionBuilder.InternalRBTreeError(RBTreeError.IndexOutOfRange);
- //}
- K key;
- NodePath x_id = GetNodeByIndex(i); // it'l throw if corresponding node does not exist
- key = Key(x_id.NodeID);
- RBDeleteX(NIL, x_id.NodeID, x_id.MainTreeNodeID);
- return key;
- }
- public int RBDelete (int z_id)
- {
- // always perform delete operation on the main tree
- Debug.Assert(_accessMethod == TreeAccessMethod.INDEX_ONLY, "not expecting anything else");
- return RBDeleteX (NIL, z_id, NIL);
- }
- /*
- * RBDelete()
- * root_id: root_id of the tree. it is NIL for Main tree.
- * z_id : node_id of node to be deleted
- *
- * returns: The id of the spliced node
- *
- * Case 1: Node is in main tree only (decrease size in main tree)
- * Case 2: Node's key is shared with a main tree node whose next is non-NIL
- * (decrease size in both trees)
- * Case 3: special case of case 2: After deletion, node leaves satelite tree with only 1 node (only root),
- * it should collapse the satelite tree - go to case 4. (decrease size in both trees)
- * Case 4: (1) Node is in Main tree and is a satelite tree root AND
- * (2) It is the only node in Satelite tree
- * (Do not decrease size in any tree, as its a collpase operation)
- *
- */
- private int RBDeleteX(int root_id, int z_id, int mainTreeNodeID)
- {
- int x_id = NIL; // used for holding spliced node (y_id's) child
- int y_id; // the spliced node
- int py_id; // for holding spliced node (y_id's) parent
- #if VerifyPath
- // by knowing the NodePath, when z_id is in a satellite branch we don't have to Search for mainTreeNodeID
- (new NodePath(z_id, mainTreeNodeID)).VerifyPath(this);
- #endif
- if (Next (z_id) != NIL)
- return RBDeleteX(Next(z_id), Next(z_id), z_id); // delete root of satelite tree.
- // if we we reach here, we are guaranteed z_id.next is NIL.
- bool isCase3 = false;
- int mNode = ((_accessMethod == TreeAccessMethod.KEY_SEARCH_AND_INDEX) ? mainTreeNodeID : z_id);
- if (Next (mNode) != NIL)
- root_id = Next (mNode);
- if (SubTreeSize (Next (mNode)) == 2) // Next(mNode) == root_id
- isCase3 = true;
- else if (SubTreeSize (Next (mNode)) == 1) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.InvalidNextSizeInDelete);
- }
- if (Left (z_id) == NIL || Right (z_id) == NIL)
- y_id = z_id;
- else
- y_id = Successor (z_id);
- if (Left (y_id) != NIL)
- x_id = Left (y_id);
- else
- x_id = Right (y_id);
- py_id = Parent(y_id);
- if (x_id != NIL)
- SetParent (x_id, py_id);
- if (py_id == NIL) // if the spliced node is the root.
- {
- // check for main tree or Satellite tree root
- if (root_id == NIL)
- root = x_id;
- else
- {
- // spliced node is root of satellite tree
- root_id = x_id;
- }
- }
- else if (y_id == Left (py_id)) // update y's parent to point to X as its child
- SetLeft (py_id, x_id);
- else
- SetRight (py_id, x_id);
- if (y_id != z_id)
- {
- // assign all values from y (spliced node) to z (node containing key to be deleted)
- // -----------
- SetKey (z_id, Key (y_id)); // assign all values from y to z
- SetNext (z_id, Next (y_id)); //z.value = y.value;
- }
- if (Next(mNode) != NIL)
- {
- // update mNode to point to satellite tree root and have the same key value.
- // mNode will have to be patched again after RBDeleteFixup as root_id can again change
- if (root_id == NIL && z_id != mNode) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.InvalidStateinDelete);
- }
- // -- it's possible for Next(mNode) to be != NIL and root_id == NIL when, the spliced node is a mNode of some
- // -- satellite tree and its "next" gets assigned to mNode
- if (root_id != NIL)
- {
- SetNext (mNode, root_id);
- SetKey (mNode, Key (root_id));
- }
- }
- // traverse from y_id's parent to root and decrement size by 1
- int tmp_py_id = py_id;
- // case: 1, 2, 3
- while (tmp_py_id != NIL)
- {
- //DecreaseSize (py_id, (Next(y_id)==NIL)?1:Size(Next(y_id)));
- RecomputeSize (tmp_py_id);
- tmp_py_id = Parent (tmp_py_id);
- }
- //if satelite tree node deleted, decrease size in main tree as well.
- if (root_id != NIL)
- {
- // case 2, 3
- int nodeId = mNode;
- while (nodeId != NIL)
- {
- DecreaseSize (nodeId);
- nodeId = Parent (nodeId);
- }
- }
- if (color (y_id) == NodeColor.black)
- root_id = RBDeleteFixup (root_id, x_id, py_id, mainTreeNodeID); // passing x.parent as y.parent, to handle x=Node.NIL case.
- if (isCase3)
- {
- // Collpase satelite tree, by swapping it with the main tree counterpart and freeing the main tree node
- if (mNode == NIL || SubTreeSize(Next(mNode)) != 1) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.InvalidNodeSizeinDelete);
- }
- _inUseSatelliteTreeCount--;
- int satelliteRootId = Next(mNode);
- SetLeft(satelliteRootId, Left(mNode));
- SetRight(satelliteRootId, Right(mNode));
- SetSubTreeSize(satelliteRootId, SubTreeSize(mNode));
- SetColor(satelliteRootId, color(mNode)); // Next of satelliteRootId is already NIL
- if (Parent(mNode) != NIL)
- {
- SetParent(satelliteRootId, Parent(mNode));
- if (Left(Parent(mNode)) == mNode) {
- SetLeft(Parent(mNode), satelliteRootId);
- }
- else {
- SetRight(Parent(mNode), satelliteRootId);
- }
- }
- // update mNode's children.
- if (Left(mNode) != NIL) {
- SetParent(Left(mNode), satelliteRootId);
- }
- if (Right(mNode) != NIL) {
- SetParent(Right(mNode), satelliteRootId);
- }
- if (root == mNode) {
- root = satelliteRootId;
- }
- FreeNode (mNode);
- mNode = NIL;
- }
- else if (Next(mNode) != NIL)
- {
- // update mNode to point to satellite tree root and have the same key value
- if (root_id == NIL && z_id != mNode) { //if mNode being deleted, its OK for root_id (it should be) NIL.
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.InvalidStateinEndDelete);
- }
- if (root_id != NIL)
- {
- SetNext (mNode, root_id);
- SetKey (mNode, Key (root_id));
- }
- }
- // In order to pin a key to it's node, free deleted z_id instead of the spliced y_id
- if (y_id != z_id)
- {
- // we know that key, next and value are same for z_id and y_id
- SetLeft (y_id, Left (z_id));
- SetRight (y_id, Right (z_id));
- SetColor (y_id, color (z_id));
- SetSubTreeSize (y_id, SubTreeSize(z_id));
- if (Parent(z_id) != NIL)
- {
- SetParent(y_id, Parent(z_id));
- if (Left(Parent(z_id)) == z_id) {
- SetLeft(Parent(z_id), y_id);
- }
- else {
- SetRight(Parent(z_id), y_id);
- }
- }
- else {
- SetParent(y_id, NIL);
- }
- // update children.
- if (Left(z_id) != NIL) {
- SetParent(Left(z_id), y_id);
- }
- if (Right(z_id) != NIL) {
- SetParent(Right(z_id), y_id);
- }
- if (root == z_id) {
- root = y_id;
- }
- else if (root_id == z_id) {
- root_id = y_id;
- }
- // update a next reference to z_id (if any)
- if (mNode != NIL && Next(mNode) == z_id) {
- SetNext(mNode, y_id);
- }
- }
- FreeNode (z_id);
- unchecked{_version++;}
- return z_id;
- }
- /*
- * RBDeleteFixup()
- * Fix the specified tree for RedBlack properties
- *
- * returns: The id of the root
- */
- private int RBDeleteFixup (int root_id, int x_id, int px_id /* px is parent of x */, int mainTreeNodeID)
- { //x is successor's non nil child or nil if both children are nil
- int w_id;
- #if VerifyPath
- // by knowing the NodePath, when z_id is in a satellite branch we don't have to Search for mainTreeNodeID
- (new NodePath(root_id, mainTreeNodeID)).VerifyPath(this);
- #endif
- if (x_id == NIL && px_id == NIL) {
- return NIL; //case of satelite tree root being deleted.
- }
- while (((root_id == NIL ? root : root_id) != x_id) && color (x_id) == NodeColor.black)
- {
- // (1) x's parent should have aleast 1 non-NIL child.
- // (2) check if x is a NIL left child or a non NIL left child
- if ((x_id != NIL && x_id == Left (Parent (x_id))) || (x_id == NIL && Left (px_id) == NIL))
- {
- // we have from DELETE, then x cannot be NIL and be a right child of its parent
- // also from DELETE, if x is non nil, it will be a left child.
- w_id = (x_id == NIL) ? Right (px_id) : Right (Parent (x_id)); // w is x's right sibling and it cannot be NIL
- if (w_id == NIL) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.RBDeleteFixup);
- }
- if (color (w_id) == NodeColor.red)
- {
- SetColor (w_id, NodeColor.black);
- SetColor (px_id, NodeColor.red);
- root_id = LeftRotate (root_id, px_id, mainTreeNodeID);
- w_id = (x_id == NIL) ? Right (px_id) : Right (Parent (x_id));
- }
- if (color (Left (w_id)) == NodeColor.black && color (Right (w_id)) == NodeColor.black)
- {
- SetColor (w_id, NodeColor.red);
- x_id = px_id;
- px_id = Parent (px_id); //maintain px_id
- }
- else
- {
- if (color (Right (w_id)) == NodeColor.black)
- {
- SetColor (Left (w_id), NodeColor.black);
- SetColor (w_id, NodeColor.red);
- root_id = RightRotate (root_id, w_id, mainTreeNodeID);
- w_id = (x_id == NIL) ? Right (px_id) : Right (Parent (x_id));
- }
- SetColor (w_id, color (px_id));
- SetColor (px_id, NodeColor.black);
- SetColor (Right (w_id), NodeColor.black);
- root_id = LeftRotate (root_id, px_id, mainTreeNodeID);
- x_id = (root_id == NIL) ? root : root_id;
- px_id = Parent (x_id);
- }
- }
- else
- { //x is a right child or it is NIL
- w_id = Left (px_id);
- if (color (w_id) == NodeColor.red)
- { // x_id is y's (the spliced node) sole non-NIL child or NIL if y had no children
- SetColor (w_id, NodeColor.black);
- if (x_id != NIL) {
- SetColor (px_id, NodeColor.red);
- root_id = RightRotate (root_id, px_id, mainTreeNodeID);
- w_id = (x_id == NIL) ? Left (px_id) : Left (Parent (x_id));
- }
- else {
- //we have from DELETE, then x cannot be NIL and be a right child of its parent
- // w_id cannot be nil.
- SetColor (px_id, NodeColor.red);
- root_id = RightRotate (root_id, px_id, mainTreeNodeID);
- w_id = (x_id == NIL) ? Left (px_id) : Left (Parent (x_id));
- if (w_id == NIL) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.CannotRotateInvalidsuccessorNodeinDelete);
- }
- }
- }
- if (color (Right (w_id)) == NodeColor.black && color (Left (w_id)) == NodeColor.black) {
- SetColor (w_id, NodeColor.red);
- x_id = px_id;
- px_id = Parent (px_id);
- }
- else {
- if (color (Left (w_id)) == NodeColor.black)
- {
- SetColor (Right (w_id), NodeColor.black);
- SetColor (w_id, NodeColor.red);
- root_id = LeftRotate (root_id, w_id, mainTreeNodeID);
- w_id = (x_id == NIL) ? Left (px_id) : Left (Parent (x_id));
- }
- if (x_id != NIL)
- {
- SetColor (w_id, color (px_id));
- SetColor (px_id, NodeColor.black);
- SetColor (Left (w_id), NodeColor.black);
- root_id = RightRotate (root_id, px_id, mainTreeNodeID);
- x_id = (root_id == NIL) ? root : root_id;
- px_id = Parent (x_id);
- }
- else
- {
- SetColor (w_id, color (px_id));
- SetColor (px_id, NodeColor.black);
- SetColor (Left (w_id), NodeColor.black);
- root_id = RightRotate (root_id, px_id, mainTreeNodeID);
- x_id = (root_id == NIL) ? root : root_id;
- px_id = Parent (x_id);
- }
- }
- }
- }
- SetColor (x_id, NodeColor.black);
- return root_id;
- }
- private int SearchSubTree (int root_id, K key)
- {
- if (root_id != NIL && _accessMethod!=TreeAccessMethod.KEY_SEARCH_AND_INDEX) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.UnsupportedAccessMethodInNonNillRootSubtree);
- }
- int x_id = (root_id == NIL) ? root : root_id;
- int c;
- while (x_id != NIL)
- {
- c = (root_id == NIL) ? CompareNode (key, Key (x_id)) : CompareSateliteTreeNode (key, Key (x_id));
- if (c == 0) {
- break;
- }
- if (c < 0) {
- #if VerifySort
- Debug.Assert((NIL == Left(x_id)) || (0 > Compare(root_id, Left(x_id), x_id)), "Search duplicate Left is not left");
- #endif
- x_id = Left (x_id);
- }
- else {
- #if VerifySort
- Debug.Assert((NIL == Right(x_id)) || (0 < Compare(root_id, Right(x_id), x_id)), "Search duplicate Right is not right");
- #endif
- x_id = Right (x_id);
- }
- }
- return x_id;
- }
- // only works on the main tree - does not work with satelite tree
- public int Search (K key)
- { // for performance reasons, written as a while loop instead of a recursive method
- int x_id = root;
- int c;
- while (x_id != NIL)
- {
- c = CompareNode (key, Key (x_id));
- if (c == 0) {
- break;
- }
- if (c < 0) {
- #if VerifySort
- Debug.Assert((NIL == Left(x_id)) || (0 > Compare(NIL, Left(x_id), x_id)), "Search Left is not left");
- #endif
- x_id = Left (x_id);
- }
- else {
- #if VerifySort
- Debug.Assert((NIL == Right(x_id)) || (0 < Compare(NIL, Right(x_id), x_id)), "Search Right is not right");
- #endif
- x_id = Right (x_id);
- }
- }
- return x_id;
- }
- // To simulate direct access for records[index]= record
- /// <summary>
- /// return key associated with the specified value. Specifically, return record for specified index/value
- /// indexer
- /// </summary>
- /// <exception cref="IndexOutOfRangeException"></exception>
- // return record i.e key at specified index
- public K this[int index]
- {
- get
- {
- return Key(GetNodeByIndex(index).NodeID);
- }
- }
- // Get Record(s) having same key value as that of specified record. Then scan the matched nodes
- // and return the node with the matching record
- /// <returns>Determine node and the branch it took to get there.</returns>
- private NodePath GetNodeByKey(K key) //i.e. GetNodeByKey
- {
- int nodeId = SearchSubTree(NIL, key);
- if (Next (nodeId) != NIL) {
- return new NodePath(SearchSubTree(Next(nodeId), key), nodeId);
- }
- else if (!Key(nodeId).Equals(key)) {
- nodeId = NIL;
- }
- return new NodePath(nodeId, NIL);
- }
- /*
- * GetIndexByRecord()
- * Gets index of the specified record. returns (-1) if specified record is not found.
- */
- public int GetIndexByKey (K key)
- {
- int nodeIndex = -1;
- NodePath nodeId = GetNodeByKey (key);
- if (nodeId.NodeID != NIL) {
- nodeIndex = GetIndexByNodePath (nodeId);
- }
- return nodeIndex;
- }
- /*
- * GetIndexByNode()
- *
- * If I am right child then size=my size + size of left child of my parent + 1
- * go up till root, if right child keep adding to the size.
- * (1) compute rank in main tree.
- * (2) if node member of a satelite tree, add to rank its relative rank in that tree.
- *
- * Rank:
- * Case 1: Node is in Main RBTree only
- * Its rank/index is its main tree index
- * Case 2: Node is in a Satelite tree only
- * Its rank/index is its satelite tree index
- * Case 3: Nodes is in both Main and Satelite RBTree (a main tree node can be a satelite tree root)
- * Its rank/index is its main tree index + its satelite tree index - 1
- * Returns the index of the specified node.
- * returns -1, if the specified Node is tree.NIL.
- *
- * Assumption: The specified node always exist in the tree.
- */
- // SQLBU 428961: Serious performance issue when creating DataView
- // this improves performance when used heavily, like with the default view (creating before rows added)
- public int GetIndexByNode (int node)
- {
- Debug.Assert(NIL != node, "GetIndexByNode(NIL)");
- if (0 == _inUseSatelliteTreeCount)
- { // compute from the main tree when no satellite branches exist
- return ComputeIndexByNode(node);
- }
- else if (NIL != Next(node))
- { // node is a main tree node
- #if VerifyIndex && VerifyPath
- (new NodePath(Next(node), node)).VerifyPath(this);
- #endif
- return ComputeIndexWithSatelliteByNode(node);
- }
- else
- {
- int mainTreeNodeId = SearchSubTree(NIL, Key(node));
- if (mainTreeNodeId == node)
- { // node is a main tree node
- #if VerifyIndex && VerifyPath
- (new NodePath(node, NIL)).VerifyPath(this);
- #endif
- return ComputeIndexWithSatelliteByNode(node);
- }
- else
- { //compute the main tree rank + satellite branch rank
- #if VerifyIndex && VerifyPath
- (new NodePath(node, mainTreeNodeId)).VerifyPath(this);
- #endif
- return ComputeIndexWithSatelliteByNode(mainTreeNodeId) +
- ComputeIndexByNode(node);
- }
- }
- }
- /// <summary>Determine tree index position from node path.</summary>
- /// <remarks>This differs from GetIndexByNode which would search for the main tree node instead of just knowing it</remarks>
- private int GetIndexByNodePath(NodePath path)
- {
- #if VerifyIndex && VerifyPath
- path.VerifyPath(this);
- #endif
- if (0 == _inUseSatelliteTreeCount)
- { // compute from the main tree when no satellite branches exist
- return ComputeIndexByNode(path.NodeID);
- }
- else if (NIL == path.MainTreeNodeID)
- { // compute from the main tree accounting for satellite branches
- return ComputeIndexWithSatelliteByNode(path.NodeID);
- }
- else
- { //compute the main tree rank + satellite branch rank
- return ComputeIndexWithSatelliteByNode(path.MainTreeNodeID) +
- ComputeIndexByNode(path.NodeID);
- }
- }
- private int ComputeIndexByNode(int nodeId) {
- #if VerifyIndex
- Debug.Assert(NIL != nodeId, "ComputeIndexByNode(NIL)");
- #endif
- int myRank = SubTreeSize(Left(nodeId));
- while (nodeId != NIL)
- {
- #if VerifyIndex && VerifyPath
- Debug.Assert(NIL == Next(nodeId), "Next not NIL");
- #endif
- int parent = Parent(nodeId);
- if (nodeId == Right(parent))
- {
- myRank += (SubTreeSize(Left(parent)) + 1);
- }
- nodeId = parent;
- }
- return myRank;
- }
- private int ComputeIndexWithSatelliteByNode(int nodeId) {
- #if VerifyIndex
- Debug.Assert(NIL != nodeId, "ComputeIndexWithSatelliteByNode(NIL)");
- #endif
- int myRank = SubTreeSize(Left(nodeId));
- while (nodeId != NIL)
- {
- int parent = Parent(nodeId);
- if (nodeId == Right(parent))
- {
- myRank += (SubTreeSize(Left(parent)) + ((Next(parent) == NIL) ? 1 : SubTreeSize(Next(parent))));
- }
- nodeId = parent;
- }
- return myRank;
- }
- /// <returns>Determine node and the branch it took to get there.</returns>
- /// <exception cref="IndexOutOfRangeException"></exception>
- private NodePath GetNodeByIndex(int userIndex)
- {
- int x_id, satelliteRootId;
- if (0 == _inUseSatelliteTreeCount) {
- // if rows were only contigously append, then using (userIndex -= _pageTable[i].InUseCount) would
- // be faster for the first 12 pages (about 5248) nodes before (log2 of Count) becomes faster again.
- // the additional complexity was deemed not worthy for the possible perf gain
- // computation cost is (log2 of Count)
- x_id = ComputeNodeByIndex(root, unchecked(userIndex + 1));
- satelliteRootId = NIL;
- }
- else {
- // computation cost is ((log2 of Distinct Count) + (log2 of Duplicate Count))
- x_id = ComputeNodeByIndex(userIndex, out satelliteRootId);
- }
- if (x_id == NIL) {
- if (TreeAccessMethod.INDEX_ONLY == _accessMethod) {
- throw ExceptionBuilder.RowOutOfRange(userIndex);
- }
- else {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.IndexOutOFRangeinGetNodeByIndex);
- }
- }
- return new NodePath(x_id, satelliteRootId);
- }
- private int ComputeNodeByIndex(int index, out int satelliteRootId)
- {
- index = unchecked(index + 1); // index is 0 based, while size is 1 based.
- satelliteRootId = NIL;
- int x_id = root;
- int rank = -1;
- while (x_id != NIL && !(((rank = SubTreeSize (Left (x_id)) + 1) == index) && Next (x_id) == NIL))
- {
- if (index < rank) {
- x_id = Left (x_id);
- }
- else if (Next (x_id) != NIL && index >= rank && index <= rank + SubTreeSize (Next (x_id)) - 1)
- {
- // node with matching index is in the associated satellite tree. continue searching for index in satellite tree.
- satelliteRootId = x_id;
- index = index - rank + 1; // rank is SubTreeSize(Node.left)+1, we do +1 here to offset +1 done in rank. index -= rank;
- return ComputeNodeByIndex(Next(x_id), index); //satellite tree root
- }
- else
- {
- if (Next (x_id) == NIL)
- index -= rank;
- else
- index -= rank + SubTreeSize (Next (x_id)) - 1;
- x_id = Right (x_id);
- }
- }
- return x_id;
- }
- private int ComputeNodeByIndex(int x_id, int index) {
- while (x_id != NIL) {
- Debug.Assert(NIL == Next(x_id), "has unexpected satellite tree");
- int y_id = Left(x_id);
- int rank = SubTreeSize(y_id) + 1;
- if (index < rank) {
- x_id = y_id;
- }
- else if (rank < index) {
- x_id = Right(x_id);
- index -= rank;
- }
- else {
- break;
- }
- }
- return x_id;
- }
- #if DEBUG
- // return true if all nodes are unique; i.e. no satelite trees.
- public bool CheckUnique (int curNodeId)
- {
- if (curNodeId != NIL)
- {
- if (Next (curNodeId) != NIL)
- return false; // atleast 1 duplicate found
- if (!CheckUnique (Left (curNodeId)) || !CheckUnique (Right (curNodeId)))
- return false;
- }
- return true;
- }
- #endif
- public int Insert (K item)
- {
- int nodeId = GetNewNode(item);
- RBInsert (NIL, nodeId, NIL, -1, false);
- return nodeId;
- }
- // Begin: List of methods for making it easy to work with ArrayList
- public int Add(K item) //Insert (int record)
- {
- int nodeId = GetNewNode (item);
- RBInsert(NIL, nodeId, NIL, -1, false);
- return nodeId;
- }
- public IEnumerator GetEnumerator() {
- return new RBTreeEnumerator(this);
- }
- // *****BruteForceImplementation*****
- //
- // iterate over all nodes, InOrder and return index of node with the specified Item
- // For the short term use a recursive method, later re-write it based on a stack data structure (if needed)
- public int IndexOf (int nodeId, K item)
- {
- int index = -1;
- // BIG ASSUMPTION: There is not satellite tree, this is INDEX_ONLY.
- if (nodeId != NIL)
- {
- if ( (Object) Key(nodeId) == (Object)item) {
- return GetIndexByNode(nodeId);
- }
- if ( (index=IndexOf(Left(nodeId), item)) != -1) {
- return index;
- }
- if ( (index=IndexOf(Right(nodeId), item)) != -1) {
- return index;
- }
- }
- return index;
- }
- public int Insert(int position, K item) //Insert (int record)
- {
- return InsertAt(position, item, false);
- }
- public int InsertAt(int position, K item, bool append)
- {
- int nodeId = GetNewNode (item);
- RBInsert (NIL, nodeId, NIL, position, append);
- return nodeId;
- }
- public void RemoveAt(int position)
- {
- DeleteByIndex(position);
- }
- public void Clear()
- {
- InitTree();
- unchecked{_version++;}
- }
- public void CopyTo(Array array, int index) {
- if (array==null) {
- throw ExceptionBuilder.ArgumentNull("array");
- }
- if (index < 0) {
- throw ExceptionBuilder.ArgumentOutOfRange("index");
- }
- int count = Count;
- if (array.Length - index < Count) {
- throw ExceptionBuilder.InvalidOffsetLength();
- }
- int x_id = Minimum(root);
- for(int i = 0; i < count; ++i) {
- array.SetValue(Key(x_id), index + i);
- x_id = Successor(x_id);
- }
- }
- public void CopyTo(K[] array, int index) {
- if (array==null) {
- throw ExceptionBuilder.ArgumentNull("array");
- }
- if (index < 0) {
- throw ExceptionBuilder.ArgumentOutOfRange("index");
- }
- int count = Count;
- if (array.Length - index < Count) {
- throw ExceptionBuilder.InvalidOffsetLength();
- }
- int x_id = Minimum(root);
- for(int i = 0; i < count; ++i) {
- array[index + i] = Key(x_id);
- x_id = Successor(x_id);
- }
- }
- // End: List of methods for making it easy to work with ArrayList
- private void SetRight (int nodeId, int rightNodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].rightId = rightNodeId;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].rightId = rightNodeId;
- }
- private void SetLeft (int nodeId, int leftNodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].leftId = leftNodeId;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].leftId = leftNodeId;
- }
- private void SetParent (int nodeId, int parentNodeId)
- {
- Debug.Assert(nodeId != NIL, " in SetParent nodeId == NIL");
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].parentId = parentNodeId;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].parentId = parentNodeId;
- }
- private void SetColor (int nodeId, NodeColor color)
- {
- Debug.Assert(nodeId != NIL, " in SetColor nodeId == NIL");
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].nodeColor = color;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].nodeColor = color;
- }
- private void SetKey (int nodeId, K key)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].keyOfNode = key;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].keyOfNode = key;
- }
- private void SetNext (int nodeId, int nextNodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].nextId = nextNodeId;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].nextId = nextNodeId;
- }
- private void SetSubTreeSize (int nodeId, int size)
- {
- Debug.Assert(nodeId != NIL &&
- (size != 0 || _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].selfId == NIL) &&
- (size != 1 || _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].nextId == NIL), "SetSize");
- // SQLBU 428961: Serious performance issue when creating DataView
- // this improves performance by reducing the impact of this heavily used method
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].subTreeSize = size;
- VerifySize(nodeId, size);
- }
- private void IncreaseSize (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].subTreeSize += 1;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].subTreeSize += 1;
- }
- private void RecomputeSize(int nodeId)
- {
- int myCorrectSize = SubTreeSize (Left (nodeId)) + SubTreeSize (Right (nodeId)) + (Next (nodeId) == NIL ? 1 : SubTreeSize (Next (nodeId)));
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].subTreeSize = myCorrectSize;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].subTreeSize = myCorrectSize;
- }
- private void DecreaseSize (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- page.Slots[slotIndex].subTreeSize -= 1;
- */
- _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].subTreeSize -= 1;
- VerifySize(nodeId, _pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].subTreeSize);
- }
- [ConditionalAttribute("DEBUG")]
- private void VerifySize(int nodeId, int size) {
- int myCorrectSize = SubTreeSize(Left(nodeId)) + SubTreeSize(Right(nodeId)) + (Next(nodeId) == NIL ? 1 : SubTreeSize(Next(nodeId)));
- Debug.Assert(myCorrectSize == size, "VerifySize");
- }
- public int Right (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- int rightId = page.Slots[slotIndex].rightId;
- return rightId;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].rightId);
- }
- public int Left (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- int leftId = page.Slots[slotIndex].leftId;
- return leftId;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].leftId);
- }
- public int Parent (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- int parentId = page.Slots[slotIndex].parentId;
- return parentId;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].parentId);
- }
- private NodeColor color (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- NodeColor col = page.Slots[slotIndex].nodeColor;
- return col;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].nodeColor);
- }
- public int Next (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- int nextId = page.Slots[slotIndex].nextId;
- return nextId;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].nextId);
- }
- public int SubTreeSize (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- int size = page.Slots[slotIndex].subTreeSize;
- return size;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].subTreeSize);
- }
- public K Key (int nodeId)
- {
- /*
- TreePage page = _pageTable[nodeId >> 16];
- int slotIndex = nodeId & 0xFFFF;
- K key = page.Slots[slotIndex].keyOfNode;
- return key;
- */
- return (_pageTable[nodeId >> 16].Slots[nodeId & 0xFFFF].keyOfNode);
- }
- private enum NodeColor {
- red = 0,
- black = 1,
- };
- private struct Node
- {
- internal int selfId;
- internal int leftId;
- internal int rightId;
- internal int parentId;
- internal int nextId; // multiple records associated with same key
- internal int subTreeSize; // number of nodes in subtree rooted at the current node
- internal K keyOfNode;
- internal NodeColor nodeColor;
- }
- /// <summary>Represents the node in the tree and the satellite branch it took to get there.</summary>
- private struct NodePath
- {
- /// <summary>Represents the node in the tree</summary>
- internal readonly int NodeID;
- /// <summary>
- /// When not NIL, it represents the fact NodeID is has duplicate values in the tree.
- /// This is the 'fake' node in the main tree that redirects to the root of the satellite tree.
- /// By tracking this value, we don't have to repeatedly search for this node.
- /// </summary>
- internal readonly int MainTreeNodeID;
- internal NodePath(int nodeID, int mainTreeNodeID)
- {
- NodeID = nodeID;
- MainTreeNodeID = mainTreeNodeID;
- }
- #if VerifyPath
- internal void VerifyPath(RBTree<K> tree)
- {
- Debug.Assert(null != tree, "null tree");
- Debug.Assert((NIL == NodeID && NIL == MainTreeNodeID) || (NIL != NodeID), "MainTreeNodeID is not NIL");
- if (NIL != MainTreeNodeID)
- {
- Debug.Assert(NIL != tree.Next(MainTreeNodeID), "MainTreeNodeID should have a Next");
- int node = MainTreeNodeID;
- while (NIL != tree.Parent(node))
- {
- node = tree.Parent(node);
- }
- Debug.Assert(tree.root == node, "MainTreeNodeID parent change doesn't align");
- }
- if (NIL != NodeID)
- {
- Debug.Assert(NIL == tree.Next(NodeID), "NodeID should not have a Next");
- int node = NodeID;
- if (NIL == MainTreeNodeID) {
- while (NIL != tree.Parent(node))
- {
- node = tree.Parent(node);
- }
- }
- else {
- while (NIL != tree.Parent(node))
- {
- Debug.Assert(NIL == tree.Next(node), "duplicate node should not have a next");
- node = tree.Parent(node);
- }
- }
- Debug.Assert((NIL == MainTreeNodeID && tree.root == node) ||
- (tree.Next(MainTreeNodeID) == node), "NodeID parent change doesn't align");
- }
- }
- #endif
- }
- private sealed class TreePage {
- public const Int32 slotLineSize = 32;
- internal readonly Node[] Slots; // List of slots
- internal readonly Int32[] SlotMap; // CEILING(slots.size/slotLineSize)
- private Int32 _inUseCount; // 0 to _slots.size
- private Int32 _pageId; // Page's Id
- private Int32 _nextFreeSlotLine; // o based position of next free slot line
- /*
- * size: number of slots per page. Maximum allowed is 64K
- */
- internal TreePage (int size)
- {
- if (size > 64 * 1024) {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.InvalidPageSize);
- }
- Slots = new Node[size];
- SlotMap = new Int32[(size + slotLineSize - 1) / slotLineSize];
- }
- /*
- * Allocate a free slot from the current page belonging to the specified tree.
- * return the Id of the allocated slot, or -1 if the current page does not have any free slots.
- */
- internal int AllocSlot (RBTree<K> tree)
- {
- int segmentPos = 0; // index into _SlotMap
- Int32 freeSlot = 0; // Uint, slot offset within the segment
- int freeSlotId = -1; // 0 based slot position
- if (_inUseCount < Slots.Length)
- {
- segmentPos = _nextFreeSlotLine;
- while (segmentPos < SlotMap.Length)
- {
- if (((UInt32)SlotMap[segmentPos]) < 0xFFFFFFFF)
- {
- freeSlotId = 0;
- freeSlot = (~(SlotMap[segmentPos])) & (SlotMap[segmentPos] + 1);
- // avoid string concat to allow debug code to run faster
- Debug.Assert((SlotMap[segmentPos] & freeSlot) == 0,"Slot position segment[segmentPos ]: [freeSlot] is in use. Expected to be empty");
- SlotMap[segmentPos] |= freeSlot; //mark free slot as used.
- _inUseCount++;
- if (_inUseCount == Slots.Length) // mark page as full
- tree.MarkPageFull (this);
- tree._inUseNodeCount++;
- // convert freeSlotPos to int value giving number of 0's to its right i.e. freeSlotId
- freeSlotId = GetIntValueFromBitMap((uint)freeSlot);
- _nextFreeSlotLine = segmentPos;
- freeSlotId = (segmentPos * TreePage.slotLineSize) + freeSlotId;
- break;
- }
- else
- {
- segmentPos++;
- }
- }
- if (freeSlotId == -1 && _nextFreeSlotLine != 0)
- {
- //Try one more time, starting from 0th segment position to locate a free slot.
- _nextFreeSlotLine = 0;
- freeSlotId = AllocSlot (tree);
- }
- }
- return freeSlotId; // 0 based slot position
- }
- internal Int32 InUseCount
- {
- get {return _inUseCount;}
- set {_inUseCount = value;}
- }
- internal Int32 PageId
- {
- get { return _pageId; }
- set { _pageId = value; }
- }
- }
- // SQLBU 428961: Serious performance issue when creating DataView
- // this improves performance allowing to iterating of the index instead of computing record by index
- // changes are required to handle satellite nodes which do not exist in DataRowCollection
- // enumerator over index will not be handed to the user, only used internally
- // instance of this enumerator will be handed to the user via DataRowCollection.GetEnumerator()
- internal struct RBTreeEnumerator : System.Collections.Generic.IEnumerator<K>, System.Collections.IEnumerator
- {
- private readonly RBTree<K> tree;
- private readonly int version;
- private int index, mainTreeNodeId;
- private K current;
- internal RBTreeEnumerator(RBTree<K> tree) {
- this.tree = tree;
- version = tree._version;
- index = NIL;
- mainTreeNodeId = tree.root;
- current = default(K);
- }
- internal RBTreeEnumerator(RBTree<K> tree, int position)
- {
- this.tree = tree;
- version = tree._version;
- if (0 == position)
- {
- index = NIL;
- mainTreeNodeId = tree.root;
- }
- else
- {
- index = tree.ComputeNodeByIndex(position-1, out mainTreeNodeId);
- if (NIL == index)
- {
- throw ExceptionBuilder.InternalRBTreeError(RBTreeError.IndexOutOFRangeinGetNodeByIndex);
- }
- }
- current = default(K);
- }
- public void Dispose() {
- }
- public bool MoveNext() {
- if (version != tree._version) {
- throw ExceptionBuilder.EnumeratorModified();
- }
- bool hasCurrent = tree.Successor(ref index, ref mainTreeNodeId);
- current = tree.Key(index);
- return hasCurrent;
- }
- public K Current {
- get {
- return current;
- }
- }
- Object System.Collections.IEnumerator.Current {
- get {
- return Current;
- }
- }
- void System.Collections.IEnumerator.Reset() {
- if (version != tree._version) {
- throw ExceptionBuilder.EnumeratorModified();
- }
- index = NIL;
- mainTreeNodeId = tree.root;
- current = default(K);
- }
- }
- }
- }
|