1 /*
   2  * Permission is hereby granted, free of charge, to any person obtaining a copy of
   3  * this software and associated documentation files (the "Software"), to deal in
   4  * the Software without restriction, including without limitation the rights to
   5  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   6  * of the Software, and to permit persons to whom the Software is furnished to do
   7  * so, subject to the following conditions:
   8  *
   9  * The above copyright notice and this permission notice shall be included in all
  10  * copies or substantial portions of the Software.
  11  *
  12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18  * SOFTWARE.
  19  */
  20 package jdk.nashorn.internal.runtime.regexp.joni;
  21 
  22 final class OptExactInfo {
  23     static final int OPT_EXACT_MAXLEN = 24;
  24 
  25     final MinMaxLen mmd = new MinMaxLen();
  26     final OptAnchorInfo anchor = new OptAnchorInfo();
  27 
  28     boolean reachEnd;
  29     boolean ignoreCase;
  30 
  31     final char chars[] = new char[OPT_EXACT_MAXLEN];
  32     int length;
  33 
  34     boolean isFull() {
  35         return length >= OPT_EXACT_MAXLEN;
  36     }
  37 
  38     void clear() {
  39         mmd.clear();
  40         anchor.clear();
  41 
  42         reachEnd = false;
  43         ignoreCase = false;
  44         length = 0;
  45     }
  46 
  47     void copy(final OptExactInfo other) {
  48         mmd.copy(other.mmd);
  49         anchor.copy(other.anchor);
  50         reachEnd = other.reachEnd;
  51         ignoreCase = other.ignoreCase;
  52         length = other.length;
  53 
  54         System.arraycopy(other.chars, 0, chars, 0, OPT_EXACT_MAXLEN);
  55     }
  56 
  57     void concat(final OptExactInfo other) {
  58         if (!ignoreCase && other.ignoreCase) {
  59             if (length >= other.length) {
  60                 return; /* avoid */
  61             }
  62             ignoreCase = true;
  63         }
  64 
  65         int p = 0; // add->s;
  66         final int end = p + other.length;
  67 
  68         int i;
  69         for (i = length; p < end;) {
  70             if (i + 1 > OPT_EXACT_MAXLEN) {
  71                 break;
  72             }
  73             chars[i++] = other.chars[p++];
  74         }
  75 
  76         length = i;
  77         reachEnd = (p == end ? other.reachEnd : false);
  78 
  79         final OptAnchorInfo tmp = new OptAnchorInfo();
  80         tmp.concat(anchor, other.anchor, 1, 1);
  81         if (!other.reachEnd) {
  82             tmp.rightAnchor = 0;
  83         }
  84         anchor.copy(tmp);
  85     }
  86 
  87     // ?? raw is not used here
  88     void concatStr(final char[] lchars, final int pp, final int end, final boolean raw) {
  89         int i;
  90         int p = pp;
  91         for (i = length; p < end && i < OPT_EXACT_MAXLEN;) {
  92             if (i + 1 > OPT_EXACT_MAXLEN) {
  93                 break;
  94             }
  95             chars[i++] = lchars[p++];
  96         }
  97 
  98         length = i;
  99     }
 100 
 101     void altMerge(final OptExactInfo other, final OptEnvironment env) {
 102         if (other.length == 0 || length == 0) {
 103             clear();
 104             return;
 105         }
 106 
 107         if (!mmd.equal(other.mmd)) {
 108             clear();
 109             return;
 110         }
 111 
 112         int i;
 113         for (i = 0; i < length && i < other.length; i++) {
 114             if (chars[i] != other.chars[i]) {
 115                 break;
 116             }
 117         }
 118 
 119         if (!other.reachEnd || i<other.length || i<length) {
 120             reachEnd = false;
 121         }
 122 
 123         length = i;
 124         ignoreCase |= other.ignoreCase;
 125 
 126         anchor.altMerge(other.anchor);
 127 
 128         if (!reachEnd) {
 129             anchor.rightAnchor = 0;
 130         }
 131     }
 132 
 133 
 134     void select(final OptExactInfo alt) {
 135         int v1 = length;
 136         int v2 = alt.length;
 137 
 138         if (v2 == 0) {
 139             return;
 140         } else if (v1 == 0) {
 141             copy(alt);
 142             return;
 143         } else if (v1 <= 2 && v2 <= 2) {
 144             /* ByteValTable[x] is big value --> low price */
 145             v2 = OptMapInfo.positionValue(chars[0] & 0xff);
 146             v1 = OptMapInfo.positionValue(alt.chars[0] & 0xff);
 147 
 148             if (length > 1) {
 149                 v1 += 5;
 150             }
 151             if (alt.length > 1) {
 152                 v2 += 5;
 153             }
 154         }
 155 
 156         if (!ignoreCase) {
 157             v1 *= 2;
 158         }
 159         if (!alt.ignoreCase) {
 160             v2 *= 2;
 161         }
 162 
 163         if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) {
 164             copy(alt);
 165         }
 166     }
 167 
 168     // comp_opt_exact_or_map_info
 169     private static final int COMP_EM_BASE   = 20;
 170     int compare(final OptMapInfo m) {
 171         if (m.value <= 0) {
 172             return -1;
 173         }
 174 
 175         final int ve = COMP_EM_BASE * length * (ignoreCase ? 1 : 2);
 176         final int vm = COMP_EM_BASE * 5 * 2 / m.value;
 177 
 178         return mmd.compareDistanceValue(m.mmd, ve, vm);
 179     }
 180 }