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; package org.teavm.classlib.impl.tz;
import org.joda.time.DateTimeZone; import java.io.BufferedReader;
import org.teavm.classlib.impl.Base46; 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.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator; import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataGeneratorContext; import org.teavm.platform.metadata.MetadataGeneratorContext;
@ -27,19 +32,49 @@ import org.teavm.platform.metadata.ResourceMap;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class TimeZoneGenerator implements MetadataGenerator { public class TimeZoneGenerator implements MetadataGenerator {
private static int[] divisors = { 60_000, 300_000, 1800_000, 3600_000 }; private static final String tzPath = "org/teavm/classlib/impl/tz/tzdata2015d.zip";
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;
@Override @Override
public ResourceMap<ResourceMap<TimeZoneResource>> generateMetadata( public ResourceMap<ResourceMap<TimeZoneResource>> generateMetadata(
MetadataGeneratorContext context, MethodReference method) { MetadataGeneratorContext context, MethodReference method) {
ResourceMap<ResourceMap<TimeZoneResource>> result = context.createResourceMap(); 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('/'); int sepIndex = id.indexOf('/');
if (sepIndex < 0) {
continue;
}
String areaName = id.substring(0, sepIndex); String areaName = id.substring(0, sepIndex);
String locationName = id.substring(sepIndex + 1); String locationName = id.substring(sepIndex + 1);
ResourceMap<TimeZoneResource> area = result.get(areaName); ResourceMap<TimeZoneResource> area = result.get(areaName);
@ -48,78 +83,15 @@ public class TimeZoneGenerator implements MetadataGenerator {
result.put(areaName, area); result.put(areaName, area);
} }
DateTimeZone tz = DateTimeZone.forID(id); StorableDateTimeZone tz = zoneMap.get(id);
TimeZoneResource tzRes = context.createResource(TimeZoneResource.class); TimeZoneResource tzRes = context.createResource(TimeZoneResource.class);
tzRes.setAbbreviation(locationName); tzRes.setAbbreviation(locationName);
tzRes.setData(encodeData(tz)); StringBuilder data = new StringBuilder();
tz.write(data);
tzRes.setData(data.toString());
area.put(locationName, tzRes); area.put(locationName, tzRes);
} }
return result; 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); String alias = iGoodLinks.get(i + 1);
Zone sourceZone = sourceMap.get(baseId); Zone sourceZone = sourceMap.get(baseId);
if (sourceZone == null) { if (sourceZone == null) {
throw new RuntimeException("Cannot find source zone '" + baseId + "' to link alias '" + /*throw new RuntimeException("Cannot find source zone '" + baseId + "' to link alias '" +
alias + "' to"); alias + "' to");*/
} else { } else {
DateTimeZoneBuilder builder = new DateTimeZoneBuilder(); DateTimeZoneBuilder builder = new DateTimeZoneBuilder();
sourceZone.addToBuilder(builder, iRuleSets); sourceZone.addToBuilder(builder, iRuleSets);
@ -257,10 +257,10 @@ public class ZoneInfoCompiler {
String alias = iBackLinks.get(i + 1); String alias = iBackLinks.get(i + 1);
StorableDateTimeZone tz = map.get(id); StorableDateTimeZone tz = map.get(id);
if (tz == null) { if (tz == null) {
if (pass > 0) { /*if (pass > 0) {
throw new RuntimeException("Cannot find time zone '" + id + "' to link alias '" + throw new RuntimeException("Cannot find time zone '" + id + "' to link alias '" +
alias + "' to"); alias + "' to");
} }*/
} else { } else {
map.put(alias, tz); map.put(alias, tz);
} }

View File

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

View File

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