Very first version of TeaVM time zone compiler

This commit is contained in:
Alexey Andreev 2015-05-14 18:38:30 +04:00
parent 13fbf7c544
commit dadc693c9f
4 changed files with 53 additions and 82 deletions

View File

@ -15,8 +15,13 @@
*/
package org.teavm.classlib.impl.tz;
import org.joda.time.DateTimeZone;
import org.teavm.classlib.impl.Base46;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataGeneratorContext;
@ -27,19 +32,49 @@ import org.teavm.platform.metadata.ResourceMap;
* @author Alexey Andreev
*/
public class TimeZoneGenerator implements MetadataGenerator {
private static int[] divisors = { 60_000, 300_000, 1800_000, 3600_000 };
public static int RESOLUTION_MINUTE = 0;
public static int RESOLUTION_5_MINUTES = 1;
public static int RESOLUTION_HALF_HOUR = 2;
public static int RESOLUTION_HOUR = 3;
private static final String tzPath = "org/teavm/classlib/impl/tz/tzdata2015d.zip";
@Override
public ResourceMap<ResourceMap<TimeZoneResource>> generateMetadata(
MetadataGeneratorContext context, MethodReference method) {
ResourceMap<ResourceMap<TimeZoneResource>> result = context.createResourceMap();
for (String id : DateTimeZone.getAvailableIDs()) {
ZoneInfoCompiler compiler = new ZoneInfoCompiler();
try (InputStream input = context.getClassLoader().getResourceAsStream(tzPath)) {
try (ZipInputStream zip = new ZipInputStream(input)) {
while (true) {
ZipEntry entry = zip.getNextEntry();
if (entry == null) {
break;
}
switch (entry.getName().substring("tzdata2015d/".length())) {
case "africa":
case "antarctica":
case "asia":
case "australasia":
case "etcetera":
case "europe":
case "northamerica":
case "pacificnew":
case "southamerica":
compiler.parseDataFile(new BufferedReader(new InputStreamReader(zip, "UTF-8")), false);
break;
/*case "backward":
case "backzone":
compiler.parseDataFile(new BufferedReader(new InputStreamReader(zip, "UTF-8")), true);
break;*/
}
}
}
} catch (IOException e) {
throw new RuntimeException("Error generating TimeZones", e);
}
Map<String, StorableDateTimeZone> zoneMap = compiler.compile();
for (String id : zoneMap.keySet()) {
int sepIndex = id.indexOf('/');
if (sepIndex < 0) {
continue;
}
String areaName = id.substring(0, sepIndex);
String locationName = id.substring(sepIndex + 1);
ResourceMap<TimeZoneResource> area = result.get(areaName);
@ -48,78 +83,15 @@ public class TimeZoneGenerator implements MetadataGenerator {
result.put(areaName, area);
}
DateTimeZone tz = DateTimeZone.forID(id);
StorableDateTimeZone tz = zoneMap.get(id);
TimeZoneResource tzRes = context.createResource(TimeZoneResource.class);
tzRes.setAbbreviation(locationName);
tzRes.setData(encodeData(tz));
StringBuilder data = new StringBuilder();
tz.write(data);
tzRes.setData(data.toString());
area.put(locationName, tzRes);
}
return result;
}
public String encodeData(DateTimeZone tz) {
// Find resolution
int resolution = RESOLUTION_HOUR;
long current = 0;
long offset = tz.getOffset(0);
while (true) {
long next = tz.nextTransition(current);
if (next == current) {
break;
}
current = next;
int nextOffset = tz.getOffset(next);
if (nextOffset == offset) {
continue;
}
offset = nextOffset;
resolution = getResolution(resolution, current);
resolution = getResolution(resolution, offset);
if (resolution == 0) {
break;
}
}
StringBuilder sb = new StringBuilder();
Base46.encode(sb, resolution);
current = 0;
offset = tz.getOffset(0);
int divisor = divisors[resolution];
long last = 0;
long lastOffset = offset / divisor;
Base46.encode(sb, lastOffset);
while (true) {
long next = tz.nextTransition(current);
if (next == current) {
break;
}
current = next;
int nextOffset = tz.getOffset(next);
if (nextOffset == offset) {
continue;
}
offset = nextOffset;
long newTime = current / divisor;
long newOffset = offset / divisor;
Base46.encodeUnsigned(sb, newTime - last);
Base46.encode(sb, newOffset - lastOffset);
last = newTime;
lastOffset = newOffset;
}
return sb.toString();
}
private int getResolution(int currentResolution, long value) {
while (currentResolution > 0 && value % divisors[currentResolution] != 0) {
--currentResolution;
}
return currentResolution;
}
}

View File

@ -237,8 +237,8 @@ public class ZoneInfoCompiler {
String alias = iGoodLinks.get(i + 1);
Zone sourceZone = sourceMap.get(baseId);
if (sourceZone == null) {
throw new RuntimeException("Cannot find source zone '" + baseId + "' to link alias '" +
alias + "' to");
/*throw new RuntimeException("Cannot find source zone '" + baseId + "' to link alias '" +
alias + "' to");*/
} else {
DateTimeZoneBuilder builder = new DateTimeZoneBuilder();
sourceZone.addToBuilder(builder, iRuleSets);
@ -257,10 +257,10 @@ public class ZoneInfoCompiler {
String alias = iBackLinks.get(i + 1);
StorableDateTimeZone tz = map.get(id);
if (tz == null) {
if (pass > 0) {
/*if (pass > 0) {
throw new RuntimeException("Cannot find time zone '" + id + "' to link alias '" +
alias + "' to");
}
}*/
} else {
map.put(alias, tz);
}

View File

@ -174,7 +174,7 @@ public class TClass<T> extends TObject {
return forName(name);
}
@SuppressWarnings({ "unchecked", "unused" })
@SuppressWarnings({ "unchecked" })
public T newInstance() throws TInstantiationException, TIllegalAccessException {
Object instance = Platform.newInstance(platformClass);
if (instance == null) {

View File

@ -29,7 +29,6 @@ public class Base46Test {
for (int i = -65536; i <= 65536; ++i) {
sb.setLength(0);
Base46.encode(sb, i);
System.out.println(i + " - " + sb);
CharFlow flow = new CharFlow(sb.toString().toCharArray());
int num = Base46.decode(flow);
assertEquals(i, num);