Leaked source code of windows server 2003
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.

595 lines
18 KiB

  1. #ifndef _UNIQUE_HPP_
  2. #define _UNIQUE_HPP_
  3. // Ruler
  4. // 1 2 3 4 5 6 7 8
  5. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  6. /********************************************************************/
  7. /* */
  8. /* The standard layout. */
  9. /* */
  10. /* The standard layout for 'hpp' files for this code is as */
  11. /* follows: */
  12. /* */
  13. /* 1. Include files. */
  14. /* 2. Constants exported from the class. */
  15. /* 3. Data structures exported from the class. */
  16. /* 4. Forward references to other data structures. */
  17. /* 5. Class specifications (including inline functions). */
  18. /* 6. Additional large inline functions. */
  19. /* */
  20. /* Any portion that is not required is simply omitted. */
  21. /* */
  22. /********************************************************************/
  23. #include "Global.hpp"
  24. #include "Hash.hpp"
  25. #include "List.hpp"
  26. #include "Pool.hpp"
  27. /********************************************************************/
  28. /* */
  29. /* Constants exported from the class. */
  30. /* */
  31. /* The constants supplied here control how unique strings */
  32. /* are constructed. */
  33. /* */
  34. /********************************************************************/
  35. CONST SBIT32 MinDetails = 16;
  36. /********************************************************************/
  37. /* */
  38. /* Class forward references. */
  39. /* */
  40. /* We need to refer to the following classes before they are */
  41. /* fully specified so here we list them as forward references. */
  42. /* */
  43. /********************************************************************/
  44. template <class LOCK> class UNIQUE;
  45. /********************************************************************/
  46. /* */
  47. /* A string description. */
  48. /* */
  49. /* All unique strings have a string drescription which is */
  50. /* into either the active or free list. */
  51. /* */
  52. /********************************************************************/
  53. class DETAIL : public LIST
  54. {
  55. private:
  56. //
  57. // Friend classes.
  58. //
  59. friend class UNIQUE<NO_LOCK>;
  60. friend class UNIQUE<PARTIAL_LOCK>;
  61. friend class UNIQUE<FULL_LOCK>;
  62. //
  63. // Private data.
  64. //
  65. BOOLEAN Active;
  66. SBIT32 Size;
  67. CHAR *Text;
  68. SBIT32 Uses;
  69. };
  70. /********************************************************************/
  71. /* */
  72. /* A unique string. */
  73. /* */
  74. /* Almost all the other classes in the library offer valuable */
  75. /* free-standing functionality. However, this class is really */
  76. /* just a support class for the variable length string class. */
  77. /* */
  78. /********************************************************************/
  79. template <class LOCK=PARTIAL_LOCK> class UNIQUE : public HASH<SBIT32,POINTER>
  80. {
  81. //
  82. // Private data.
  83. //
  84. LIST Active;
  85. LIST Free;
  86. DETAIL *Default;
  87. POOL<DETAIL> Details;
  88. LOCK Sharelock;
  89. public:
  90. //
  91. // Public functions.
  92. //
  93. UNIQUE( VOID );
  94. DETAIL *CreateString( CHAR *String,SBIT32 Size );
  95. SBIT32 CompareStrings( DETAIL *Detail1,DETAIL *Detail2 );
  96. DETAIL *CopyString( DETAIL *Detail1,DETAIL *Detail2 );
  97. VOID DeleteString( DETAIL *Detail );
  98. ~UNIQUE( VOID );
  99. //
  100. // Public inline functions.
  101. //
  102. INLINE DETAIL *DefaultString( VOID )
  103. { return Default; }
  104. INLINE SBIT32 Size( DETAIL *Detail )
  105. { return Detail -> Size; }
  106. INLINE CHAR *Value( DETAIL *Detail )
  107. { return Detail -> Text; }
  108. private:
  109. //
  110. // Private functions.
  111. //
  112. VIRTUAL SBIT32 ComputeHashKey
  113. (
  114. CONST SBIT32 & Key
  115. );
  116. VIRTUAL BOOLEAN MatchingKeys
  117. (
  118. CONST SBIT32 & Key1,
  119. CONST SBIT32 & Key2
  120. );
  121. //
  122. // Disabled operations.
  123. //
  124. UNIQUE( CONST UNIQUE & Copy );
  125. VOID operator=( CONST UNIQUE & Copy );
  126. };
  127. /********************************************************************/
  128. /* */
  129. /* Class constructor. */
  130. /* */
  131. /* Create a new unique string table. This call is not thread */
  132. /* safe and should only be made in a single thread environment. */
  133. /* */
  134. /********************************************************************/
  135. template <class LOCK> UNIQUE<LOCK>::UNIQUE( VOID )
  136. {
  137. //
  138. // Create the default string.
  139. //
  140. Default = CreateString( "",0 );
  141. }
  142. /********************************************************************/
  143. /* */
  144. /* Create a new unique string. */
  145. /* */
  146. /* When we are handed a new string we need to find out whether */
  147. /* it is unique (and needs to be added to the table) or just a */
  148. /* duplicate of an existing string. */
  149. /* */
  150. /********************************************************************/
  151. template <class LOCK> DETAIL *UNIQUE<LOCK>::CreateString
  152. (
  153. CHAR *String,
  154. SBIT32 Size
  155. )
  156. {
  157. AUTO DETAIL *Detail1;
  158. AUTO DETAIL *Detail2;
  159. //
  160. // Claim an exclusive lock (if enabled).
  161. //
  162. Sharelock.ClaimExclusiveLock();
  163. //
  164. // Let us assume that the string is unique and
  165. // build an entry to for it. If we later find
  166. // it is not then we just back out the changes.
  167. //
  168. if ( Free.EndOfList() )
  169. {
  170. REGISTER SBIT32 Count;
  171. //
  172. // Create a several new string descriptions
  173. // and link them into the free list.
  174. //
  175. for ( Count=0;Count < MinDetails;Count ++ )
  176. {
  177. //
  178. // Create a new description and add it
  179. // to the free list.
  180. //
  181. Detail1 = new DETAIL;
  182. Detail1 -> Active = False;
  183. Detail1 -> Insert( & Free );
  184. }
  185. }
  186. //
  187. // We know that the free list must contain
  188. // least one element (if not we would have
  189. // just made some). We extract the oldest
  190. // here.
  191. //
  192. if ( (Detail1 = ((DETAIL*) Free.Last())) -> Active )
  193. {
  194. //
  195. // Delete any existing value when we
  196. // recycle an old and unused string
  197. // description. Remember to remove
  198. // it from the hash before deleting
  199. // the string as the hash uses the
  200. // string.
  201. //
  202. RemoveFromHash( ((SBIT32) Detail1) );
  203. delete [] Detail1 -> Text;
  204. Detail1 -> Active = False;
  205. }
  206. //
  207. // We now setup the string description for the
  208. // new string.
  209. //
  210. Detail1 -> Size = Size;
  211. Detail1 -> Text = String;
  212. Detail1 -> Uses = 1;
  213. //
  214. // We are now ready to search the hash table for
  215. // a matching string. We do this by overloading
  216. // the hash table key comparision (see later).
  217. //
  218. if ( ! FindInHash( ((SBIT32) Detail1),((POINTER*) & Detail2) ) )
  219. {
  220. //
  221. // We have found a new string so we need to
  222. // make the string description active and
  223. // insert it in the active list.
  224. //
  225. (Detail2 = Detail1) -> Active = True;
  226. Detail1 -> Delete( & Free );
  227. Detail1 -> Insert( & Active );
  228. //
  229. // Add the new unique string the the hash
  230. // table so we can find it later.
  231. //
  232. AddToHash( ((SBIT32) Detail1),((POINTER) Detail1) );
  233. //
  234. // We know the string is unique so lets
  235. // allocate some space for it and copy it
  236. // into the new area.
  237. //
  238. Detail1 -> Text =
  239. (
  240. strncpy
  241. (
  242. new CHAR [ (Size + 1) ],
  243. String,
  244. Size
  245. )
  246. );
  247. Detail1 -> Text[ Size ] = '\0';
  248. }
  249. else
  250. {
  251. //
  252. // Increment the use count for an existing
  253. // string.
  254. //
  255. if ( Detail2 != Default )
  256. {
  257. //
  258. // We may be lucky and find an unused
  259. // string. If so we need to add it to
  260. // the active list again.
  261. //
  262. if ( (Detail2 -> Uses ++) == 0 )
  263. {
  264. //
  265. // Add an unused string back to the
  266. // active list again.
  267. //
  268. Detail1 -> Delete( & Free );
  269. Detail1 -> Insert( & Active );
  270. }
  271. }
  272. }
  273. //
  274. // Release any lock we got earlier.
  275. //
  276. Sharelock.ReleaseExclusiveLock();
  277. return Detail2;
  278. }
  279. /********************************************************************/
  280. /* */
  281. /* Compare two strings. */
  282. /* */
  283. /* Compare two strings and find the relationship between them. */
  284. /* */
  285. /********************************************************************/
  286. template <class LOCK> SBIT32 UNIQUE<LOCK>::CompareStrings
  287. (
  288. DETAIL *Detail1,
  289. DETAIL *Detail2
  290. )
  291. {
  292. //
  293. // We know that all strings are unique so if the
  294. // string pointers match then they must be the
  295. // the same string.
  296. //
  297. if ( Detail1 != Detail2 )
  298. {
  299. REGISTER SBIT32 Result =
  300. (
  301. strncmp
  302. (
  303. Detail1 -> Text,
  304. Detail2 -> Text,
  305. (Detail1 -> Size < Detail2 -> Size)
  306. ? Detail1 -> Size
  307. : Detail2 -> Size
  308. )
  309. );
  310. //
  311. // If the strings match pick the longest.
  312. //
  313. if ( Result == 0 )
  314. { Result = ((Detail1 -> Size < Detail2 -> Size) ? -1 : 1); }
  315. return Result;
  316. }
  317. else
  318. { return 0; }
  319. }
  320. /********************************************************************/
  321. /* */
  322. /* Compute a hash key. */
  323. /* */
  324. /* Compute a hash key for the supplied key. This hash key */
  325. /* is used to select the hash chain to search. */
  326. /* */
  327. /********************************************************************/
  328. template <class LOCK> SBIT32 UNIQUE<LOCK>::ComputeHashKey
  329. (
  330. CONST SBIT32 & Key
  331. )
  332. {
  333. REGISTER SBIT32 Count;
  334. REGISTER DETAIL *Detail = ((DETAIL*) Key);
  335. REGISTER SBIT32 HashKey = 2964557531;
  336. for ( Count=0;Count < Detail -> Size;Count ++ )
  337. {
  338. REGISTER SBIT32 Value = ((SBIT32) Detail -> Text[ Count ]);
  339. HashKey = ((HashKey * Value) + Value);
  340. }
  341. return (HashKey & 0x3fffffff);
  342. }
  343. /********************************************************************/
  344. /* */
  345. /* Copy a string. */
  346. /* */
  347. /* All strings are unique so there is no need to copy a string. */
  348. /* Nonetheless, we still have to update the use counts. */
  349. /* */
  350. /********************************************************************/
  351. template <class LOCK> DETAIL *UNIQUE<LOCK>::CopyString
  352. (
  353. DETAIL *Detail1,
  354. DETAIL *Detail2
  355. )
  356. {
  357. //
  358. // Claim an exclusive lock (if enabled).
  359. //
  360. Sharelock.ClaimExclusiveLock();
  361. //
  362. // Decrement the use count for old string.
  363. //
  364. if ( Detail1 != Default )
  365. { Detail1 -> Uses --; }
  366. //
  367. // Increment the use count for new string.
  368. //
  369. if ( Detail2 != Default )
  370. { Detail2 -> Uses ++; }
  371. //
  372. // Release any lock we got earlier.
  373. //
  374. Sharelock.ReleaseExclusiveLock();
  375. return Detail2;
  376. }
  377. /********************************************************************/
  378. /* */
  379. /* Compare two hash keys. */
  380. /* */
  381. /* Compare two hash keys to see if they match. */
  382. /* */
  383. /********************************************************************/
  384. template <class LOCK> BOOLEAN UNIQUE<LOCK>::MatchingKeys
  385. (
  386. CONST SBIT32 & Key1,
  387. CONST SBIT32 & Key2
  388. )
  389. {
  390. REGISTER DETAIL *Detail1 = ((DETAIL*) Key1);
  391. REGISTER DETAIL *Detail2 = ((DETAIL*) Key2);
  392. return
  393. (
  394. (Detail1 -> Size == Detail2 -> Size)
  395. &&
  396. (strncmp( Detail1 -> Text,Detail2 -> Text,Detail1 -> Size ) == 0)
  397. );
  398. }
  399. /********************************************************************/
  400. /* */
  401. /* Delete a string. */
  402. /* */
  403. /* Delete a text string. */
  404. /* */
  405. /********************************************************************/
  406. template <class LOCK> VOID UNIQUE<LOCK>::DeleteString( DETAIL *Detail )
  407. {
  408. //
  409. // Claim an exclusive lock (if enabled).
  410. //
  411. Sharelock.ClaimExclusiveLock();
  412. //
  413. // Decrement the use count for the string.
  414. //
  415. if ( Detail != Default )
  416. {
  417. //
  418. // Decrement the use count and ensure that
  419. // this is not the last use of the string.
  420. //
  421. if ( (-- Detail -> Uses) == 0 )
  422. {
  423. //
  424. // When we delete the last use of
  425. // a string we add it to the free
  426. // list. The string can be reclaimed
  427. // if it is recreated before it is
  428. // deleted.
  429. //
  430. Detail -> Delete( & Active );
  431. Detail -> Insert( & Free );
  432. }
  433. }
  434. //
  435. // Release any lock we got earlier.
  436. //
  437. Sharelock.ReleaseExclusiveLock();
  438. }
  439. /********************************************************************/
  440. /* */
  441. /* Class destructor. */
  442. /* */
  443. /* Destory the unique string table. This call is not thread */
  444. /* safe and should only be made in a single thread environment. */
  445. /* */
  446. /********************************************************************/
  447. template <class LOCK> UNIQUE<LOCK>::~UNIQUE( VOID )
  448. {
  449. //
  450. // Delete all active strings.
  451. //
  452. while ( ! Active.EndOfList() )
  453. {
  454. REGISTER DETAIL *Detail = ((DETAIL*) Active.First());
  455. //
  456. // Delete from the list and add to the free
  457. // pool just to be tidy.
  458. //
  459. Detail -> Delete( & Active );
  460. //
  461. // The string description may be contain an
  462. // previous value and require some cleanup.
  463. //
  464. if ( Detail -> Active )
  465. {
  466. //
  467. // Delete any existing value. Remember
  468. // to remove it from the hash before
  469. // deleting the string as the hash uses
  470. // the string.
  471. //
  472. RemoveFromHash( ((SBIT32) Detail) );
  473. delete [] Detail -> Text;
  474. Detail -> Active = False;
  475. }
  476. //
  477. // Push back into the pool.
  478. //
  479. Details.PushPool( Detail );
  480. }
  481. //
  482. // Delete all free strings.
  483. //
  484. while ( ! Free.EndOfList() )
  485. {
  486. REGISTER DETAIL *Detail = ((DETAIL*) Free.First());
  487. //
  488. // Delete from the list and add to the free
  489. // pool just to be tidy.
  490. //
  491. Detail -> Delete( & Free );
  492. //
  493. // The string description may be contain an
  494. // previous value and require some cleanup.
  495. //
  496. if ( Detail -> Active )
  497. {
  498. //
  499. // Delete any existing value. Remember
  500. // to remove it from the hash before
  501. // deleting the string as the hash uses
  502. // the string.
  503. //
  504. RemoveFromHash( ((SBIT32) Detail) );
  505. delete [] Detail -> Text;
  506. Detail -> Active = False;
  507. }
  508. //
  509. // Push back into the pool.
  510. //
  511. Details.PushPool( Detail );
  512. }
  513. }
  514. #endif