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.

1009 lines
27 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Filename : TRIE.H
  4. // Purpose : Basic C MACROS/DEFS used by the Trie package
  5. //
  6. // Project : PQS
  7. // Component: FE_CORE
  8. //
  9. // Author : dovh
  10. //
  11. // Log :
  12. // MMM DD YYYY dovh Creation
  13. // Dec 11 1996 DovH UNICODE Preparation: Convert char to TCHAR.
  14. // Dec 1 1998 dovh Use HCFE_GlobalHandle
  15. // Nov 2 1999 YairH Fix copilation errors.
  16. // Nov 8 1999 urib Fix tabulation format.
  17. //
  18. ////////////////////////////////////////////////////////////////////////////////
  19. #ifndef __TRIE_H__
  20. #define __TRIE_H__
  21. #pragma once
  22. #include "comdefs.h"
  23. #include "gtable.h"
  24. #include "autoptr.h"
  25. #include "excption.h"
  26. #include "tracer.h"
  27. DECLARE_TAG(s_tagTrie, "Trie")
  28. //
  29. // T R I E P A C K A G E F L A G S :
  30. //
  31. #define TRIE_DEFAULT 0X00000000L
  32. #define TRIE_IGNORECASE 0X00000001L
  33. #define TRIE_SHORTEST_MATCH 0X00000010L
  34. #define TRIE_LONGEST_MATCH 0X00000020L
  35. #define TRIE_ALL_MATCHES 0X00000040L
  36. #define TRIE_FILTER_VERIFY 0X00000080L
  37. #define TRIE_EXCHANGE_ITEM 0X00000100L
  38. #define TRIE_OUT_BUFFER_EMPTY 0X00000200L
  39. #define TRIE_NODE_SUFFIXCOUNT_INIT 0
  40. #define TRIE_NODE_SUFFIXSIZE_INIT 2
  41. #define DECLARE_TRIE_SENTINEL CTrieNode<BYTE> g_trie_Sentinel
  42. template <class T, class C = CToUpper >
  43. class CTrieNode
  44. {
  45. public:
  46. CTrieNode();
  47. CTrieNode(short sSize);
  48. CTrieNode(
  49. T* NewItem,
  50. ULONG options,
  51. const WCHAR* NewString,
  52. ULONG ulCharToCopy = 0xffffffff);
  53. ~CTrieNode();
  54. void DeleteItem();
  55. void
  56. AddSuffix(
  57. ULONG options,
  58. CTrieNode<T, C>* newSuffix,
  59. USHORT index = 0xffff
  60. );
  61. void
  62. SplitNode(
  63. CTrieNode<T, C>* parent, // Parent of node
  64. short index, // Index of node in parent->suffix
  65. const WCHAR * NewString, // String sharing prefix with node->string
  66. size_t charsMatched,
  67. T* item, // Item associated with (sub)string
  68. ULONG options // Insertion options
  69. );
  70. void Print(ULONG ulOffset);
  71. int
  72. trie_StrMatchIns(
  73. const WCHAR * s,
  74. const WCHAR * t,
  75. size_t * matchCount
  76. );
  77. inline
  78. int
  79. trie_StrMatch(
  80. const WCHAR * s,
  81. const WCHAR * t,
  82. size_t * matchCount
  83. );
  84. private:
  85. void DoubleSuffixArray();
  86. public:
  87. short suffixCount; // Number of suffixes
  88. short suffixSize; // Size of suffixes array
  89. CTrieNode ** suffix; // Pointer to suffixes array
  90. T* item; // Pointer to item corresponding to node
  91. size_t charCount; // String length
  92. WCHAR* string; // Zero terminated string
  93. public:
  94. };
  95. extern CTrieNode<BYTE> g_trie_Sentinel;
  96. template <class T, class C = CToUpper >
  97. class CTrie
  98. {
  99. public:
  100. CTrie(bool fDeleteItemsOnDestruction = false);
  101. ~CTrie();
  102. DictStatus
  103. trie_Insert( // Insert string into trie
  104. const WCHAR * string, // String key of item
  105. unsigned long options, // Insertion flags
  106. T * item, // Item to be inserted
  107. T ** pTrieItem // Matching item already in trie
  108. );
  109. DictStatus
  110. trie_Find(
  111. const WCHAR * string, // A string
  112. unsigned long options, // Search flags
  113. short outBufferSize, // Max number of results wanted
  114. T ** outBuffer, // Buffer to be filled with matching items
  115. short * resultCount // Number of matching prefixes returned
  116. );
  117. void Print();
  118. private:
  119. CTrieNode<T, C>* root;
  120. bool fDeleteItems;
  121. };
  122. ///////////////////////////////////////////////////////////////////////////////
  123. // CTrieNode implementation
  124. ///////////////////////////////////////////////////////////////////////////////
  125. template <class T, class C >
  126. inline CTrieNode<T, C>::CTrieNode() :
  127. suffixCount(0),
  128. suffixSize(0),
  129. charCount(0),
  130. item(NULL),
  131. suffix(NULL)
  132. {
  133. string = new WCHAR[1];
  134. string[0] = L'\0';
  135. }
  136. template <class T, class C >
  137. inline CTrieNode<T, C>::CTrieNode(short sSize) :
  138. suffixCount(0),
  139. suffixSize(sSize),
  140. string(NULL),
  141. charCount(0),
  142. item(NULL),
  143. suffix(NULL)
  144. {
  145. Assert(sSize > 0);
  146. suffix = new CTrieNode<T, C>*[suffixSize];
  147. memset(suffix,0, suffixSize*sizeof(CTrieNode<T, C>*));
  148. }
  149. template <class T, class C >
  150. inline CTrieNode<T, C>::CTrieNode(
  151. T* NewItem,
  152. ULONG options,
  153. const WCHAR* NewString,
  154. ULONG ulCharToCopy) :
  155. suffixCount(TRIE_NODE_SUFFIXCOUNT_INIT),
  156. suffixSize(TRIE_NODE_SUFFIXSIZE_INIT)
  157. {
  158. charCount = min(wcslen(NewString), ulCharToCopy);
  159. CAutoArrayPointer<WCHAR> apwcsNewString = new WCHAR[charCount + 1];
  160. string = apwcsNewString.Get();
  161. wcsncpy(string, NewString, charCount);
  162. string[charCount] = L'\0';
  163. suffix = new CTrieNode<T, C>*[suffixSize];
  164. memset(suffix, 0, sizeof(CTrieNode<T, C>*) * suffixSize);
  165. item = NewItem;
  166. apwcsNewString.Detach();
  167. }
  168. template <class T, class C >
  169. inline void CTrieNode<T, C>::DeleteItem()
  170. {
  171. for (short s = 0; s < suffixCount; s++)
  172. {
  173. if (suffix[s] != (CTrieNode<T, C>*)&g_trie_Sentinel)
  174. {
  175. suffix[s]->DeleteItem();
  176. }
  177. }
  178. delete item;
  179. }
  180. template <class T, class C >
  181. inline CTrieNode<T, C>::~CTrieNode()
  182. {
  183. Trace(
  184. elInfo,
  185. s_tagTrie,(
  186. "CTrieNode:"
  187. "Released"));
  188. for (short s = 0; s < suffixCount; s++)
  189. {
  190. if (suffix[s] != (CTrieNode<T, C>*)&g_trie_Sentinel)
  191. {
  192. delete suffix[s];
  193. }
  194. }
  195. delete[] suffix;
  196. delete string;
  197. }
  198. template <class T, class C >
  199. inline
  200. int
  201. CTrieNode<T, C>::trie_StrMatch(
  202. const WCHAR * s,
  203. const WCHAR * t,
  204. size_t * matchCount
  205. )
  206. {
  207. const WCHAR * s0 = s;
  208. const WCHAR * t0 = t;
  209. //
  210. // Straigh K&R ptr version...
  211. //
  212. for ( ; *s0 == *t0; s0++, t0++ )
  213. {
  214. if (*s0 == TEXT('\0'))
  215. {
  216. *matchCount = s0 - s;
  217. Assert( (*s0 - *t0) == 0 );
  218. return (0);
  219. }
  220. }
  221. *matchCount = s0 - s;
  222. return ( *s0 - *t0 );
  223. } // end trie_StrMatch
  224. template <class T, class C >
  225. inline
  226. int
  227. CTrieNode<T, C>::trie_StrMatchIns(
  228. const WCHAR * s,
  229. const WCHAR * t,
  230. size_t * matchCount
  231. )
  232. {
  233. const WCHAR * s0 = s;
  234. const WCHAR * t0 = t;
  235. //
  236. // Straigh K&R ptr version...
  237. //
  238. for ( ; C::MapToUpper(*s0) == C::MapToUpper(*t0); s0++, t0++ )
  239. {
  240. if (*s0 == TEXT('\0'))
  241. {
  242. *matchCount = s0 - s;
  243. Assert ( (C::MapToUpper(*s0) - C::MapToUpper(*t0)) == 0 );
  244. return (0);
  245. }
  246. }
  247. *matchCount = s0 - s;
  248. return ( C::MapToUpper(*s0) - C::MapToUpper(*t0) );
  249. } // end trie_StrMatchIns
  250. /*++
  251. Function trie_AddSuffix:
  252. Insert a new suffix into the suffix array of node.
  253. Routine Parameters:
  254. node - Add a newSuffix to node->suffix array.
  255. index - index in node->suffix to at which newSuffix should be added
  256. to preserve increasing lexicographic ordering on node->suffix.
  257. newSuffix - new suffix node to be added as child of node.
  258. Return value:
  259. --*/
  260. template <class T, class C >
  261. inline void
  262. CTrieNode<T, C>::AddSuffix(
  263. ULONG options,
  264. CTrieNode<T, C>* newSuffix,
  265. USHORT index
  266. )
  267. {
  268. //
  269. // Make sure there is enough room for the new child:
  270. //
  271. Assert(suffixCount <= suffixSize);
  272. if (suffixCount == suffixSize)
  273. {
  274. DoubleSuffixArray();
  275. }
  276. if (0xffff == index)
  277. {
  278. if (options & TRIE_IGNORECASE)
  279. {
  280. for ( index=0;
  281. (index < suffixCount) &&
  282. (C::MapToUpper(suffix[index]->string[0]) < C::MapToUpper(newSuffix->string[0]));
  283. index++
  284. )
  285. ;
  286. }
  287. else
  288. {
  289. for ( index=0;
  290. (index < suffixCount) &&
  291. (suffix[index]->string[0] < newSuffix->string[0]);
  292. index++
  293. )
  294. ;
  295. }
  296. }
  297. #ifdef DEBUG
  298. if (options & TRIE_IGNORECASE)
  299. {
  300. Assert((index == 0 ) ||
  301. (index == suffixCount) ||
  302. (C::MapToUpper(suffix[index]->string[0]) > C::MapToUpper(newSuffix->string[0])));
  303. }
  304. else
  305. {
  306. Assert((index == 0 ) ||
  307. (index == suffixCount) ||
  308. (suffix[index]->string[0] > newSuffix->string[0]));
  309. }
  310. #endif
  311. //
  312. // Shift node->suffix[index .. node->suffixCount] one location to the right
  313. // to make room for newSuffix at location index:
  314. //
  315. if ( index < suffixCount )
  316. {
  317. for (short i=suffixCount; i>index; i--)
  318. {
  319. suffix[i] = suffix[i-1];
  320. }
  321. }
  322. suffixCount++;
  323. //
  324. // WARNING: after the next line do not add more allocations. The new suffix
  325. // might be an automatic pointer that in this case will be released twice,
  326. // as part of the destruction of the class and as automatic pointer
  327. //
  328. suffix[index] = newSuffix;
  329. } // end AddSuffix
  330. /*++
  331. Function trie_SplitNode:
  332. Assume string and node->string has a non-empty common prefix, which
  333. is a strict substring of node->string. Splits node->string into the common
  334. prefix, and the two suffixes (string may be a prefix of node->string) in which
  335. case the corresponding suffix is NULL, represented by trie_Sentinel?).
  336. Add two new children representing the admissible continuations of
  337. the common suffix.
  338. Return value:
  339. Log:
  340. Apr-14-1998 dovh - PerlWarn: change to ==:
  341. Assert( node = parent->suffix[ index ] );
  342. --*/
  343. template <class T, class C >
  344. inline void
  345. CTrieNode<T, C>::SplitNode(
  346. CTrieNode<T, C>* parent, // Parent of node
  347. short index, // Index of node in parent->suffix
  348. const WCHAR * NewString, // String sharing prefix with node->string
  349. size_t charsMatched,
  350. T* item, // Item associated with (sub)string
  351. ULONG options // Insertion options
  352. )
  353. {
  354. //
  355. // Verify that the prefix common to string and node->string is
  356. // a non-NULL proper prefix of node->string:
  357. //
  358. Assert( ( (options & TRIE_IGNORECASE) ?
  359. (C::MapToUpper(*string) == C::MapToUpper(*NewString)) :
  360. (*string == *NewString) )
  361. );
  362. Assert(charsMatched < wcslen(string));
  363. //
  364. // Set up the prefix node to replace node as child of parent:
  365. //
  366. CAutoClassPointer<CTrieNode<T, C> > nodePrefix =
  367. new CTrieNode<T, C>(NULL, options, string, charsMatched);
  368. //
  369. // Compute respective suffix of string and add as the second child
  370. // of nodePrefix:
  371. //
  372. if ( wcslen(NewString) == charsMatched )
  373. {
  374. //
  375. // TRIE_ITEM: Add trie_Sentinel to nodePrefix;
  376. // nodePrefix should point to new item!
  377. //
  378. nodePrefix->AddSuffix(0,(CTrieNode<T, C>*)&g_trie_Sentinel, 0);
  379. nodePrefix->item = item;
  380. }
  381. else
  382. {
  383. Assert( charsMatched < wcslen(NewString) );
  384. //
  385. // Allocate the string suffix node:
  386. //
  387. CAutoClassPointer<CTrieNode<T, C> > strSuffix =
  388. new CTrieNode(item, options, &NewString[charsMatched]);
  389. nodePrefix->AddSuffix(options, strSuffix.Get());
  390. strSuffix.Detach();
  391. }
  392. WCHAR* pwcsCurrStr = string;
  393. size_t CurrCharCount = charCount;
  394. try
  395. {
  396. size_t newCharCount = charCount - charsMatched;
  397. Assert(newCharCount > 0);
  398. CAutoArrayPointer<WCHAR> apwcsNewStr = new WCHAR[newCharCount + 1];
  399. wcscpy(apwcsNewStr.Get(), &(string[charsMatched]));
  400. string = apwcsNewStr.Get();
  401. charCount = newCharCount;
  402. //
  403. // Add node as a child of nodePrefix:
  404. // (Recall: node->string == respective suffix)
  405. //
  406. nodePrefix->AddSuffix(options, this);
  407. apwcsNewStr.Detach();
  408. delete[] pwcsCurrStr;
  409. }
  410. catch (CMemoryException& e)
  411. {
  412. string = pwcsCurrStr;
  413. charCount = CurrCharCount;
  414. throw e;
  415. }
  416. //
  417. // Replace node by nodePrefix as the respective child of parent:
  418. //
  419. Assert( this == parent->suffix[ index ] );
  420. parent->suffix[ index ] = nodePrefix.Get();
  421. nodePrefix.Detach();
  422. } // end trie_SplitNode
  423. template <class T, class C >
  424. inline void
  425. CTrieNode<T, C>::Print(ULONG ulOffset)
  426. {
  427. for (ULONG i = 0; i < ulOffset; i++)
  428. {
  429. printf(" ");
  430. }
  431. if (this == (CTrieNode<T, C>*)&g_trie_Sentinel)
  432. {
  433. printf("Sentinel\n");
  434. }
  435. else
  436. {
  437. printf("%S\n",string);
  438. }
  439. for (short k = 0; k < suffixCount; k++)
  440. {
  441. suffix[k]->Print(ulOffset + 4);
  442. }
  443. }
  444. template <class T, class C >
  445. inline void
  446. CTrieNode<T, C>::DoubleSuffixArray()
  447. {
  448. short newSize;
  449. if (0 == suffixSize)
  450. {
  451. newSize = TRIE_NODE_SUFFIXSIZE_INIT;
  452. }
  453. else
  454. {
  455. newSize = suffixSize * 2;
  456. }
  457. CTrieNode<T, C> ** newPSuffix;
  458. Assert(suffixCount == suffixSize);
  459. newPSuffix = new CTrieNode<T, C>*[newSize];
  460. memcpy(newPSuffix, suffix, suffixSize*sizeof(CTrieNode<T, C>*));
  461. delete[] suffix;
  462. suffix = newPSuffix;
  463. suffixSize = newSize;
  464. } // end trie_DoubleNode
  465. ///////////////////////////////////////////////////////////////////////////////
  466. // CTrie implementation
  467. ///////////////////////////////////////////////////////////////////////////////
  468. template <class T, class C >
  469. inline CTrie<T, C>::CTrie(bool fDeleteItemsOnDestruction) :
  470. fDeleteItems(fDeleteItemsOnDestruction)
  471. {
  472. root = new CTrieNode<T, C>(TRIE_NODE_SUFFIXSIZE_INIT);
  473. }
  474. template <class T, class C >
  475. inline CTrie<T, C>::~CTrie()
  476. {
  477. if (fDeleteItems)
  478. {
  479. root->DeleteItem();
  480. }
  481. delete root;
  482. }
  483. /*++
  484. Function trie_Insert:
  485. Insert a given string into trie if it's not already a member trie.
  486. Routine Parameters:
  487. trie - Trie to insert item into.
  488. string - String key of item.
  489. options - Insertion options. If options == 0 the item will be inserted
  490. only if the string key is not already in the tree. If options
  491. is TRIE_EXCHANGE_ITEM the existing trie item will be replaced by
  492. the item argument in the Trie. In that case the existing item
  493. associated with string in the trie will be returned in the
  494. *pTrieItem argument.
  495. item - New item to be inserted.
  496. pTrieItem - If an item associated with string already exists,
  497. then *pTrieItem points to that item upon return.
  498. Return value:
  499. DICT_SUCCESS if string was inserted successfully, else
  500. DICT_ITEM_ALREADY_PRESENT.
  501. --*/
  502. template <class T, class C >
  503. inline DictStatus
  504. CTrie<T, C>::trie_Insert( // Insert string into trie
  505. const WCHAR * string, // String key of item
  506. unsigned long options, // Insertion flags
  507. T * item, // Item to be inserted
  508. T ** pTrieItem // Matching item already in trie
  509. )
  510. {
  511. CTrieNode<T, C> * t, * c;
  512. int cmp = -1;
  513. const WCHAR * subString = string;
  514. size_t subStringSize = wcslen(subString);
  515. size_t strIndex = 0;
  516. size_t charsMatched = 0;
  517. CAutoClassPointer<CTrieNode<T, C> > apNewSuffix;
  518. t = root;
  519. if (pTrieItem != NULL)
  520. {
  521. *pTrieItem = NULL;
  522. }
  523. while (true)
  524. {
  525. short i = 0;
  526. //
  527. // Search in this level sorted alternatives list:
  528. //
  529. for ( i = 0;
  530. i < t->suffixCount;
  531. i++
  532. )
  533. {
  534. c = t->suffix[i];
  535. // Quick "skip check":
  536. cmp = (options & TRIE_IGNORECASE) ?
  537. (C::MapToUpper(*c->string) - C::MapToUpper(*subString)) :
  538. (*c->string - *subString);
  539. if ( cmp < 0)
  540. {
  541. continue;
  542. }
  543. if (cmp > 0)
  544. {
  545. //
  546. // First character of t->string does not match,
  547. // insert a copy of subString before c (== t->suffix[i]):
  548. //
  549. apNewSuffix = new CTrieNode<T, C>(item, options, subString);
  550. t->AddSuffix(options, apNewSuffix.Get(), i);
  551. apNewSuffix.Detach();
  552. return DICT_SUCCESS;
  553. }
  554. else
  555. {
  556. // At least one character matched.
  557. // subStringSize = _tcslen(subString);
  558. cmp = (options & TRIE_IGNORECASE) ?
  559. c->trie_StrMatchIns(c->string, subString, &charsMatched) :
  560. c->trie_StrMatch(c->string, subString, &charsMatched);
  561. Assert(charsMatched <= min(c->charCount, subStringSize));
  562. if (cmp == 0)
  563. {
  564. // t->charCount (<= subStringSize) characters matched
  565. //
  566. Assert(c->charCount == subStringSize);
  567. // subString matched exactly:
  568. //
  569. if ((c->suffixCount == 0) ||
  570. (c->suffix[0] == (CTrieNode<T, C>*)&g_trie_Sentinel))
  571. {
  572. // string already present:
  573. //
  574. if (pTrieItem != NULL)
  575. {
  576. *pTrieItem = c->item;
  577. }
  578. if (options & TRIE_EXCHANGE_ITEM)
  579. {
  580. Assert(pTrieItem!= NULL);
  581. c->item = item;
  582. }
  583. return(DICT_ITEM_ALREADY_PRESENT);
  584. }
  585. else
  586. {
  587. //
  588. // Insert the NULL trie_Sentinel at the front of
  589. // the c->suffix list; and terminate!
  590. //
  591. // c should point to new item!
  592. //
  593. c->AddSuffix(options, (CTrieNode<T, C>*)&g_trie_Sentinel, 0);
  594. c->item = item;
  595. return( DICT_SUCCESS );
  596. }
  597. }
  598. else
  599. {
  600. //
  601. // cmp != 0:
  602. //
  603. if (charsMatched == c->charCount)
  604. {
  605. // CASE I: t->string is shorter than subString,
  606. // and all of t->string matched.
  607. // Continue the search through the suffixes subtree:
  608. //
  609. strIndex += c->charCount;
  610. Assert( strIndex < wcslen(string) );
  611. subString = &string[strIndex];
  612. subStringSize = wcslen(subString);
  613. t = c;
  614. i = -1;
  615. continue;
  616. }
  617. else
  618. {
  619. // CASE II: the child c and subString have a common prefix which is
  620. // a non-NULL strict prefix of c->string. Split c into the common
  621. // prefix node (a new node which will replace c as a child of t),
  622. // with two children: c (with a corresponding suffix); and a new
  623. // node (with the respective suffix of subString);
  624. //
  625. c->SplitNode(
  626. t, // Parent of node to split
  627. i, // Index of node in parent->suffix
  628. subString, // String sharing prefix with node->string
  629. charsMatched,
  630. item,
  631. options
  632. );
  633. return( DICT_SUCCESS );
  634. }
  635. } // end if (cmp == 0)
  636. } // end if (cmp > 0)
  637. } // end for
  638. //
  639. // Either the new string was successfully inserted, in which case
  640. // we would have returned already; or we reached the end of the
  641. // suffix array:
  642. //
  643. //
  644. // Insert a copy of subString at the end of t->suffix:
  645. //
  646. apNewSuffix = new CTrieNode<T, C>(item, options, subString);
  647. //
  648. // Add item parameter to trie_NewNode!
  649. //
  650. t->AddSuffix(options, apNewSuffix.Get(), i);
  651. apNewSuffix.Detach();
  652. if (t->suffixCount == 1 && t->charCount != 0)
  653. {
  654. //
  655. // First child of t and t is not the root of the trie;
  656. // add a sentinel to t to designate
  657. // that t->string is an actual item:
  658. //
  659. t->AddSuffix(options, (CTrieNode<T, C>*)&g_trie_Sentinel, 0);
  660. }
  661. return DICT_SUCCESS;
  662. } // end while
  663. Assert(0);
  664. return(DICT_ITEM_NOT_FOUND);
  665. } // end trie_Insert
  666. template <class T, class C >
  667. inline DictStatus
  668. CTrie<T, C>::trie_Find(
  669. const WCHAR * string, // A string
  670. unsigned long options, // Search flags
  671. short outBufferSize, // Max number of results wanted
  672. T ** outBuffer, // Buffer to be filled with matching items
  673. short * resultCount // Number of matching prefixes returned
  674. )
  675. {
  676. CTrieNode<T, C> * node = root;
  677. CTrieNode<T, C> * child = NULL;
  678. int cmp = -1;
  679. DictStatus status = DICT_ITEM_NOT_FOUND;
  680. const WCHAR * subString = string;
  681. size_t strIndex = 0;
  682. size_t charsMatched = 0;
  683. int i;
  684. // at least one option matches:
  685. Assert( options &
  686. (TRIE_SHORTEST_MATCH | TRIE_LONGEST_MATCH | TRIE_ALL_MATCHES)
  687. );
  688. // at most one option matches:
  689. Assert ( ( ((options & TRIE_SHORTEST_MATCH)>>4) +
  690. ((options & TRIE_LONGEST_MATCH)>>5) +
  691. ((options & TRIE_ALL_MATCHES)>>6)
  692. ) == 1
  693. );
  694. //
  695. // Initialization:
  696. //
  697. Assert(outBufferSize > 0);
  698. Assert(outBuffer);
  699. memset(outBuffer, 0, sizeof(CTrieNode<T, C>*) * outBufferSize);
  700. *resultCount = 0;
  701. while ( status != DICT_SUCCESS &&
  702. *resultCount < outBufferSize
  703. )
  704. {
  705. if (child != NULL)
  706. {
  707. strIndex += child->charCount;
  708. subString = &string[strIndex];
  709. node = child;
  710. }
  711. //
  712. // Future: low & high can be improved by a partial binary search on
  713. // the first character of string in node->suffix:
  714. // if (node->suffixSize > threshold)
  715. // trie_BinarySearch( &low, &high, subString[0]);
  716. //
  717. //
  718. // Search in this level sorted alternatives list:
  719. //
  720. for ( i = 0;
  721. i < node->suffixCount;
  722. i++
  723. )
  724. {
  725. // Quick "skip check":
  726. child = node->suffix[i];
  727. cmp = options & TRIE_IGNORECASE ?
  728. C::MapToUpper(*child->string) - C::MapToUpper(*subString) :
  729. *child->string - *subString;
  730. if ( cmp < 0 )
  731. {
  732. continue;
  733. }
  734. else
  735. {
  736. break;
  737. }
  738. } // end for
  739. Assert(cmp >= 0 || i == node->suffixCount);
  740. if (cmp != 0)
  741. {
  742. //
  743. // First character did not match => subString mismatched;
  744. // Bail out:
  745. //
  746. break; // From while loop!
  747. }
  748. //
  749. // cmp == 0 => first character matched;
  750. // Try to match more of subString:
  751. //
  752. // Note: subStringSize == _tcslen(subString);
  753. //
  754. cmp = (options & TRIE_IGNORECASE) ?
  755. child->trie_StrMatchIns(child->string, subString, &charsMatched) :
  756. child->trie_StrMatch(child->string, subString, &charsMatched);
  757. Assert(charsMatched <= min(child->charCount, MAX_PATTERN_LENGTH));
  758. if (charsMatched != child->charCount)
  759. {
  760. //
  761. // child->string did not match;
  762. // there are no more prefixes of string in trie
  763. //
  764. // return (status);
  765. break; // From while loop!
  766. }
  767. //
  768. // Interesting case: all of child->string matched.
  769. //
  770. if (child->item != NULL)
  771. {
  772. //
  773. // Child represents a real item:
  774. // Add child->item to result set:
  775. //
  776. outBuffer[*resultCount] = child->item;
  777. if (0 == cmp)
  778. {
  779. status = DICT_SUCCESS;
  780. }
  781. if ( (options & TRIE_SHORTEST_MATCH) ==
  782. TRIE_SHORTEST_MATCH
  783. )
  784. {
  785. // (*resultCount)++;
  786. // return(status);
  787. break; // From while loop!
  788. }
  789. else
  790. {
  791. if ( (options & TRIE_ALL_MATCHES) ==
  792. TRIE_ALL_MATCHES
  793. )
  794. {
  795. (*resultCount)++;
  796. }
  797. }
  798. //
  799. // Descend into subtree rooted at child:
  800. //
  801. continue;
  802. }
  803. else
  804. {
  805. //
  806. // Child does not represent a real item;
  807. // keep looking for matches.
  808. // descend into subtree rooted at child:
  809. //
  810. continue;
  811. }
  812. } // end while
  813. if ( ((options & TRIE_LONGEST_MATCH)||
  814. (options & TRIE_SHORTEST_MATCH)) &&
  815. (outBuffer[*resultCount] != NULL))
  816. {
  817. (*resultCount)++;
  818. }
  819. return(status);
  820. } // end trie_Find
  821. template <class T, class C >
  822. inline void
  823. CTrie<T, C>::Print()
  824. {
  825. root->Print(0);
  826. }
  827. #endif // __TRIE_H__