summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java56
-rw-r--r--luni/src/main/java/libcore/icu/DateIntervalFormat.java33
-rw-r--r--luni/src/main/native/libcore_icu_DateIntervalFormat.cpp39
3 files changed, 111 insertions, 17 deletions
diff --git a/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java b/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java
new file mode 100644
index 0000000..02d8f97
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/DateIntervalFormatBenchmark.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.SimpleBenchmark;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+import static libcore.icu.DateIntervalFormat.*;
+
+public class DateIntervalFormatBenchmark extends SimpleBenchmark {
+ public void timeDateIntervalFormat_formatDateRange_DATE(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ formatDateRange(l, utc, 0L, 0L, flags);
+ }
+ }
+
+ public void timeDateIntervalFormat_formatDateRange_TIME(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ formatDateRange(l, utc, 0L, 0L, flags);
+ }
+ }
+
+ public void timeDateIntervalFormat_formatDateRange_DATE_TIME(int reps) throws Exception {
+ Locale l = Locale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
+
+ for (int rep = 0; rep < reps; ++rep) {
+ formatDateRange(l, utc, 0L, 0L, flags);
+ }
+ }
+}
diff --git a/luni/src/main/java/libcore/icu/DateIntervalFormat.java b/luni/src/main/java/libcore/icu/DateIntervalFormat.java
index a71989e..ab9085f 100644
--- a/luni/src/main/java/libcore/icu/DateIntervalFormat.java
+++ b/luni/src/main/java/libcore/icu/DateIntervalFormat.java
@@ -19,6 +19,7 @@ package libcore.icu;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
+import libcore.util.BasicLruCache;
/**
* Exposes icu4c's DateIntervalFormat.
@@ -46,7 +47,18 @@ public final class DateIntervalFormat {
private static final int DAY_IN_MS = 24 * 60 * 60 * 1000;
private static final int EPOCH_JULIAN_DAY = 2440588;
- // TODO: check whether icu4c's DateIntervalFormat is expensive enough to warrant a native peer.
+ private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
+
+ static class FormatterCache extends BasicLruCache<String, Long> {
+ FormatterCache() {
+ super(8);
+ }
+
+ protected void entryEvicted(String key, Long value) {
+ destroyDateIntervalFormat(value);
+ }
+ };
+
private DateIntervalFormat() {
}
@@ -86,7 +98,20 @@ public final class DateIntervalFormat {
}
String skeleton = toSkeleton(startCalendar, endCalendar, flags);
- return formatDateInterval(skeleton, locale.toString(), tz.getID(), startMs, endMs);
+ synchronized (CACHED_FORMATTERS) {
+ return formatDateInterval(getFormatter(skeleton, locale.toString(), tz.getID()), startMs, endMs);
+ }
+ }
+
+ private static long getFormatter(String skeleton, String localeName, String tzName) {
+ String key = skeleton + "\t" + localeName + "\t" + tzName;
+ Long formatter = CACHED_FORMATTERS.get(key);
+ if (formatter != null) {
+ return formatter;
+ }
+ long address = createDateIntervalFormat(skeleton, localeName, tzName);
+ CACHED_FORMATTERS.put(key, address);
+ return address;
}
private static String toSkeleton(Calendar startCalendar, Calendar endCalendar, int flags) {
@@ -204,5 +229,7 @@ public final class DateIntervalFormat {
return (int) (utcMs / DAY_IN_MS) + EPOCH_JULIAN_DAY;
}
- private static native String formatDateInterval(String skeleton, String localeName, String timeZoneName, long fromDate, long toDate);
+ private static native long createDateIntervalFormat(String skeleton, String localeName, String tzName);
+ private static native void destroyDateIntervalFormat(long address);
+ private static native String formatDateInterval(long address, long fromDate, long toDate);
}
diff --git a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
index 65ace4e..72bc631 100644
--- a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
+++ b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
@@ -23,41 +23,52 @@
#include "cutils/log.h"
#include "unicode/dtitvfmt.h"
-static jstring DateIntervalFormat_formatDateInterval(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName, jstring javaTzName, jlong fromDate, jlong toDate) {
+static jlong DateIntervalFormat_createDateIntervalFormat(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName, jstring javaTzName) {
Locale locale = getLocale(env, javaLocaleName);
ScopedJavaUnicodeString skeletonHolder(env, javaSkeleton);
if (!skeletonHolder.valid()) {
- return NULL;
- }
-
- ScopedJavaUnicodeString tzNameHolder(env, javaTzName);
- if (!tzNameHolder.valid()) {
- return NULL;
+ return 0;
}
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<DateIntervalFormat> formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), locale, status));
+ DateIntervalFormat* formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), locale, status));
if (maybeThrowIcuException(env, "DateIntervalFormat::createInstance", status)) {
- return NULL;
+ return 0;
}
+ ScopedJavaUnicodeString tzNameHolder(env, javaTzName);
+ if (!tzNameHolder.valid()) {
+ return 0;
+ }
formatter->adoptTimeZone(TimeZone::createTimeZone(tzNameHolder.unicodeString()));
+ return reinterpret_cast<uintptr_t>(formatter);
+}
+
+static void DateIntervalFormat_destroyDateIntervalFormat(JNIEnv*, jclass, jlong address) {
+ delete reinterpret_cast<DateIntervalFormat*>(address);
+}
+
+static jstring DateIntervalFormat_formatDateInterval(JNIEnv* env, jclass, jlong address, jlong fromDate, jlong toDate) {
+ DateIntervalFormat* formatter(reinterpret_cast<DateIntervalFormat*>(address));
DateInterval date_interval(fromDate, toDate);
- UnicodeString result;
+ UnicodeString s;
FieldPosition pos = 0;
- formatter->format(&date_interval, result, pos, status);
+ UErrorCode status = U_ZERO_ERROR;
+ formatter->format(&date_interval, s, pos, status);
if (maybeThrowIcuException(env, "DateIntervalFormat::format", status)) {
- return NULL;
+ return NULL;
}
- return env->NewString(result.getBuffer(), result.length());
+ return env->NewString(s.getBuffer(), s.length());
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(DateIntervalFormat, formatDateInterval, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJ)Ljava/lang/String;"),
+ NATIVE_METHOD(DateIntervalFormat, createDateIntervalFormat, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J"),
+ NATIVE_METHOD(DateIntervalFormat, destroyDateIntervalFormat, "(J)V"),
+ NATIVE_METHOD(DateIntervalFormat, formatDateInterval, "(JJJ)Ljava/lang/String;"),
};
void register_libcore_icu_DateIntervalFormat(JNIEnv* env) {
jniRegisterNativeMethods(env, "libcore/icu/DateIntervalFormat", gMethods, NELEM(gMethods));