LCOV - code coverage report
Current view: top level - intl/icu/source/common - bytestrie.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 263 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : *   Copyright (C) 2010-2011, International Business Machines
       6             : *   Corporation and others.  All Rights Reserved.
       7             : *******************************************************************************
       8             : *   file name:  bytestrie.cpp
       9             : *   encoding:   UTF-8
      10             : *   tab size:   8 (not used)
      11             : *   indentation:4
      12             : *
      13             : *   created on: 2010sep25
      14             : *   created by: Markus W. Scherer
      15             : */
      16             : 
      17             : #include "unicode/utypes.h"
      18             : #include "unicode/bytestream.h"
      19             : #include "unicode/bytestrie.h"
      20             : #include "unicode/uobject.h"
      21             : #include "cmemory.h"
      22             : #include "uassert.h"
      23             : 
      24             : U_NAMESPACE_BEGIN
      25             : 
      26           0 : BytesTrie::~BytesTrie() {
      27           0 :     uprv_free(ownedArray_);
      28           0 : }
      29             : 
      30             : // lead byte already shifted right by 1.
      31             : int32_t
      32           0 : BytesTrie::readValue(const uint8_t *pos, int32_t leadByte) {
      33             :     int32_t value;
      34           0 :     if(leadByte<kMinTwoByteValueLead) {
      35           0 :         value=leadByte-kMinOneByteValueLead;
      36           0 :     } else if(leadByte<kMinThreeByteValueLead) {
      37           0 :         value=((leadByte-kMinTwoByteValueLead)<<8)|*pos;
      38           0 :     } else if(leadByte<kFourByteValueLead) {
      39           0 :         value=((leadByte-kMinThreeByteValueLead)<<16)|(pos[0]<<8)|pos[1];
      40           0 :     } else if(leadByte==kFourByteValueLead) {
      41           0 :         value=(pos[0]<<16)|(pos[1]<<8)|pos[2];
      42             :     } else {
      43           0 :         value=(pos[0]<<24)|(pos[1]<<16)|(pos[2]<<8)|pos[3];
      44             :     }
      45           0 :     return value;
      46             : }
      47             : 
      48             : const uint8_t *
      49           0 : BytesTrie::jumpByDelta(const uint8_t *pos) {
      50           0 :     int32_t delta=*pos++;
      51           0 :     if(delta<kMinTwoByteDeltaLead) {
      52             :         // nothing to do
      53           0 :     } else if(delta<kMinThreeByteDeltaLead) {
      54           0 :         delta=((delta-kMinTwoByteDeltaLead)<<8)|*pos++;
      55           0 :     } else if(delta<kFourByteDeltaLead) {
      56           0 :         delta=((delta-kMinThreeByteDeltaLead)<<16)|(pos[0]<<8)|pos[1];
      57           0 :         pos+=2;
      58           0 :     } else if(delta==kFourByteDeltaLead) {
      59           0 :         delta=(pos[0]<<16)|(pos[1]<<8)|pos[2];
      60           0 :         pos+=3;
      61             :     } else {
      62           0 :         delta=(pos[0]<<24)|(pos[1]<<16)|(pos[2]<<8)|pos[3];
      63           0 :         pos+=4;
      64             :     }
      65           0 :     return pos+delta;
      66             : }
      67             : 
      68             : UStringTrieResult
      69           0 : BytesTrie::current() const {
      70           0 :     const uint8_t *pos=pos_;
      71           0 :     if(pos==NULL) {
      72           0 :         return USTRINGTRIE_NO_MATCH;
      73             :     } else {
      74             :         int32_t node;
      75           0 :         return (remainingMatchLength_<0 && (node=*pos)>=kMinValueLead) ?
      76           0 :                 valueResult(node) : USTRINGTRIE_NO_VALUE;
      77             :     }
      78             : }
      79             : 
      80             : UStringTrieResult
      81           0 : BytesTrie::branchNext(const uint8_t *pos, int32_t length, int32_t inByte) {
      82             :     // Branch according to the current byte.
      83           0 :     if(length==0) {
      84           0 :         length=*pos++;
      85             :     }
      86           0 :     ++length;
      87             :     // The length of the branch is the number of bytes to select from.
      88             :     // The data structure encodes a binary search.
      89           0 :     while(length>kMaxBranchLinearSubNodeLength) {
      90           0 :         if(inByte<*pos++) {
      91           0 :             length>>=1;
      92           0 :             pos=jumpByDelta(pos);
      93             :         } else {
      94           0 :             length=length-(length>>1);
      95           0 :             pos=skipDelta(pos);
      96             :         }
      97             :     }
      98             :     // Drop down to linear search for the last few bytes.
      99             :     // length>=2 because the loop body above sees length>kMaxBranchLinearSubNodeLength>=3
     100             :     // and divides length by 2.
     101           0 :     do {
     102           0 :         if(inByte==*pos++) {
     103             :             UStringTrieResult result;
     104           0 :             int32_t node=*pos;
     105           0 :             U_ASSERT(node>=kMinValueLead);
     106           0 :             if(node&kValueIsFinal) {
     107             :                 // Leave the final value for getValue() to read.
     108           0 :                 result=USTRINGTRIE_FINAL_VALUE;
     109             :             } else {
     110             :                 // Use the non-final value as the jump delta.
     111           0 :                 ++pos;
     112             :                 // int32_t delta=readValue(pos, node>>1);
     113           0 :                 node>>=1;
     114             :                 int32_t delta;
     115           0 :                 if(node<kMinTwoByteValueLead) {
     116           0 :                     delta=node-kMinOneByteValueLead;
     117           0 :                 } else if(node<kMinThreeByteValueLead) {
     118           0 :                     delta=((node-kMinTwoByteValueLead)<<8)|*pos++;
     119           0 :                 } else if(node<kFourByteValueLead) {
     120           0 :                     delta=((node-kMinThreeByteValueLead)<<16)|(pos[0]<<8)|pos[1];
     121           0 :                     pos+=2;
     122           0 :                 } else if(node==kFourByteValueLead) {
     123           0 :                     delta=(pos[0]<<16)|(pos[1]<<8)|pos[2];
     124           0 :                     pos+=3;
     125             :                 } else {
     126           0 :                     delta=(pos[0]<<24)|(pos[1]<<16)|(pos[2]<<8)|pos[3];
     127           0 :                     pos+=4;
     128             :                 }
     129             :                 // end readValue()
     130           0 :                 pos+=delta;
     131           0 :                 node=*pos;
     132           0 :                 result= node>=kMinValueLead ? valueResult(node) : USTRINGTRIE_NO_VALUE;
     133             :             }
     134           0 :             pos_=pos;
     135           0 :             return result;
     136             :         }
     137           0 :         --length;
     138           0 :         pos=skipValue(pos);
     139           0 :     } while(length>1);
     140           0 :     if(inByte==*pos++) {
     141           0 :         pos_=pos;
     142           0 :         int32_t node=*pos;
     143           0 :         return node>=kMinValueLead ? valueResult(node) : USTRINGTRIE_NO_VALUE;
     144             :     } else {
     145           0 :         stop();
     146           0 :         return USTRINGTRIE_NO_MATCH;
     147             :     }
     148             : }
     149             : 
     150             : UStringTrieResult
     151           0 : BytesTrie::nextImpl(const uint8_t *pos, int32_t inByte) {
     152             :     for(;;) {
     153           0 :         int32_t node=*pos++;
     154           0 :         if(node<kMinLinearMatch) {
     155           0 :             return branchNext(pos, node, inByte);
     156           0 :         } else if(node<kMinValueLead) {
     157             :             // Match the first of length+1 bytes.
     158           0 :             int32_t length=node-kMinLinearMatch;  // Actual match length minus 1.
     159           0 :             if(inByte==*pos++) {
     160           0 :                 remainingMatchLength_=--length;
     161           0 :                 pos_=pos;
     162           0 :                 return (length<0 && (node=*pos)>=kMinValueLead) ?
     163           0 :                         valueResult(node) : USTRINGTRIE_NO_VALUE;
     164             :             } else {
     165             :                 // No match.
     166           0 :                 break;
     167             :             }
     168           0 :         } else if(node&kValueIsFinal) {
     169             :             // No further matching bytes.
     170           0 :             break;
     171             :         } else {
     172             :             // Skip intermediate value.
     173           0 :             pos=skipValue(pos, node);
     174             :             // The next node must not also be a value node.
     175           0 :             U_ASSERT(*pos<kMinValueLead);
     176             :         }
     177           0 :     }
     178           0 :     stop();
     179           0 :     return USTRINGTRIE_NO_MATCH;
     180             : }
     181             : 
     182             : UStringTrieResult
     183           0 : BytesTrie::next(int32_t inByte) {
     184           0 :     const uint8_t *pos=pos_;
     185           0 :     if(pos==NULL) {
     186           0 :         return USTRINGTRIE_NO_MATCH;
     187             :     }
     188           0 :     if(inByte<0) {
     189           0 :         inByte+=0x100;
     190             :     }
     191           0 :     int32_t length=remainingMatchLength_;  // Actual remaining match length minus 1.
     192           0 :     if(length>=0) {
     193             :         // Remaining part of a linear-match node.
     194           0 :         if(inByte==*pos++) {
     195           0 :             remainingMatchLength_=--length;
     196           0 :             pos_=pos;
     197             :             int32_t node;
     198           0 :             return (length<0 && (node=*pos)>=kMinValueLead) ?
     199           0 :                     valueResult(node) : USTRINGTRIE_NO_VALUE;
     200             :         } else {
     201           0 :             stop();
     202           0 :             return USTRINGTRIE_NO_MATCH;
     203             :         }
     204             :     }
     205           0 :     return nextImpl(pos, inByte);
     206             : }
     207             : 
     208             : UStringTrieResult
     209           0 : BytesTrie::next(const char *s, int32_t sLength) {
     210           0 :     if(sLength<0 ? *s==0 : sLength==0) {
     211             :         // Empty input.
     212           0 :         return current();
     213             :     }
     214           0 :     const uint8_t *pos=pos_;
     215           0 :     if(pos==NULL) {
     216           0 :         return USTRINGTRIE_NO_MATCH;
     217             :     }
     218           0 :     int32_t length=remainingMatchLength_;  // Actual remaining match length minus 1.
     219             :     for(;;) {
     220             :         // Fetch the next input byte, if there is one.
     221             :         // Continue a linear-match node without rechecking sLength<0.
     222             :         int32_t inByte;
     223           0 :         if(sLength<0) {
     224             :             for(;;) {
     225           0 :                 if((inByte=*s++)==0) {
     226           0 :                     remainingMatchLength_=length;
     227           0 :                     pos_=pos;
     228             :                     int32_t node;
     229           0 :                     return (length<0 && (node=*pos)>=kMinValueLead) ?
     230           0 :                             valueResult(node) : USTRINGTRIE_NO_VALUE;
     231             :                 }
     232           0 :                 if(length<0) {
     233           0 :                     remainingMatchLength_=length;
     234           0 :                     break;
     235             :                 }
     236           0 :                 if(inByte!=*pos) {
     237           0 :                     stop();
     238           0 :                     return USTRINGTRIE_NO_MATCH;
     239             :                 }
     240           0 :                 ++pos;
     241           0 :                 --length;
     242           0 :             }
     243             :         } else {
     244             :             for(;;) {
     245           0 :                 if(sLength==0) {
     246           0 :                     remainingMatchLength_=length;
     247           0 :                     pos_=pos;
     248             :                     int32_t node;
     249           0 :                     return (length<0 && (node=*pos)>=kMinValueLead) ?
     250           0 :                             valueResult(node) : USTRINGTRIE_NO_VALUE;
     251             :                 }
     252           0 :                 inByte=*s++;
     253           0 :                 --sLength;
     254           0 :                 if(length<0) {
     255           0 :                     remainingMatchLength_=length;
     256           0 :                     break;
     257             :                 }
     258           0 :                 if(inByte!=*pos) {
     259           0 :                     stop();
     260           0 :                     return USTRINGTRIE_NO_MATCH;
     261             :                 }
     262           0 :                 ++pos;
     263           0 :                 --length;
     264           0 :             }
     265             :         }
     266             :         for(;;) {
     267           0 :             int32_t node=*pos++;
     268           0 :             if(node<kMinLinearMatch) {
     269           0 :                 UStringTrieResult result=branchNext(pos, node, inByte);
     270           0 :                 if(result==USTRINGTRIE_NO_MATCH) {
     271           0 :                     return USTRINGTRIE_NO_MATCH;
     272             :                 }
     273             :                 // Fetch the next input byte, if there is one.
     274           0 :                 if(sLength<0) {
     275           0 :                     if((inByte=*s++)==0) {
     276           0 :                         return result;
     277             :                     }
     278             :                 } else {
     279           0 :                     if(sLength==0) {
     280           0 :                         return result;
     281             :                     }
     282           0 :                     inByte=*s++;
     283           0 :                     --sLength;
     284             :                 }
     285           0 :                 if(result==USTRINGTRIE_FINAL_VALUE) {
     286             :                     // No further matching bytes.
     287           0 :                     stop();
     288           0 :                     return USTRINGTRIE_NO_MATCH;
     289             :                 }
     290           0 :                 pos=pos_;  // branchNext() advanced pos and wrote it to pos_ .
     291           0 :             } else if(node<kMinValueLead) {
     292             :                 // Match length+1 bytes.
     293           0 :                 length=node-kMinLinearMatch;  // Actual match length minus 1.
     294           0 :                 if(inByte!=*pos) {
     295           0 :                     stop();
     296           0 :                     return USTRINGTRIE_NO_MATCH;
     297             :                 }
     298           0 :                 ++pos;
     299           0 :                 --length;
     300           0 :                 break;
     301           0 :             } else if(node&kValueIsFinal) {
     302             :                 // No further matching bytes.
     303           0 :                 stop();
     304           0 :                 return USTRINGTRIE_NO_MATCH;
     305             :             } else {
     306             :                 // Skip intermediate value.
     307           0 :                 pos=skipValue(pos, node);
     308             :                 // The next node must not also be a value node.
     309           0 :                 U_ASSERT(*pos<kMinValueLead);
     310             :             }
     311           0 :         }
     312           0 :     }
     313             : }
     314             : 
     315             : const uint8_t *
     316           0 : BytesTrie::findUniqueValueFromBranch(const uint8_t *pos, int32_t length,
     317             :                                      UBool haveUniqueValue, int32_t &uniqueValue) {
     318           0 :     while(length>kMaxBranchLinearSubNodeLength) {
     319           0 :         ++pos;  // ignore the comparison byte
     320           0 :         if(NULL==findUniqueValueFromBranch(jumpByDelta(pos), length>>1, haveUniqueValue, uniqueValue)) {
     321           0 :             return NULL;
     322             :         }
     323           0 :         length=length-(length>>1);
     324           0 :         pos=skipDelta(pos);
     325             :     }
     326           0 :     do {
     327           0 :         ++pos;  // ignore a comparison byte
     328             :         // handle its value
     329           0 :         int32_t node=*pos++;
     330           0 :         UBool isFinal=(UBool)(node&kValueIsFinal);
     331           0 :         int32_t value=readValue(pos, node>>1);
     332           0 :         pos=skipValue(pos, node);
     333           0 :         if(isFinal) {
     334           0 :             if(haveUniqueValue) {
     335           0 :                 if(value!=uniqueValue) {
     336           0 :                     return NULL;
     337             :                 }
     338             :             } else {
     339           0 :                 uniqueValue=value;
     340           0 :                 haveUniqueValue=TRUE;
     341             :             }
     342             :         } else {
     343           0 :             if(!findUniqueValue(pos+value, haveUniqueValue, uniqueValue)) {
     344           0 :                 return NULL;
     345             :             }
     346           0 :             haveUniqueValue=TRUE;
     347             :         }
     348             :     } while(--length>1);
     349           0 :     return pos+1;  // ignore the last comparison byte
     350             : }
     351             : 
     352             : UBool
     353           0 : BytesTrie::findUniqueValue(const uint8_t *pos, UBool haveUniqueValue, int32_t &uniqueValue) {
     354             :     for(;;) {
     355           0 :         int32_t node=*pos++;
     356           0 :         if(node<kMinLinearMatch) {
     357           0 :             if(node==0) {
     358           0 :                 node=*pos++;
     359             :             }
     360           0 :             pos=findUniqueValueFromBranch(pos, node+1, haveUniqueValue, uniqueValue);
     361           0 :             if(pos==NULL) {
     362           0 :                 return FALSE;
     363             :             }
     364           0 :             haveUniqueValue=TRUE;
     365           0 :         } else if(node<kMinValueLead) {
     366             :             // linear-match node
     367           0 :             pos+=node-kMinLinearMatch+1;  // Ignore the match bytes.
     368             :         } else {
     369           0 :             UBool isFinal=(UBool)(node&kValueIsFinal);
     370           0 :             int32_t value=readValue(pos, node>>1);
     371           0 :             if(haveUniqueValue) {
     372           0 :                 if(value!=uniqueValue) {
     373           0 :                     return FALSE;
     374             :                 }
     375             :             } else {
     376           0 :                 uniqueValue=value;
     377           0 :                 haveUniqueValue=TRUE;
     378             :             }
     379           0 :             if(isFinal) {
     380           0 :                 return TRUE;
     381             :             }
     382           0 :             pos=skipValue(pos, node);
     383             :         }
     384           0 :     }
     385             : }
     386             : 
     387             : int32_t
     388           0 : BytesTrie::getNextBytes(ByteSink &out) const {
     389           0 :     const uint8_t *pos=pos_;
     390           0 :     if(pos==NULL) {
     391           0 :         return 0;
     392             :     }
     393           0 :     if(remainingMatchLength_>=0) {
     394           0 :         append(out, *pos);  // Next byte of a pending linear-match node.
     395           0 :         return 1;
     396             :     }
     397           0 :     int32_t node=*pos++;
     398           0 :     if(node>=kMinValueLead) {
     399           0 :         if(node&kValueIsFinal) {
     400           0 :             return 0;
     401             :         } else {
     402           0 :             pos=skipValue(pos, node);
     403           0 :             node=*pos++;
     404           0 :             U_ASSERT(node<kMinValueLead);
     405             :         }
     406             :     }
     407           0 :     if(node<kMinLinearMatch) {
     408           0 :         if(node==0) {
     409           0 :             node=*pos++;
     410             :         }
     411           0 :         getNextBranchBytes(pos, ++node, out);
     412           0 :         return node;
     413             :     } else {
     414             :         // First byte of the linear-match node.
     415           0 :         append(out, *pos);
     416           0 :         return 1;
     417             :     }
     418             : }
     419             : 
     420             : void
     421           0 : BytesTrie::getNextBranchBytes(const uint8_t *pos, int32_t length, ByteSink &out) {
     422           0 :     while(length>kMaxBranchLinearSubNodeLength) {
     423           0 :         ++pos;  // ignore the comparison byte
     424           0 :         getNextBranchBytes(jumpByDelta(pos), length>>1, out);
     425           0 :         length=length-(length>>1);
     426           0 :         pos=skipDelta(pos);
     427             :     }
     428           0 :     do {
     429           0 :         append(out, *pos++);
     430           0 :         pos=skipValue(pos);
     431             :     } while(--length>1);
     432           0 :     append(out, *pos);
     433           0 : }
     434             : 
     435             : void
     436           0 : BytesTrie::append(ByteSink &out, int c) {
     437           0 :     char ch=(char)c;
     438           0 :     out.Append(&ch, 1);
     439           0 : }
     440             : 
     441             : U_NAMESPACE_END

Generated by: LCOV version 1.13