blob: 950dfc9027f74b993902185bc7df5d5cdd858a87 [file] [log] [blame]
/*
* Copyright (c) 2011, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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 com.google.dart.indexer.storage.inmemory.api;
import com.google.dart.indexer.index.entries.LocationInfo;
import com.google.dart.indexer.index.layers.bidirectional_edges.BidirectionalEdgesLocationInfo;
import com.google.dart.indexer.index.layers.reverse_edges.ReverseEdgesLocationInfo;
import com.google.dart.indexer.locations.Location;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class SimpleLocationInfoEncoder implements ILocationInfoCoder {
private static boolean isBitSet(byte bt, int num) {
return (bt & ((byte) 1 << num)) != 0;
}
private static byte setBit(byte bt, int num) {
return (byte) (bt | ((byte) 1 << num));
}
byte flags;
@Override
public LocationInfo decode(byte[] data, ILocationEncoder encoder) {
ByteBuffer wrap = ByteBuffer.wrap(data);
flags = wrap.get(0);
boolean biderectionalLocations = isBitSet(flags, 0);
if (biderectionalLocations) {
Collection<Location> source = new ArrayList<Location>();
Collection<Location> destination = new ArrayList<Location>();
int decodeCollection = decodeCollection(wrap, encoder, 1, 1, source);
decodeCollection(wrap, encoder, decodeCollection, 4, destination);
if (source.isEmpty()) {
source = Collections.emptyList();
}
if (destination.isEmpty()) {
destination = Collections.emptyList();
}
BidirectionalEdgesLocationInfo bidirectionalEdgesLocationInfo = new BidirectionalEdgesLocationInfo(
source, destination);
return bidirectionalEdgesLocationInfo;
} else {
Collection<Location> source = new ArrayList<Location>();
decodeCollection(wrap, encoder, 1, 1, source);
if (source.isEmpty()) {
source = Collections.emptyList();
}
ReverseEdgesLocationInfo re = new ReverseEdgesLocationInfo(source);
return re;
}
}
@Override
public byte[] encode(LocationInfo info, ILocationEncoder locationCoder) {
flags = 0;
if (info instanceof BidirectionalEdgesLocationInfo) {
flags |= 1;
BidirectionalEdgesLocationInfo inf = (BidirectionalEdgesLocationInfo) info;
Location[] sourceLocations = inf.getSourceLocations();
Location[] deLocations = inf.getDestinationLocations();
int sourceLocationsSize = calcLocationSize(sourceLocations, locationCoder, 1);
int deLocationsSize = calcLocationSize(deLocations, locationCoder, 4);
int mem = 1 + sourceLocationsSize + deLocationsSize;
byte[] result = new byte[mem];
ByteBuffer wrap = ByteBuffer.wrap(result);
wrap.put(0, flags);
int pos = 1;
int index = 1;
pos = encodeCollection(locationCoder, sourceLocations, wrap, 1, index);
pos = encodeCollection(locationCoder, deLocations, wrap, pos, 4);
return result;
}
if (info instanceof ReverseEdgesLocationInfo) {
ReverseEdgesLocationInfo inf = (ReverseEdgesLocationInfo) info;
Location[] sourceLocations = inf.getSourceLocations();
int mem = 1 + calcLocationSize(sourceLocations, locationCoder, 1);
byte[] result = new byte[mem];
ByteBuffer wrap = ByteBuffer.wrap(result);
wrap.put(0, flags);
int pos = 1;
int index = 1;
pos = encodeCollection(locationCoder, sourceLocations, wrap, pos, index);
pos++;
return result;
}
return null;
}
/*
* private static class IncrementalBufferWriter { private final ByteBuffer buffer; private int
* pos;
*
* public IncrementalBufferWriter(ByteBuffer buff, int pos) { this.buffer = buff; this.pos = pos;
* }
*
* public void write(char ch) { buffer.putChar(pos, ch); pos += 2; }
*
* public void write(int i) { buffer.putInt(pos, i); pos += 4; }
*
* public int getPos() { return pos; } }
*
* private int encodeCollection(ILocationEncoder locationCoder, Location[] sourceLocations,
* ByteBuffer wrap, int pos, int index) { boolean shortS = isBitSet(flags, index); boolean zero =
* isBitSet(flags, index + 1); boolean smallLength = isBitSet(flags, index + 2); boolean one =
* zero & smallLength;
*
* IncrementalBufferWriter writer = new IncrementalBufferWriter(wrap, pos);
*
* if (one) { int encode = locationCoder.encode(sourceLocations[0]); writer.write( shortS ? (char)
* encode : encode); } else if (!zero) { int length = sourceLocations.length; writer.write(
* smallLength ? (char) length : length); for (int a = 0; a < sourceLocations.length; a++) { int
* encode = locationCoder.encode(sourceLocations[a]); writer.write(shortS ?(char) encode : encode
* ); } } return writer.getPos(); }
*/
int decodeCollection(ByteBuffer buffer, ILocationEncoder encoder, int pos, int index,
Collection<Location> result) {
boolean shortS = isBitSet(flags, index);
boolean zero = isBitSet(flags, index + 1);
boolean smallLength = isBitSet(flags, index + 2);
boolean one = zero & smallLength;
if (one) {
if (shortS) {
Location decode = encoder.decode(buffer.getChar(pos));
result.add(decode);
pos += 2;
} else {
Location decode = encoder.decode(buffer.getInt(pos));
result.add(decode);
pos += 4;
}
} else if (!zero) {
if (smallLength) {
int length = buffer.getChar(pos);
pos += 2;
if (shortS) {
for (int a = 0; a < length; a++) {
int location = buffer.getChar(pos);
result.add(encoder.decode(location));
pos += 2;
}
} else {
for (int a = 0; a < length; a++) {
int location = buffer.getInt(pos);
result.add(encoder.decode(location));
pos += 4;
}
}
} else {
int length = buffer.getChar(pos);
pos += 4;
if (shortS) {
for (int a = 0; a < length; a++) {
int location = buffer.getChar(pos);
result.add(encoder.decode(location));
pos += 2;
}
} else {
for (int a = 0; a < length; a++) {
int location = buffer.getInt(pos);
result.add(encoder.decode(location));
pos += 4;
}
}
}
}
return pos;
}
private int calcLocationSize(Location[] sourceLocations, ILocationEncoder locationCoder, int index) {
int vla = 2;
for (int a = 0; a < sourceLocations.length; a++) {
int encode = locationCoder.encode(sourceLocations[a]);
if (encode > 65535) {
vla = 4;
break;
}
}
if (vla == 2) {
flags = setBit(flags, index);
}
if (sourceLocations.length < 65535) {
if (sourceLocations.length == 0) {
flags = setBit(flags, index + 1);
return 0;
} else if (sourceLocations.length == 1) {
flags = setBit(flags, index + 1);
flags = setBit(flags, index + 2);
return vla;
} else {
flags = setBit(flags, index + 2);
return 2 + sourceLocations.length * vla;
}
}
return 4 + sourceLocations.length * vla;
}
private int encodeCollection(ILocationEncoder locationCoder, Location[] sourceLocations,
ByteBuffer wrap, int pos, int index) {
boolean shortS = isBitSet(flags, index);
boolean zero = isBitSet(flags, index + 1);
boolean smallLength = isBitSet(flags, index + 2);
boolean one = zero & smallLength;
if (one) {
if (shortS) {
int encode = locationCoder.encode(sourceLocations[0]);
wrap.putChar(pos, (char) encode);
pos += 2;
} else {
int encode = locationCoder.encode(sourceLocations[0]);
wrap.putInt(pos, encode);
pos += 4;
}
} else if (!zero) {
if (smallLength) {
int length = sourceLocations.length;
wrap.putChar(pos, (char) length);
pos += 2;
if (shortS) {
for (int a = 0; a < sourceLocations.length; a++) {
wrap.putChar(pos, (char) locationCoder.encode(sourceLocations[a]));
pos += 2;
}
} else {
for (int a = 0; a < sourceLocations.length; a++) {
wrap.putInt(pos, locationCoder.encode(sourceLocations[a]));
pos += 4;
}
}
} else {
int length = sourceLocations.length;
wrap.putInt(pos, length);
pos += 4;
if (shortS) {
for (int a = 0; a < sourceLocations.length; a++) {
wrap.putChar(pos, (char) locationCoder.encode(sourceLocations[a]));
pos += 2;
}
} else {
for (int a = 0; a < sourceLocations.length; a++) {
wrap.putInt(pos, locationCoder.encode(sourceLocations[a]));
pos += 4;
}
}
}
}
return pos;
}
}