/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package com.python.pydev.analysis.additionalinfo;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import org.python.pydev.core.FastBufferedReader;
import org.python.pydev.core.ObjectsPool;
import org.python.pydev.core.ObjectsPool.ObjectsPoolMap;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.codecompletion.revisited.PyPublicTreeMap;
import com.aptana.shared_core.string.FastStringBuffer;
/**
* @author Fabio
*
*/
public class TreeIO {
/**
* Tree is written as:
* line 1= tree size
* cub|2|CubeColourDialog!13&999@CUBIC!263@cube!202&999@
*/
public static void dumpTreeToBuffer(SortedMap<String, Set<IInfo>> tree, FastStringBuffer tempBuf,
Map<String, Integer> strToInt) {
Set<Entry<String, Set<IInfo>>> entrySet = tree.entrySet();
Iterator<Entry<String, Set<IInfo>>> it = entrySet.iterator();
tempBuf.append(entrySet.size());
tempBuf.append('\n');
while (it.hasNext()) {
Entry<String, Set<IInfo>> next = it.next();
tempBuf.append(next.getKey());
Set<IInfo> value = next.getValue();
tempBuf.append('|');
tempBuf.append(value.size());
tempBuf.append('|');
Iterator<IInfo> it2 = value.iterator();
Integer integer;
while (it2.hasNext()) {
IInfo info = it2.next();
tempBuf.append(info.getName());
tempBuf.append('!');
String path = info.getPath();
if (path != null) {
integer = strToInt.get(path);
if (integer == null) {
integer = strToInt.size() + 1;
strToInt.put(path, integer);
}
tempBuf.append(integer);
tempBuf.append('&');
}
String modName = info.getDeclaringModuleName();
integer = strToInt.get(modName);
if (integer == null) {
integer = strToInt.size() + 1;
strToInt.put(modName, integer);
}
int v = integer << 3;
v |= info.getType();
tempBuf.append(v); //Write a single for name+type
tempBuf.append('@');
}
tempBuf.append('\n');
}
tempBuf.append("-- END TREE\n");
}
/**
* Dict format is the following:
* -- START DICTIONARY
* dictionary size
* name=integer
*/
public static void dumpDictToBuffer(Map<String, Integer> strToInt, FastStringBuffer buf2) {
Iterator<Entry<String, Integer>> it = strToInt.entrySet().iterator();
buf2.append("-- START DICTIONARY\n");
buf2.append(strToInt.size());
buf2.append('\n');
while (it.hasNext()) {
Entry<String, Integer> next = it.next();
buf2.append(next.getValue());
buf2.append('=');
buf2.append(next.getKey());
buf2.append('\n');
}
buf2.append("-- END DICTIONARY\n");
}
/**
* @author Fabio
*
*/
private static final class MapEntry implements Map.Entry {
private final String key;
private final HashSet<IInfo> set;
public MapEntry(String key, HashSet<IInfo> set) {
this.key = key;
this.set = set;
}
public Object getKey() {
return key;
}
public Object getValue() {
return set;
}
public Object setValue(Object value) {
throw new UnsupportedOperationException();
}
}
public static PyPublicTreeMap<String, Set<IInfo>> loadTreeFrom(final FastBufferedReader reader,
final Map<Integer, String> dictionary, FastStringBuffer buf, ObjectsPoolMap objectsPoolMap)
throws IOException {
PyPublicTreeMap<String, Set<IInfo>> tree = new PyPublicTreeMap<String, Set<IInfo>>();
final int size = com.aptana.shared_core.string.StringUtils.parsePositiveInt(reader.readLine());
try {
final Entry[] entries = new Entry[size];
//each line is something as: cub|CubeColourDialog!13&999@CUBIC!263@cube!202&999@
//note: the path (2nd int in record) is optional
for (int iEntry = 0; iEntry < size; iEntry++) {
buf.clear();
FastStringBuffer line = reader.readLine();
if (line == null || line.startsWith("-- ")) {
throw new RuntimeException("Unexpected line: " + line);
}
char[] internalCharsArray = line.getInternalCharsArray();
int length = line.length();
String key = null;
String infoName = null;
String path = null;
int i = 0;
OUT: for (; i < length; i++) {
char c = internalCharsArray[i];
switch (c) {
case '|':
key = ObjectsPool.internLocal(objectsPoolMap, buf.toString());
buf.clear();
i++;
break OUT;
default:
buf.appendResizeOnExc(c);
}
}
int hashSize = 0;
OUT2: for (; i < length; i++) {
char c = internalCharsArray[i];
switch (c) {
case '|':
hashSize = com.aptana.shared_core.string.StringUtils.parsePositiveInt(buf);
buf.clear();
i++;
break OUT2;
default:
buf.appendResizeOnExc(c);
}
}
HashSet<IInfo> set = new HashSet<IInfo>(hashSize);
for (; i < length; i++) {
char c = internalCharsArray[i];
switch (c) {
case '!':
infoName = ObjectsPool.internLocal(objectsPoolMap, buf.toString());
buf.clear();
break;
case '&':
path = dictionary.get(com.aptana.shared_core.string.StringUtils.parsePositiveInt(buf));
buf.clear();
break;
case '@':
int dictKey = com.aptana.shared_core.string.StringUtils.parsePositiveInt(buf);
byte type = (byte) dictKey;
type &= 0x07; //leave only the 3 least significant bits there (this is the type -- value from 0 - 8).
dictKey = (dictKey >> 3); // the entry in the dict doesn't have the least significant bits there.
buf.clear();
String moduleDeclared = dictionary.get(dictKey);
if (moduleDeclared == null) {
throw new AssertionError("Unable to find key: " + dictKey);
}
if (infoName == null) {
throw new AssertionError("Info name may not be null. Line: " + line);
}
switch (type) {
case IInfo.CLASS_WITH_IMPORT_TYPE:
set.add(new ClassInfo(infoName, moduleDeclared, path, false));
break;
case IInfo.METHOD_WITH_IMPORT_TYPE:
set.add(new FuncInfo(infoName, moduleDeclared, path, false));
break;
case IInfo.ATTRIBUTE_WITH_IMPORT_TYPE:
set.add(new AttrInfo(infoName, moduleDeclared, path, false));
break;
case IInfo.NAME_WITH_IMPORT_TYPE:
set.add(new NameInfo(infoName, moduleDeclared, path, false));
break;
case IInfo.MOD_IMPORT_TYPE:
set.add(new ModInfo(infoName, false));
break;
default:
Log.log("Unexpected type: " + type);
}
break;
default:
buf.appendResizeOnExc(c);
}
}
entries[iEntry] = new MapEntry(key, set);
}
tree.buildFromSorted(size, new Iterator() {
private int iNext;
public boolean hasNext() {
return iNext > size;
}
public Object next() {
Object o = entries[iNext];
iNext++;
return o;
}
public void remove() {
}
}, null, null);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return tree;
}
public static Map<Integer, String> loadDictFrom(FastBufferedReader reader, FastStringBuffer buf,
ObjectsPoolMap objectsPoolMap) throws IOException {
int size = com.aptana.shared_core.string.StringUtils.parsePositiveInt(reader.readLine());
HashMap<Integer, String> map = new HashMap<Integer, String>(size + 5);
FastStringBuffer line;
int val = 0;
while (true) {
line = reader.readLine();
if (line == null) {
return map;
} else if (line.startsWith("-- ")) {
if (line.startsWith("-- END DICTIONARY")) {
return map;
}
throw new RuntimeException("Unexpected line: " + line);
} else {
int length = line.length();
//line is str=int
for (int i = 0; i < length; i++) {
char c = line.charAt(i);
if (c == '=') {
val = com.aptana.shared_core.string.StringUtils.parsePositiveInt(buf);
buf.clear();
} else {
buf.appendResizeOnExc(c);
}
}
String bufStr = buf.toString();
String interned = objectsPoolMap.get(bufStr);
if (interned == null) {
interned = bufStr;
objectsPoolMap.put(bufStr, bufStr);
}
map.put(val, interned);
buf.clear();
}
}
}
}