home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / i18n / coleitr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  14.9 KB  |  569 lines

  1. /*
  2. *****************************************************************************************
  3. *                                                                                       *
  4. * COPYRIGHT:                                                                            *
  5. *   (C) Copyright Taligent, Inc.,  1996                                                 *
  6. *   (C) Copyright International Business Machines Corporation,  1996-1998               *
  7. *   Licensed Material - Program-Property of IBM - All Rights Reserved.                  *
  8. *   US Government Users Restricted Rights - Use, duplication, or disclosure             *
  9. *   restricted by GSA ADP Schedule Contract with IBM Corp.                              *
  10. *                                                                                       *
  11. *****************************************************************************************
  12. */
  13. //=============================================================================
  14. //
  15. // File coleitr.cpp
  16. //
  17. // 
  18. //
  19. // Created by: Helena Shih
  20. //
  21. // Modification History:
  22. //
  23. //  Date         Name          Description
  24. //
  25. //  6/23/97     helena      Adding comments to make code more readable.
  26. // 08/03/98     erm         Synched with 1.2 version of CollationElementIterator.java
  27. //=============================================================================
  28.  
  29. #include "sortkey.h"
  30. #include "coleitr.h"
  31.  
  32. #include "chariter.h"
  33. #include "tables.h"
  34. #include "normlzr.h"
  35. #include "unicode.h"
  36.  
  37. int32_t const CollationElementIterator::NULLORDER = 0xffffffff;
  38. int32_t const CollationElementIterator::UNMAPPEDCHARVALUE = 0x7fff0000;
  39.  
  40.  
  41. // This private method will never be called, but it makes the linker happy
  42.  
  43. CollationElementIterator::CollationElementIterator()
  44. : expIndex(0),
  45.   text(0),
  46.   swapOrder(0),
  47.   bufferAlias(0),
  48.   orderAlias(0)
  49. {
  50. }
  51.  
  52. // This private method will never be called, but it makes the linker happy
  53.  
  54. CollationElementIterator::CollationElementIterator(const RuleBasedCollator* order)
  55. : expIndex(0),
  56.   text(0),
  57.   bufferAlias(0),
  58.   swapOrder(0),
  59.   orderAlias(order)
  60. {
  61. }
  62.  
  63. // This is the "real" constructor for this class; it constructs an iterator
  64. // over the source text using the specified collator
  65. CollationElementIterator::CollationElementIterator( const UnicodeString& sourceText,
  66.                                                     const RuleBasedCollator* order,
  67.                                                     UErrorCode& status) 
  68. : expIndex(0), 
  69.   swapOrder(0),
  70.   text(NULL),
  71.   bufferAlias(NULL),
  72.   orderAlias(order)
  73. {
  74.     if (U_FAILURE(status)) {
  75.         return;
  76.     }
  77.  
  78.     if ( sourceText.size() != 0 ) {
  79.         //
  80.         // A CollationElementIterator is really a two-layered beast.
  81.         // Internally it uses a Normalizer to munge the source text
  82.         // into a form where all "composed" Unicode characters (such as ü) are
  83.         // split into a normal character and a combining accent character.  
  84.         // Afterward, CollationElementIterator does its own processing to handle
  85.         // expanding and contracting collation sequences, ignorables, and so on.
  86.         //
  87.       Normalizer::EMode decomp = (order->getStrength() == Collator::IDENTICAL)
  88.     ? Normalizer::NO_OP
  89.     : order->getDecomposition();
  90.       
  91.       text = new Normalizer(sourceText, decomp);
  92.       if (text == NULL) {
  93.     status = U_MEMORY_ALLOCATION_ERROR;
  94.       }
  95.     }
  96. }
  97.  
  98.  
  99. // This is the "real" constructor for this class; it constructs an iterator
  100. // over the source text using the specified collator
  101. CollationElementIterator::CollationElementIterator( const CharacterIterator& sourceText,
  102.                                                     const RuleBasedCollator* order,
  103.                                                     UErrorCode& status) 
  104. : expIndex(0), 
  105.   swapOrder(0),
  106.   text(NULL),
  107.   bufferAlias(NULL),
  108.   orderAlias(order)
  109. {
  110.     if (U_FAILURE(status)) {
  111.         return;
  112.     }
  113.  
  114.     // **** should I just drop this test? ****
  115.     if ( sourceText.endIndex() != 0 )
  116.     {
  117.         //
  118.         // A CollationElementIterator is really a two-layered beast.
  119.         // Internally it uses a Normalizer to munge the source text
  120.         // into a form where all "composed" Unicode characters (such as ü) are
  121.         // split into a normal character and a combining accent character.  
  122.         // Afterward, CollationElementIterator does its own processing to handle
  123.         // expanding and contracting collation sequences, ignorables, and so on.
  124.         //
  125.       Normalizer::EMode decomp = order->getStrength() == Collator::IDENTICAL
  126.         ? Normalizer::NO_OP
  127.         : order->getDecomposition();
  128.       
  129.       text = new Normalizer(sourceText, decomp);
  130.       if (text == NULL) {
  131.         status = U_MEMORY_ALLOCATION_ERROR;
  132.       }
  133.     }
  134. }
  135.  
  136. CollationElementIterator::CollationElementIterator(const    CollationElementIterator& other)
  137.     : expIndex(other.expIndex), text(0), swapOrder(other.swapOrder)
  138. {
  139.     text = (Normalizer*) other.text->clone();
  140.     bufferAlias = other.bufferAlias;
  141.     orderAlias = other.orderAlias;
  142. }
  143.  
  144. const   CollationElementIterator&
  145. CollationElementIterator::operator=(const   CollationElementIterator& other)
  146. {
  147.     if (this != &other)
  148.     {
  149.         expIndex = other.expIndex;
  150.         swapOrder = other.swapOrder;
  151.  
  152.         delete text;
  153.         text = (Normalizer*)other.text->clone();
  154.  
  155.         bufferAlias = other.bufferAlias;
  156.         orderAlias = other.orderAlias;
  157.     }
  158.  
  159.     return *this;
  160. }
  161.  
  162. CollationElementIterator::~CollationElementIterator()
  163. {
  164.     delete text;
  165.     text = NULL;
  166.     bufferAlias = NULL;
  167.     orderAlias = NULL;
  168. }
  169.  
  170. bool_t
  171. CollationElementIterator::operator==(const CollationElementIterator& that) const
  172. {
  173.     if (this == &that)
  174.     {
  175.         return TRUE;
  176.     }
  177.  
  178.     if (*text != *(that.text))
  179.     {
  180.         return FALSE;
  181.     }
  182.  
  183.     if (swapOrder != that.swapOrder)
  184.     {
  185.         return FALSE;
  186.     }
  187.  
  188.     if (*bufferAlias != *(that.bufferAlias))
  189.     {
  190.         return FALSE;
  191.     }
  192.  
  193.     if (expIndex != that.expIndex)
  194.     {
  195.         return FALSE;
  196.     }
  197.  
  198.     if (orderAlias != that.orderAlias)
  199.     {
  200.         return FALSE;
  201.     }
  202.  
  203.     return TRUE;
  204. }
  205.  
  206. bool_t
  207. CollationElementIterator::operator!=(const CollationElementIterator& other) const
  208. {
  209.     return !(*this == other);
  210. }
  211.  
  212. /**
  213.  * Resets the cursor to the beginning of the string.
  214.  */
  215. void 
  216. CollationElementIterator::reset()
  217. {
  218.   if (text != NULL)
  219.     {
  220.       text->reset();
  221.       text->setMode(orderAlias->getDecomposition());
  222.     }
  223.  
  224.   bufferAlias = NULL;
  225.   expIndex = 0;
  226.   swapOrder = 0;
  227. }
  228.  
  229. // Sets the source to the new source string.
  230. void
  231. CollationElementIterator::setText(const UnicodeString&  source,
  232.                                         UErrorCode&      status)
  233. {
  234.     if (U_FAILURE(status))
  235.     {
  236.         return;
  237.     }
  238.  
  239.     bufferAlias = 0;
  240.     swapOrder = 0;
  241.     expIndex = 0;
  242.  
  243.     if (text == NULL)
  244.     {
  245.         text = new Normalizer(source, orderAlias->getDecomposition());
  246.     }
  247.     else
  248.     {
  249.         text->setText(source, status);
  250.         text->setMode(orderAlias->getDecomposition());
  251.     }
  252. }
  253.  
  254. // Sets the source to the new character iterator.
  255. void
  256. CollationElementIterator::setText(CharacterIterator&  source,
  257.                                         UErrorCode&      status)
  258. {
  259.     if (U_FAILURE(status)) {
  260.         return;
  261.     }
  262.  
  263.     bufferAlias = 0;
  264.     swapOrder = 0;
  265.     expIndex = 0;
  266.  
  267.     if (text == NULL) {
  268.         text = new Normalizer(source, orderAlias->getDecomposition());
  269.     }
  270.     else
  271.     {
  272.         text->setMode(orderAlias->getDecomposition());
  273.         text->setText(source, status);
  274.     }
  275. }
  276.  
  277. /**
  278.  * Get the ordering priority of the next character in the string.
  279.  * @return the next character's ordering.  Returns NULLORDER if
  280.  * the end of string is reached.
  281.  */
  282. int32_t
  283. CollationElementIterator::next(UErrorCode& status)
  284. {
  285.     if (text == NULL || U_FAILURE(status))
  286.     {
  287.         return NULLORDER;
  288.     }
  289.  
  290.     // Update the decomposition mode if necessary.
  291.     text->setMode(orderAlias->getDecomposition());
  292.     
  293.     if (bufferAlias != NULL)
  294.     {
  295.         // bufferAlias needs a bit of an explanation.
  296.         // When we hit an expanding character in the text, we call the order's
  297.         // getExpandValues method to retrieve an array of the orderings for all
  298.         // of the characters in the expansion (see the end of this method).
  299.         // The first ordering is returned, and an alias to the orderings array
  300.         // is saved so that the remaining orderings can be returned on subsequent
  301.         // calls to next.  So, if the expanding buffer is not exhausted, 
  302.         // all we have to do here is return the next ordering in the buffer.  
  303.         if (expIndex < bufferAlias->size())
  304.         {
  305.             return strengthOrder(bufferAlias->at(expIndex++));
  306.         }
  307.         else
  308.         {
  309.             bufferAlias = NULL;
  310.             expIndex = 0;
  311.         }
  312.     }
  313.     else if (swapOrder != 0)
  314.     {
  315.         // If we find a character with no order, we return the marking
  316.         // flag, UNMAPPEDCHARVALUE, 0x7fff0000, and then the character 
  317.         // itself shifted left 16 bits as orders.  At this point, the
  318.         // UNMAPPEDCHARVALUE flag has already been returned by the code
  319.         // below, so just return the shifted character here.
  320.         int32_t order = swapOrder << 16;
  321.  
  322.         swapOrder = 0;
  323.  
  324.         return order;
  325.     }
  326.  
  327.     // Gets the next character from the string using decomposition iterator.
  328.     UChar ch = text->current();
  329.     text->next();
  330.  
  331.     if (U_FAILURE(status))
  332.     {
  333.         return NULLORDER;
  334.     }
  335.  
  336.     if (ch == Normalizer::DONE)
  337.     {
  338.         return NULLORDER;
  339.     }
  340.     
  341.     // Ask the collator for this character's ordering.
  342.     int32_t value = orderAlias->getUnicodeOrder(ch);
  343.  
  344.     if (value == RuleBasedCollator::UNMAPPED)
  345.     {
  346.         // Returned an "unmapped" flag and save the character so it can be 
  347.         // returned next time this method is called.
  348.         if (ch == 0x0000) return ch;
  349.         swapOrder = ch;  // \u0000 is not valid in C++'s UnicodeString
  350.         return UNMAPPEDCHARVALUE;
  351.     }
  352.     
  353.     if (value >= RuleBasedCollator::CONTRACTCHARINDEX)
  354.     {
  355.         value = nextContractChar(ch, status);
  356.     }
  357.  
  358.     if (value >= RuleBasedCollator::EXPANDCHARINDEX)
  359.     {
  360.         bufferAlias = orderAlias->getExpandValueList(value);
  361.         expIndex = 0;
  362.         value = bufferAlias->at(expIndex++);
  363.     }
  364.  
  365.     return strengthOrder(value);
  366. }
  367.  
  368.  /**
  369.   * Get the ordering priority of the previous collation element in the string.
  370.   * @param status the error code status.
  371.   * @return the previous element's ordering.  Returns NULLORDER if
  372.   * the beginning of string is reached.
  373.   */
  374. int32_t
  375. CollationElementIterator::previous(UErrorCode& status)
  376. {
  377.     if (text == NULL || U_FAILURE(status))
  378.     {
  379.         return NULLORDER;
  380.     }
  381.  
  382.     text->setMode(orderAlias->getDecomposition());
  383.  
  384.     if (bufferAlias != NULL)
  385.     {
  386.         if (expIndex > 0)
  387.         {
  388.             return strengthOrder(bufferAlias->at(--expIndex));
  389.         }
  390.  
  391.         bufferAlias = NULL;
  392.         expIndex = 0;
  393.     }
  394.     else if (swapOrder != 0)
  395.     {
  396.         int32_t order = swapOrder << 16;
  397.  
  398.         swapOrder = 0;
  399.         return order;
  400.     }
  401.  
  402.     UChar ch = text->previous();
  403.  
  404.     if (ch == Normalizer::DONE)
  405.     {
  406.         return NULLORDER;
  407.     }
  408.  
  409.     int32_t value = orderAlias->getUnicodeOrder(ch);
  410.  
  411.     if (value == RuleBasedCollator::UNMAPPED)
  412.     {
  413.         if (ch == 0x0000) return ch;
  414.         swapOrder = UNMAPPEDCHARVALUE;
  415.         return ch;
  416.     }
  417.     
  418.     if (value >= RuleBasedCollator::CONTRACTCHARINDEX)
  419.     {
  420.         value = prevContractChar(ch, status);
  421.     }
  422.  
  423.     if (value >= RuleBasedCollator::EXPANDCHARINDEX)
  424.     {
  425.         bufferAlias = orderAlias->getExpandValueList(value);
  426.         expIndex = bufferAlias->size();
  427.         value = bufferAlias->at(--expIndex);
  428.     }
  429.  
  430.     return strengthOrder(value);
  431. }
  432.  
  433. int32_t
  434. CollationElementIterator::strengthOrder(int32_t order) const
  435. {
  436.     Collator::ECollationStrength s = orderAlias->getStrength();
  437.     // Mask off the unwanted differences.
  438.     if (s == Collator::PRIMARY)
  439.     {
  440.         order &= RuleBasedCollator::PRIMARYDIFFERENCEONLY;
  441.     } else if (s == Collator::SECONDARY)
  442.     {
  443.         order &= RuleBasedCollator::SECONDARYDIFFERENCEONLY;
  444.     }
  445.     return order;
  446. }
  447.  
  448. UTextOffset
  449. CollationElementIterator::getOffset() const
  450. {
  451.     // Since the DecompositionIterator is doing the work of iterating through
  452.     // the text string, we can just ask it what its offset is.
  453.     return (text != NULL) ? text->getIndex() : 0;
  454. }
  455.  
  456. void 
  457. CollationElementIterator::setOffset(UTextOffset newOffset, 
  458.                                     UErrorCode& status)
  459. {
  460.     if (U_FAILURE(status))
  461.     {
  462.         return;
  463.     }
  464.  
  465.     if (text != NULL)
  466.     {
  467.         text->setIndex(newOffset);
  468.     }
  469.  
  470.     bufferAlias = NULL;
  471.     expIndex = 0;
  472.     swapOrder = 0;
  473. }
  474.  
  475. //============================================================
  476. // privates
  477. //============================================================
  478.  
  479.  
  480. /**
  481.  * Get the ordering priority of the next contracting character in the
  482.  * string.
  483.  * @param ch the starting character of a contracting character token
  484.  * @return the next contracting character's ordering.  Returns NULLORDER
  485.  * if the end of string is reached.
  486.  */
  487. int32_t
  488. CollationElementIterator::nextContractChar(UChar ch,
  489.                                            UErrorCode& status)
  490. {
  491.     // First get the ordering of this single character
  492.     VectorOfPToContractElement *list = orderAlias->getContractValues(ch);
  493.     EntryPair *pair = (EntryPair *)list->at(0);
  494.     int32_t order = pair->value;
  495.  
  496.     // Now iterate through the chars following it and
  497.     // look for the longest match
  498.     key.remove();
  499.     key += ch;
  500.  
  501.     while ((ch = text->current()) != Normalizer::DONE)
  502.     {
  503.         if (U_FAILURE(status))
  504.         {
  505.             return NULLORDER;
  506.         }
  507.  
  508.         key += ch;
  509.  
  510.         int32_t n = RuleBasedCollator::getEntry(list, key, TRUE);
  511.  
  512.         if (n == RuleBasedCollator::UNMAPPED)
  513.         {
  514.             break;
  515.         }
  516.         text->next();
  517.  
  518.         pair = (EntryPair *)list->at(n);
  519.         order = pair->value;
  520.     }
  521.  
  522.     return order;
  523. }
  524.  
  525. /**
  526.  * Get the ordering priority of the previous contracting character in the
  527.  * string.
  528.  * @param ch the starting character of a contracting character token
  529.  * @return the next contracting character's ordering.  Returns NULLORDER
  530.  * if the end of string is reached.
  531.  */
  532. int32_t CollationElementIterator::prevContractChar(UChar ch,
  533.                                                    UErrorCode &status)
  534. {
  535.     // First get the ordering of this single character
  536.     VectorOfPToContractElement *list = orderAlias->getContractValues(ch);
  537.     EntryPair *pair = (EntryPair *)list->at(0);
  538.     int32_t order = pair->value;
  539.  
  540.     // Now iterate through the chars following it and
  541.     // look for the longest match
  542.     key.remove();
  543.     key += ch;
  544.  
  545.     while ((ch = text->previous()) != Normalizer::DONE)
  546.     {
  547.         key += ch;
  548.  
  549.         int32_t n = RuleBasedCollator::getEntry(list, key, FALSE);
  550.  
  551.         if (n == RuleBasedCollator::UNMAPPED)
  552.         {
  553.             ch = text->next();
  554.  
  555.             if (U_FAILURE(status))
  556.             {
  557.                 return NULLORDER;
  558.             }
  559.  
  560.             break;
  561.         }
  562.  
  563.         pair = (EntryPair *)list->at(n);
  564.         order = pair->value;
  565.     }
  566.  
  567.     return order;
  568. }
  569.