Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
3.3 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: DIRTREE.CXX
  7. //
  8. // Contents: Directory Tree
  9. //
  10. // Classes: CDirTree
  11. //
  12. // History: 13-Aug-91 BartoszM Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <misc.hxx>
  18. #include <dirtree.hxx>
  19. void CDirTree::Init ( unsigned count )
  20. {
  21. //
  22. // If we are rebuilding the directory tree, cleanup the old one
  23. //
  24. if (_count != 0)
  25. {
  26. delete _pKeys;
  27. _pKeys = new CKeyArray(1);
  28. }
  29. ciAssert ( count > 0 );
  30. _count = count;
  31. // How many binary digits are needed
  32. // to represent numbers from 0 to _count-1?
  33. if ( _count > 1 )
  34. _digits = Log2 ( _count - 1 );
  35. else
  36. _digits = 0;
  37. _firstLeaf = 1 << _digits;
  38. }
  39. void CDirTree::Init ( CKeyArray& keys, unsigned count )
  40. {
  41. Init ( count );
  42. for ( unsigned n = 1; n < count; n++)
  43. {
  44. ciAssert ( keys.Get(n).Pid() != pidAll );
  45. _pKeys->Add ( Index(n), keys.Get(n) );
  46. }
  47. Done ( n );
  48. }
  49. void CDirTree::Add ( unsigned i, const CKeyBuf& key )
  50. {
  51. // skip the zerot'th key
  52. if ( i == 0 )
  53. return;
  54. ciAssert ( &key != 0 );
  55. ciAssert ( key.Pid() != pidAll );
  56. _pKeys->Add ( Index(i), key);
  57. }
  58. unsigned CDirTree::Seek ( const CKey& key ) const
  59. {
  60. ciDebugOut (( DEB_PDIR, "CDirTree::Seek %.*ws pid %d\n",
  61. key.StrLen(), key.GetStr(), key.Pid() ));
  62. //----------------------------------------------------
  63. // Notice: Make sure that pidAll is smaller
  64. // than any other legal PID. If the search key
  65. // has pidAll we want to be positioned at the beginning
  66. // of the range.
  67. //----------------------------------------------------
  68. ciAssert ( pidAll == 0 );
  69. for ( unsigned i = 1; i < _firstLeaf; )
  70. {
  71. ciDebugOut (( DEB_PDIR, "\tCompare with %.*ws pid %d ",
  72. _pKeys->Get(i).StrLen(), _pKeys->Get(i).GetStr(), _pKeys->Get(i).Pid() ));
  73. if ( key.Compare(_pKeys->Get(i)) < 0 )
  74. {
  75. ciDebugOut (( DEB_PDIR, "too big\n" ));
  76. i = 2 * i;
  77. }
  78. else
  79. {
  80. ciDebugOut (( DEB_PDIR, "too small or equal\n" ));
  81. i = 2 * i + 1;
  82. }
  83. }
  84. return i - _firstLeaf;
  85. }
  86. // Decompose idx = (1, 2^digits - 1) in the following form
  87. // idx = i * 2^n, where i is odd
  88. // n counts the number of trailing zeros,
  89. // i has (digits - n) digits
  90. //
  91. // level = digits - n
  92. // is the level of the tree (root is level 1)
  93. //
  94. // i / 2 is the node number within this level
  95. // it has (level-1) digits
  96. unsigned CDirTree::Index( unsigned idx )
  97. {
  98. ciAssert (idx != 0);
  99. unsigned i = idx;
  100. unsigned n = 0;
  101. while ( (i & 1) == 0 )
  102. {
  103. i >>= 1;
  104. n++;
  105. }
  106. // n = number of trailing 0's
  107. // i is odd
  108. idx = (1 << (_digits - n - 1)) + (i >> 1);
  109. ciAssert ( idx < _firstLeaf );
  110. return idx;
  111. }
  112. void CDirTree::Done( unsigned i )
  113. {
  114. //
  115. // This can be very expensive, since each key will allocate
  116. // > 250 bytes and fill them with 0xff. But it's too late to do anything
  117. // about it since the definition of max key is defined now that we've
  118. // shipped.
  119. //
  120. for ( ; i < _firstLeaf; i++ )
  121. _pKeys->FillMax(Index(i));
  122. }