Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "AlphabeticIndex"
     18 
     19 #include "IcuUtilities.h"
     20 #include "JNIHelp.h"
     21 #include "JniConstants.h"
     22 #include "JniException.h"
     23 #include "ScopedIcuLocale.h"
     24 #include "ScopedJavaUnicodeString.h"
     25 #include "unicode/alphaindex.h"
     26 #include "unicode/uniset.h"
     27 
     28 static AlphabeticIndex* fromPeer(jlong peer) {
     29   return reinterpret_cast<AlphabeticIndex*>(static_cast<uintptr_t>(peer));
     30 }
     31 
     32 static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName) {
     33   UErrorCode status = U_ZERO_ERROR;
     34   ScopedIcuLocale icuLocale(env, javaLocaleName);
     35   if (!icuLocale.valid()) {
     36     return 0;
     37   }
     38   AlphabeticIndex* ai = new AlphabeticIndex(icuLocale.locale(), status);
     39   if (maybeThrowIcuException(env, "AlphabeticIndex", status)) {
     40     return 0;
     41   }
     42   return reinterpret_cast<uintptr_t>(ai);
     43 }
     44 
     45 static void AlphabeticIndex_destroy(JNIEnv*, jclass, jlong peer) {
     46   delete fromPeer(peer);
     47 }
     48 
     49 static jint AlphabeticIndex_getMaxLabelCount(JNIEnv*, jclass, jlong peer) {
     50   AlphabeticIndex* ai = fromPeer(peer);
     51   return ai->getMaxLabelCount();
     52 }
     53 
     54 static void AlphabeticIndex_setMaxLabelCount(JNIEnv* env, jclass, jlong peer, jint count) {
     55   AlphabeticIndex* ai = fromPeer(peer);
     56   UErrorCode status = U_ZERO_ERROR;
     57   ai->setMaxLabelCount(count, status);
     58   maybeThrowIcuException(env, "AlphabeticIndex::setMaxLabelCount", status);
     59 }
     60 
     61 static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocaleName) {
     62   AlphabeticIndex* ai = fromPeer(peer);
     63   ScopedIcuLocale icuLocale(env, javaLocaleName);
     64   if (!icuLocale.valid()) {
     65     return;
     66   }
     67   UErrorCode status = U_ZERO_ERROR;
     68   ai->addLabels(icuLocale.locale(), status);
     69   maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
     70 }
     71 
     72 static void AlphabeticIndex_addLabelRange(JNIEnv* env, jclass, jlong peer,
     73                                           jint codePointStart, jint codePointEnd) {
     74   AlphabeticIndex* ai = fromPeer(peer);
     75   UErrorCode status = U_ZERO_ERROR;
     76   ai->addLabels(UnicodeSet(codePointStart, codePointEnd), status);
     77   maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
     78 }
     79 
     80 static jint AlphabeticIndex_getBucketCount(JNIEnv* env, jclass, jlong peer) {
     81   AlphabeticIndex* ai = fromPeer(peer);
     82   UErrorCode status = U_ZERO_ERROR;
     83   jint result = ai->getBucketCount(status);
     84   if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketCount", status)) {
     85     return -1;
     86   }
     87   return result;
     88 }
     89 
     90 static jint AlphabeticIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) {
     91   AlphabeticIndex* ai = fromPeer(peer);
     92   ScopedJavaUnicodeString string(env, javaString);
     93   if (!string.valid()) {
     94     return -1;
     95   }
     96   UErrorCode status = U_ZERO_ERROR;
     97   jint result = ai->getBucketIndex(string.unicodeString(), status);
     98   if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketIndex", status)) {
     99     return -1;
    100   }
    101   return result;
    102 }
    103 
    104 static jstring AlphabeticIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) {
    105   if (index < 0) {
    106     jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
    107     return NULL;
    108   }
    109 
    110   // Iterate to the nth bucket.
    111   AlphabeticIndex* ai = fromPeer(peer);
    112   UErrorCode status = U_ZERO_ERROR;
    113   ai->resetBucketIterator(status);
    114   if (maybeThrowIcuException(env, "AlphabeticIndex::resetBucketIterator", status)) {
    115     return NULL;
    116   }
    117   for (jint i = 0; i <= index; ++i) {
    118     if (!ai->nextBucket(status)) {
    119       jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
    120       return NULL;
    121     }
    122     if (maybeThrowIcuException(env, "AlphabeticIndex::nextBucket", status)) {
    123       return NULL;
    124     }
    125   }
    126 
    127   // Return "" for the underflow/inflow/overflow buckets.
    128   if (ai->getBucketLabelType() != U_ALPHAINDEX_NORMAL) {
    129     return env->NewStringUTF("");
    130   }
    131 
    132   const UnicodeString& label(ai->getBucketLabel());
    133   return env->NewString(label.getBuffer(), label.length());
    134 }
    135 
    136 static jlong AlphabeticIndex_buildImmutableIndex(JNIEnv* env, jclass, jlong peer) {
    137   AlphabeticIndex* ai = fromPeer(peer);
    138   UErrorCode status = U_ZERO_ERROR;
    139   AlphabeticIndex::ImmutableIndex* ii = ai->buildImmutableIndex(status);
    140   if (maybeThrowIcuException(env, "AlphabeticIndex::buildImmutableIndex", status)) {
    141     return 0;
    142   }
    143   return reinterpret_cast<uintptr_t>(ii);
    144 }
    145 
    146 static AlphabeticIndex::ImmutableIndex* immutableIndexFromPeer(jlong peer) {
    147   return reinterpret_cast<AlphabeticIndex::ImmutableIndex*>(static_cast<uintptr_t>(peer));
    148 }
    149 
    150 static jint ImmutableIndex_getBucketCount(JNIEnv*, jclass, jlong peer) {
    151   AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
    152   return ii->getBucketCount();
    153 }
    154 
    155 static jint ImmutableIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) {
    156   AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
    157   ScopedJavaUnicodeString string(env, javaString);
    158   if (!string.valid()) {
    159     return -1;
    160   }
    161   UErrorCode status = U_ZERO_ERROR;
    162   jint result = ii->getBucketIndex(string.unicodeString(), status);
    163   if (maybeThrowIcuException(env, "AlphabeticIndex::ImmutableIndex::getBucketIndex", status)) {
    164     return -1;
    165   }
    166   return result;
    167 }
    168 
    169 static jstring ImmutableIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) {
    170   AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
    171   const AlphabeticIndex::Bucket* bucket = ii->getBucket(index);
    172   if (bucket == NULL) {
    173     jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
    174     return NULL;
    175   }
    176 
    177   // Return "" for the underflow/inflow/overflow buckets.
    178   if (bucket->getLabelType() != U_ALPHAINDEX_NORMAL) {
    179     return env->NewStringUTF("");
    180   }
    181 
    182   const UnicodeString& label(bucket->getLabel());
    183   return env->NewString(label.getBuffer(), label.length());
    184 }
    185 
    186 static JNINativeMethod gMethods[] = {
    187   NATIVE_METHOD(AlphabeticIndex, create, "(Ljava/lang/String;)J"),
    188   NATIVE_METHOD(AlphabeticIndex, destroy, "(J)V"),
    189   NATIVE_METHOD(AlphabeticIndex, getMaxLabelCount, "(J)I"),
    190   NATIVE_METHOD(AlphabeticIndex, setMaxLabelCount, "(JI)V"),
    191   NATIVE_METHOD(AlphabeticIndex, addLabels, "(JLjava/lang/String;)V"),
    192   NATIVE_METHOD(AlphabeticIndex, addLabelRange, "(JII)V"),
    193   NATIVE_METHOD(AlphabeticIndex, getBucketCount, "(J)I"),
    194   NATIVE_METHOD(AlphabeticIndex, getBucketIndex, "(JLjava/lang/String;)I"),
    195   NATIVE_METHOD(AlphabeticIndex, getBucketLabel, "(JI)Ljava/lang/String;"),
    196   NATIVE_METHOD(AlphabeticIndex, buildImmutableIndex, "(J)J"),
    197 };
    198 static JNINativeMethod gImmutableIndexMethods[] = {
    199   NATIVE_METHOD(ImmutableIndex, getBucketCount, "(J)I"),
    200   NATIVE_METHOD(ImmutableIndex, getBucketIndex, "(JLjava/lang/String;)I"),
    201   NATIVE_METHOD(ImmutableIndex, getBucketLabel, "(JI)Ljava/lang/String;"),
    202 };
    203 void register_libcore_icu_AlphabeticIndex(JNIEnv* env) {
    204   jniRegisterNativeMethods(env, "libcore/icu/AlphabeticIndex", gMethods, NELEM(gMethods));
    205   jniRegisterNativeMethods(env, "libcore/icu/AlphabeticIndex$ImmutableIndex", gImmutableIndexMethods, NELEM(gImmutableIndexMethods));
    206 }
    207